<commit_before>use rand;
use std::iter::DoubleEndedIterator;
use std::fmt;

static SIZE  : uint = 4;

#[deriving(Eq, Show)]
pub enum Direction {
    Up,
    Right,
    Down,
    Left,
}

impl Direction {
    fn to_vector(self) -> (int, int) {
        match self {
            Up    => (0, -1),
            Right => (1, 0),
            Down  => (0, 1),
            Left  => (-1, 0)
        }
    }

    // Haskell succ/pred???
    fn all_directions() -> ~[Direction] {
        ~[Up, Right, Down, Left]
    }

}

pub struct Traversal {
    xs: ~[uint],
    ys: ~[uint],

    idx: uint,
    max_idx: uint,
    size: uint
}

impl Traversal {
    pub fn new(size: uint, dir: Direction) -> Traversal {
        let (x, y) = dir.to_vector();
        let xs = if x == 1 {
            range(0u, size).rev().collect::<~[uint]>()
        } else {
            range(0u, size).collect::<~[uint]>()
        };
        let ys = if y == 1 {
            range(0u, size).rev().collect::<~[uint]>()
        } else {
            range(0u, size).collect::<~[uint]>()
        };

        Traversal { xs: xs, ys: ys,
                    idx: 0, max_idx: size * size,
                    size: size,
        }
    }
}

impl Iterator<(uint, uint)> for Traversal {
    fn next(&mut self) -> Option<(uint, uint)> {
        if self.idx == self.max_idx {
            None
        } else {
            let ret = (self.xs[self.idx / self.size],
                       self.ys[self.idx % self.size]);
            self.idx += 1;
            Some(ret)
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Tile {
    pub x: uint,
    pub y: uint,
    pub value: int,

    pub prev_pos: Option<(uint, uint)>,
    pub merged_from: Option<((uint,uint), (uint, uint))>
}

impl Tile {
    pub fn new((x, y): (uint, uint), value: int) -> Tile {
        Tile { x: x, y: y, value: value,
               prev_pos: None, merged_from: None }
    }

    pub fn save_position(&mut self) {
        self.prev_pos = Some((self.x, self.y));
    }

    pub fn update_position(&mut self, (x, y): (uint, uint)) {
        self.x = x;
        self.y = y
    }

    pub fn pos(&self) -> (uint, uint) {
        (self.x, self.y)
    }

}

impl fmt::Show for Tile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.buf.write_str(format!("[{:4d}]", self.value))
    }
}

// Layout for console
//
// +-----+-----+-----+-----+
// |(0,0)|(0,1)|     |     |
// +-----+-----+-----+-----+
// |(1,0)|     |     |     |
// +-----+-----+-----+-----+
// |     |     |     |     |
// +-----+-----+-----+-----+
// |     |     |     |(3,3)|
// +-----+-----+-----+-----+
//
//

#[deriving(Eq, Show, Clone)]
pub struct Grid {
    pub size: uint,
    pub cells: Vec<Vec<Option<Tile>>>
}

impl Grid {
    pub fn new(size: uint) -> Grid {
        Grid {
            size: size,
            cells: Vec::from_elem(size,
                                  Vec::from_elem(size, None))
        }
    }

    pub fn random_available_cell(&self) -> Option<(uint, uint)> {
        let cells = self.available_cells();

        match cells.len() {
            0 => None,
            n => {
                Some(*cells.get(rand::random::<uint>() % n))
            }
        }
    }

    pub fn available_cells(&self) -> Vec<(uint, uint)> {
        let mut cells = Vec::new();

        self.each_cell(|x, y, tile| {
            if tile.is_none() {
                cells.push((x,y))
            }
        });
        cells
    }

    pub fn each_cell(&self, callback: |uint, uint, Option<&Tile>|) {
        for x in range(0u, self.size) {
            for y in range(0u, self.size) {
                callback(x, y, self.cells.get(x).get(y).as_ref())
            }
        }
    }

    pub fn each_mut_cell(&mut self, callback: |uint, uint, &mut Option<Tile>|) {
        for x in range(0u, self.size) {
            for y in range(0u, self.size) {
                callback(x, y, self.cells.get_mut(x).get_mut(y))
            }
        }
    }

    pub fn cells_available(&self) -> bool {
        self.available_cells().len() != 0
    }

    pub fn cell_available(&self, (x, y): (uint, uint)) -> bool {
        self.cells.get(x).get(y).is_none()
    }

    pub fn cell_occupied(&self, (x, y): (uint, uint)) -> bool {
        self.cells.get(x).get(y).is_some()
    }

    pub fn insert_tile(&mut self, tile: Tile) {
        *self.cells.get_mut(tile.x).get_mut(tile.y) = Some(tile);
    }

    pub fn remove_tile(&mut self, tile: Tile) {
        println!("remove ({}, {})", tile.x, tile.y);
        *self.cells.get_mut(tile.x).get_mut(tile.y) = None;
    }

    pub fn within_bounds(&self, (x, y): (uint, uint)) -> bool {
        x < self.size && y < self.size
    }

    pub fn cell_content(&self, (x, y): (uint, uint)) -> Option<Tile> {
        if self.within_bounds((x, y)) {
            *self.cells.get(x).get(y)
        } else {
            None
        }
    }

    fn debug_print(&self) {
        for col in self.cells.iter() {
            for cell in col.iter() {
                match *cell {
                    Some(t) => print!("{}\t", t),
                    None    => print!("[    ]\t"),
                }
            }
            println!("");
        }
    }

}

#[deriving(Show)]
pub struct GameManager {
    pub size: uint,
    pub start_tiles: uint,

    pub grid: Grid,
    pub score: uint,
    pub playing: bool
}

impl GameManager {
    pub fn new(size: uint) -> GameManager {
        GameManager { size: size,
                      start_tiles: 2,
                      grid: Grid::new(size),
                      score: 0,
                      playing: false }
    }

    pub fn setup(&mut self) {
        self.playing = true;

        self.add_start_tiles();
    }

    pub fn add_random_tile(&mut self) {
        if self.grid.cells_available() {
            let value = if rand::random::<uint>() % 10 < 9 { 2 } else { 4 };
            let tile = Tile::new(self.grid.random_available_cell().unwrap(), value);
            println!("add new {}", tile.pos());
            self.grid.insert_tile(tile);
        }
    }

    fn add_start_tiles(&mut self) {
        for _ in range(0, self.start_tiles) {
            self.add_random_tile();
        }
    }

    pub fn prepare_tiles(&mut self) {
        self.grid.each_mut_cell(|_x, _y, tile| {
            if tile.is_some() {
                let mut t = tile.unwrap().clone();
                t.merged_from = None;
                t.save_position();
                *tile = Some(t);
            }
        })
    }

    pub fn move_tile(&mut self, tile: Tile, (x, y): (uint, uint)) {
        println!("move {} to {}", tile.pos(), (x,y));
        let mut tile = tile;
        *self.grid.cells.get_mut(tile.x).get_mut(tile.y) = None;
        tile.update_position((x, y));
        //*self.grid.cells.get_mut(tile.x).get_mut(tile.y) = None;
        let pos = self.grid.cells.get_mut(x).get_mut(y);
        *pos = Some(tile);
        //(*pos).unwrap().update_position((x, y));
    }

    pub fn move(&mut self, dir: Direction) -> bool {
        let mut moved = false;

        self.prepare_tiles();
        for (x, y) in self.build_traversal(dir) {
            let tile_opt = self.grid.cell_content((x, y));

            match tile_opt {
                None => (),
                Some(mut tile) => {
                    let (farthest_pos, next_pos) = self.find_farthest_position((x,y), dir.to_vector());
                    //println!("debug 1 ({}, {}), {:}", x, y, (farthest_pos, next_pos));
                    //println!("debug 3 {}{} ",tile.pos(), tile);
                    let next_opt = self.grid.cell_content(next_pos);
                    // println!("next => {}", next_opt);
                    match next_opt {
                        Some(next) if next.value == tile.value && tile.merged_from.is_none() => {
                            let mut merged = Tile::new(next_pos, tile.value * 2);
                            println!("{}, {} merged to {}", tile.pos(), next_pos, next_pos);
                            merged.merged_from = Some((tile.pos(), next.pos()));

                            self.grid.insert_tile(merged);
                            //println!("debug 2: remove {:?}", tile);
                            self.grid.remove_tile(tile);

                            tile.update_position(next_pos);

                            self.score += merged.value as uint;

                            // The mighty 2048 tile
                            moved = true;
                        }
                        _ => {
                            if tile.pos() != farthest_pos {
                                self.move_tile(tile, farthest_pos);
                                moved = true;
                            }
                        }
                    }
                }
            }
        }

        if moved {
            // xxx moves_av

            println!("moved some cell!");
            self.add_random_tile();
            self.grid.debug_print();
        }

        moved
    }

    pub fn moves_available(&self) -> bool {
        self.grid.cells_available() || self.tile_matches_available()
    }

    // visit order
    fn build_traversal(&self, dir: Direction) -> Traversal {
        Traversal::new(self.size, dir)
    }

    fn find_farthest_position(&self, (x, y): (uint, uint), (dx, dy): (int, int)) -> ((uint, uint), (uint, uint)) {
        let (mut prev_x, mut prev_y) = (x as int, y as int);
        let (mut next_x, mut next_y) = (prev_x + dx, prev_y + dy);

        while self.grid.within_bounds((next_x as uint, next_y as uint)) &&
              self.grid.cell_available((next_x as uint, next_y as uint)) {
                  prev_x = next_x;
                  prev_y = next_y;
                  next_x = prev_x + dx;
                  next_y =  prev_y + dy;
        }
        // (farthest, next)
        ((prev_x as uint, prev_y as uint),
         (next_x as uint, next_y as uint))
    }

    fn tile_matches_available(&self) -> bool {
        for x in range(0u, self.size) {
            for y in range(0u, self.size) {
                match self.grid.cell_content((x,y)) {
                    Some(tile) => {
                        for dir in Direction::all_directions().iter() {
                            let (dx, dy) = dir.to_vector();
                            let nx = (x as int + dx) as uint;
                            let ny = (y as int + dy) as uint;
                            match self.grid.cell_content((nx, ny)) {
                                Some(other) if other.value == tile.value => {
                                    return true;
                                }
                                _ => ()
                            }
                        }

                    }
                    _ => ()
                }

            }
        }
        false
    }

}

fn main() {
    let mut gm = GameManager::new(SIZE);
    gm.setup();
    println!("DEBUG: gm-> {}", gm);
    // gm.add_start_tiles();
    println!("DEBUG: gm-> {}", gm);
    gm.add_random_tile();
    gm.grid.debug_print();
    //gm.move(Up);                // Left
    //gm.move(Down);              // Right
    //gm.move(Left);              // Up
    //gm.move(Right);             // Down
    gm.move(Up);
    println!("===========");
    gm.grid.debug_print();
/*    gm.add_random_tile();
    gm.grid.debug_print();
    gm.add_random_tile();
    gm.grid.debug_print();
    gm.add_random_tile();
    println!("===========");

    gm.move(Down);
    gm.grid.debug_print();
    println!("=========== Up");
    gm.move(Up);
    gm.grid.debug_print();
    let ret : ~[(uint, uint)]  =  gm.build_traversal(Up).collect::<~[(uint,uint)]>();
    println!("traversal => {}", ret);
*/
    //println!("build tranv = {}", gm.build_traversals(Down).collect::<Vec<(uint,uint)>>());
}
<commit_msg>fix multiple merge one move<commit_after>use rand;
use std::iter::DoubleEndedIterator;
use std::fmt;

static SIZE  : uint = 4;

#[deriving(Eq, Show)]
pub enum Direction {
    Up,
    Right,
    Down,
    Left,
}

impl Direction {
    fn to_vector(self) -> (int, int) {
        match self {
            Up    => (0, -1),
            Right => (1, 0),
            Down  => (0, 1),
            Left  => (-1, 0)
        }
    }

    // Haskell succ/pred???
    fn all_directions() -> ~[Direction] {
        ~[Up, Right, Down, Left]
    }

}

pub struct Traversal {
    xs: ~[uint],
    ys: ~[uint],

    idx: uint,
    max_idx: uint,
    size: uint
}

impl Traversal {
    pub fn new(size: uint, dir: Direction) -> Traversal {
        let (x, y) = dir.to_vector();
        let xs = if x == 1 {
            range(0u, size).rev().collect::<~[uint]>()
        } else {
            range(0u, size).collect::<~[uint]>()
        };
        let ys = if y == 1 {
            range(0u, size).rev().collect::<~[uint]>()
        } else {
            range(0u, size).collect::<~[uint]>()
        };

        Traversal { xs: xs, ys: ys,
                    idx: 0, max_idx: size * size,
                    size: size,
        }
    }
}

impl Iterator<(uint, uint)> for Traversal {
    fn next(&mut self) -> Option<(uint, uint)> {
        if self.idx == self.max_idx {
            None
        } else {
            let ret = (self.xs[self.idx / self.size],
                       self.ys[self.idx % self.size]);
            self.idx += 1;
            Some(ret)
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Tile {
    pub x: uint,
    pub y: uint,
    pub value: int,

    pub prev_pos: Option<(uint, uint)>,
    pub merged_from: Option<((uint,uint), (uint, uint))>
}

impl Tile {
    pub fn new((x, y): (uint, uint), value: int) -> Tile {
        Tile { x: x, y: y, value: value,
               prev_pos: None, merged_from: None }
    }

    pub fn save_position(&mut self) {
        self.prev_pos = Some((self.x, self.y));
    }

    pub fn update_position(&mut self, (x, y): (uint, uint)) {
        self.x = x;
        self.y = y
    }

    pub fn pos(&self) -> (uint, uint) {
        (self.x, self.y)
    }

}

impl fmt::Show for Tile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.buf.write_str(format!("[{:4d}]", self.value))
    }
}

// Layout for console
//
// +-----+-----+-----+-----+
// |(0,0)|(0,1)|     |     |
// +-----+-----+-----+-----+
// |(1,0)|     |     |     |
// +-----+-----+-----+-----+
// |     |     |     |     |
// +-----+-----+-----+-----+
// |     |     |     |(3,3)|
// +-----+-----+-----+-----+
//
//

#[deriving(Eq, Show, Clone)]
pub struct Grid {
    pub size: uint,
    pub cells: Vec<Vec<Option<Tile>>>
}

impl Grid {
    pub fn new(size: uint) -> Grid {
        Grid {
            size: size,
            cells: Vec::from_elem(size,
                                  Vec::from_elem(size, None))
        }
    }

    pub fn random_available_cell(&self) -> Option<(uint, uint)> {
        let cells = self.available_cells();

        match cells.len() {
            0 => None,
            n => {
                Some(*cells.get(rand::random::<uint>() % n))
            }
        }
    }

    pub fn available_cells(&self) -> Vec<(uint, uint)> {
        let mut cells = Vec::new();

        self.each_cell(|x, y, tile| {
            if tile.is_none() {
                cells.push((x,y))
            }
        });
        cells
    }

    pub fn each_cell(&self, callback: |uint, uint, Option<&Tile>|) {
        for x in range(0u, self.size) {
            for y in range(0u, self.size) {
                callback(x, y, self.cells.get(x).get(y).as_ref())
            }
        }
    }

    pub fn each_mut_cell(&mut self, callback: |uint, uint, &mut Option<Tile>|) {
        for x in range(0u, self.size) {
            for y in range(0u, self.size) {
                callback(x, y, self.cells.get_mut(x).get_mut(y))
            }
        }
    }

    pub fn cells_available(&self) -> bool {
        self.available_cells().len() != 0
    }

    pub fn cell_available(&self, (x, y): (uint, uint)) -> bool {
        self.cells.get(x).get(y).is_none()
    }

    pub fn cell_occupied(&self, (x, y): (uint, uint)) -> bool {
        self.cells.get(x).get(y).is_some()
    }

    pub fn insert_tile(&mut self, tile: Tile) {
        *self.cells.get_mut(tile.x).get_mut(tile.y) = Some(tile);
    }

    pub fn remove_tile(&mut self, tile: Tile) {
        println!("remove ({}, {})", tile.x, tile.y);
        *self.cells.get_mut(tile.x).get_mut(tile.y) = None;
    }

    pub fn within_bounds(&self, (x, y): (uint, uint)) -> bool {
        x < self.size && y < self.size
    }

    pub fn cell_content(&self, (x, y): (uint, uint)) -> Option<Tile> {
        if self.within_bounds((x, y)) {
            *self.cells.get(x).get(y)
        } else {
            None
        }
    }

    fn debug_print(&self) {
        for col in self.cells.iter() {
            for cell in col.iter() {
                match *cell {
                    Some(t) => print!("{}\t", t),
                    None    => print!("[    ]\t"),
                }
            }
            println!("");
        }
    }

}

#[deriving(Show)]
pub struct GameManager {
    pub size: uint,
    pub start_tiles: uint,

    pub grid: Grid,
    pub score: uint,
    pub playing: bool
}

impl GameManager {
    pub fn new(size: uint) -> GameManager {
        GameManager { size: size,
                      start_tiles: 2,
                      grid: Grid::new(size),
                      score: 0,
                      playing: false }
    }

    pub fn setup(&mut self) {
        self.playing = true;

        self.add_start_tiles();
    }

    pub fn add_random_tile(&mut self) {
        if self.grid.cells_available() {
            let value = if rand::random::<uint>() % 10 < 9 { 2 } else { 4 };
            let tile = Tile::new(self.grid.random_available_cell().unwrap(), value);
            println!("add new {}", tile.pos());
            self.grid.insert_tile(tile);
        }
    }

    fn add_start_tiles(&mut self) {
        for _ in range(0, self.start_tiles) {
            self.add_random_tile();
        }
    }

    pub fn prepare_tiles(&mut self) {
        self.grid.each_mut_cell(|_x, _y, tile| {
            if tile.is_some() {
                let mut t = tile.unwrap().clone();
                t.merged_from = None;
                t.save_position();
                *tile = Some(t);
            }
        })
    }

    pub fn move_tile(&mut self, tile: Tile, (x, y): (uint, uint)) {
        println!("move {} to {}", tile.pos(), (x,y));
        let mut tile = tile;
        *self.grid.cells.get_mut(tile.x).get_mut(tile.y) = None;
        tile.update_position((x, y));
        //*self.grid.cells.get_mut(tile.x).get_mut(tile.y) = None;
        let pos = self.grid.cells.get_mut(x).get_mut(y);
        *pos = Some(tile);
        //(*pos).unwrap().update_position((x, y));
    }

    pub fn move(&mut self, dir: Direction) -> bool {
        let mut moved = false;

        self.prepare_tiles();
        for (x, y) in self.build_traversal(dir) {
            let tile_opt = self.grid.cell_content((x, y));

            match tile_opt {
                None => (),
                Some(mut tile) => {
                    let (farthest_pos, next_pos) = self.find_farthest_position((x,y), dir.to_vector());
                    let next_opt = self.grid.cell_content(next_pos);
                    match next_opt {
                        Some(next) if next.value == tile.value && next.merged_from.is_none() => {
                            let mut merged = Tile::new(next_pos, tile.value * 2);
                            println!("{}, {} merged to {}", tile.pos(), next_pos, next_pos);
                            merged.merged_from = Some((tile.pos(), next.pos()));

                            self.grid.insert_tile(merged);
                            self.grid.remove_tile(tile);

                            tile.update_position(next_pos);

                            self.score += merged.value as uint;
                            // The mighty 2048 tile
                            moved = true;
                        }
                        _ => {
                            if tile.pos() != farthest_pos {
                                self.move_tile(tile, farthest_pos);
                                moved = true;
                            }
                        }
                    }
                }
            }
        }

        if moved {
            // xxx moves_av
            println!("some cell moved, add new one!");
            self.add_random_tile();
        }

        moved
    }

    pub fn moves_available(&self) -> bool {
        self.grid.cells_available() || self.tile_matches_available()
    }

    // visit order
    fn build_traversal(&self, dir: Direction) -> Traversal {
        Traversal::new(self.size, dir)
    }

    fn find_farthest_position(&self, (x, y): (uint, uint), (dx, dy): (int, int)) -> ((uint, uint), (uint, uint)) {
        let (mut prev_x, mut prev_y) = (x as int, y as int);
        let (mut next_x, mut next_y) = (prev_x + dx, prev_y + dy);

        while self.grid.within_bounds((next_x as uint, next_y as uint)) &&
              self.grid.cell_available((next_x as uint, next_y as uint)) {
                  prev_x = next_x;
                  prev_y = next_y;
                  next_x = prev_x + dx;
                  next_y =  prev_y + dy;
        }
        // (farthest, next)
        ((prev_x as uint, prev_y as uint),
         (next_x as uint, next_y as uint))
    }

    fn tile_matches_available(&self) -> bool {
        for x in range(0u, self.size) {
            for y in range(0u, self.size) {
                match self.grid.cell_content((x,y)) {
                    Some(tile) => {
                        for dir in Direction::all_directions().iter() {
                            let (dx, dy) = dir.to_vector();
                            let nx = (x as int + dx) as uint;
                            let ny = (y as int + dy) as uint;
                            match self.grid.cell_content((nx, ny)) {
                                Some(other) if other.value == tile.value => {
                                    return true;
                                }
                                _ => ()
                            }
                        }

                    }
                    _ => ()
                }

            }
        }
        false
    }

}
<|endoftext|>


<commit_before>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

static mut registered_drivers: bool = false;

struct Dataset {
    c_dataset: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALAllRegister();
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALVersionInfo(c_key));
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        unsafe {
            let _g = LOCK.lock();
            return GDALOpen(c_filename, GA_ReadOnly);
        };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe {
            let _g = LOCK.lock();
            GDALClose(self.c_dataset);
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}
<commit_msg>get raster size<commit_after>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

static mut registered_drivers: bool = false;

struct Dataset {
    c_dataset: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALAllRegister();
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALVersionInfo(c_key));
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        unsafe {
            let _g = LOCK.lock();
            return GDALOpen(c_filename, GA_ReadOnly);
        };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe {
            let _g = LOCK.lock();
            GDALClose(self.c_dataset);
        }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        unsafe {
            let _g = LOCK.lock();
            let size_x = GDALGetRasterXSize(self.c_dataset) as int;
            let size_y = GDALGetRasterYSize(self.c_dataset) as int;
            return (size_x, size_y);
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}
<|endoftext|>


<commit_before>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

struct Dataset {
    c_dataset: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALAllRegister();
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALVersionInfo(c_key));
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    unsafe {
        // TODO call once
        let _g = LOCK.lock();
        GDALAllRegister();
    }
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        unsafe {
            let _g = LOCK.lock();
            return GDALOpen(c_filename, GA_ReadOnly);
        };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe {
            let _g = LOCK.lock();
            GDALClose(self.c_dataset);
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}
<commit_msg>only call GDALAllRegister once<commit_after>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

static mut registered_drivers: bool = false;

struct Dataset {
    c_dataset: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALAllRegister();
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALVersionInfo(c_key));
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        unsafe {
            let _g = LOCK.lock();
            return GDALOpen(c_filename, GA_ReadOnly);
        };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe {
            let _g = LOCK.lock();
            GDALClose(self.c_dataset);
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}
<|endoftext|>


<commit_before>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

static mut registered_drivers: bool = false;

struct Dataset {
    c_dataset: *(),
}

struct Driver {
    c_driver: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALVersionInfo(c_key));
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        unsafe {
            let _g = LOCK.lock();
            return GDALOpen(c_filename, GA_ReadOnly);
        };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe {
            let _g = LOCK.lock();
            GDALClose(self.c_dataset);
        }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        unsafe {
            let _g = LOCK.lock();
            let size_x = GDALGetRasterXSize(self.c_dataset) as int;
            let size_y = GDALGetRasterYSize(self.c_dataset) as int;
            return (size_x, size_y);
        }
    }

    pub fn get_driver(&self) -> Driver {
        let mut c_driver;
        unsafe {
            let _g = LOCK.lock();
            c_driver = GDALGetDatasetDriver(self.c_dataset);
        };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        unsafe {
            let _g = LOCK.lock();
            return GDALGetRasterCount(self.c_dataset) as int;
        }
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALGetProjectionRef(self.c_dataset));
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe {
                let _g = LOCK.lock();
                GDALSetProjection(self.c_dataset, c_projection);
            }
        });
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        unsafe {
            let _g = LOCK.lock();
            return GDALGetDriverByName(c_name);
        }
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALGetDriverShortName(self.c_driver));
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let _g = LOCK.lock();
            return raw::from_c_str(GDALGetDriverLongName(self.c_driver));
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}
<commit_msg>remove most locks<commit_after>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

static mut registered_drivers: bool = false;

struct Dataset {
    c_dataset: *(),
}

struct Driver {
    c_driver: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            return raw::from_c_str(GDALVersionInfo(c_key));
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        unsafe {
            return GDALOpen(c_filename, GA_ReadOnly);
        };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe {
            GDALClose(self.c_dataset);
        }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        unsafe {
            let size_x = GDALGetRasterXSize(self.c_dataset) as int;
            let size_y = GDALGetRasterYSize(self.c_dataset) as int;
            return (size_x, size_y);
        }
    }

    pub fn get_driver(&self) -> Driver {
        let mut c_driver;
        unsafe {
            c_driver = GDALGetDatasetDriver(self.c_dataset);
        };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        unsafe {
            return GDALGetRasterCount(self.c_dataset) as int;
        }
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            return raw::from_c_str(GDALGetProjectionRef(self.c_dataset));
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe {
                GDALSetProjection(self.c_dataset, c_projection);
            }
        });
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        unsafe {
            return GDALGetDriverByName(c_name);
        }
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            return raw::from_c_str(GDALGetDriverShortName(self.c_driver));
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            return raw::from_c_str(GDALGetDriverLongName(self.c_driver));
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}
<|endoftext|>


<commit_before>//! GC heap allocator.
//!
//! ### Safety
//!
//! First, a few general observations about safety in Rust.
//!
//! *   If a `mut` reference to a value exists, and other references to the value
//!     also exist, we can definitely crash.
//!
//!     One way it can happen is that the `mut` value is or contains an
//!     `enum`. Using the other reference, we can borrow a refrence to a
//!     current field of the `enum`. Then, using the `mut` reference, we can
//!     assign some other variant to the `enum`, invalidating the reference.
//!     Rust does not detect that the reference is invalid, so when we use it,
//!     we are accessing gibberish.
//!
//!     Another way is if a callback is called while we're in the middle of
//!     mutating a value, while it's in an invalid state. When you read
//!     "callback", think of `deref` and `drop` methods, which are called
//!     implicitly all over the place. These callbacks are normally safe,
//!     because they simply can't have a reference to the value that's in an
//!     intermediate state. But if another reference exists, it might be used
//!     to try to read from the half-mutated value.
//!
//! *   If a data structure contains two paths to a value, under Rust's usual
//!     rules, you can get two `mut` references to that value.
//!
//!     This is why you tend to build ownership trees in Rust and it's why GC
//!     is particularly challenging in Rust: GCs build an arbitrary graph of
//!     values and references.
//!
//! This GC takes the following approach to ensure safety.
//!
//! *   Minimize access to values stored in the heap. For the most part,
//!     application code *never* sees a direct reference to any value that is
//!     physically stored someplace where it's subject to GC.
//!
//! *   Minimize the times when direct references to in-heap values exist at
//!     all, and during these operations, prevent control from escaping to
//!     arbitrary application code.
//!
//! *   Ensure that when any direct references to in-heap values exist, they
//!     obey Rust's rules: for any given value, either only non-`mut`
//!     references, or at most one `mut` reference, exists at a time.
//!
//! Thus we are particularly keen to avoid the possibility of "reentering" the
//! heap, creating new references to in-heap values while others already exist.
//!
//! References to heap values therefore exist only during the following
//! operations:
//!
//! *   Allocation - That is, moving values into the heap. This is safe because
//!     it never triggers any user code at all while heap references exist.
//!
//! * - Heap reads and writes - The only way to do these is via macro-generated
//!     accessors which do not expose references.  Reads call `from_heap()` on
//!     in-heap values, which is dangerous because `from_heap()` receives a
//!     direct reference.  Writes call `drop()`, which is even more dangerous:
//!     (1) it receives a direct `mut` reference; and (2) it leaves in-heap
//!     values uninitialized.
//!
//! *   GC marking - The code for this is all macro-generated.
//!
//! *   GC sweeping - This calls `drop()`, which is dangerous for the reasons
//!     noted above.
//!
//! To make this scheme safe, `from_heap()` and `drop()` must be tightly controlled.
//! `from_heap()` is therefore in an unsafe trait; users are expected to use
//! the `gc_heap_type!` to autogenerate instances.
//!
//! However, **we leave it up to the user to exercise care with `drop()`.**
//! We suggest *never* implementing `Drop` for a heap type. If you must,
//! avoid reading pointer fields while dropping, and avoid calling into
//! arbitrary code.

use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ptr;
use traits::IntoHeapAllocation;
use pages::{heap_type_id, TypedPage, PageSet, PageSetRef};
use ptr::{Pointer, UntypedPointer};
use gcref::GcRef;
use marking::{mark, MarkingTracer};

pub struct Heap {
    page_sets: HashMap<usize, PageSet>,
    pins: RefCell<HashMap<UntypedPointer, usize>>,
    marking_tracer: Option<MarkingTracer>,
}

// What does this do? You'll never guess!
pub type HeapSessionId<'h> = PhantomData<::std::cell::Cell<&'h mut ()>>;

pub struct HeapSession<'h> {
    id: HeapSessionId<'h>,
    heap: &'h mut Heap,
}

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<R, F>(f: F) -> R
where
    F: for<'h> FnOnce(&mut HeapSession<'h>) -> R,
{
    Heap::new().enter(f)
}

impl Heap {
    /// Create a new, empty heap.
    pub fn new() -> Heap {
        Heap {
            page_sets: HashMap::new(),
            pins: RefCell::new(HashMap::new()),
            marking_tracer: Some(MarkingTracer::default()),
        }
    }

    /// Run some code using this Heap.
    ///
    /// # Example
    ///
    ///     use cell_gc::{Heap, GCLeaf};
    ///
    ///     let mut heap = Heap::new();
    ///     heap.enter(|hs| {
    ///         // ... hs.alloc(MyHeapStruct { ... }) ...
    ///         # hs.force_gc();
    ///     });
    ///
    pub fn enter<R, F>(&mut self, f: F) -> R
    where
        F: for<'h> FnOnce(&mut HeapSession<'h>) -> R,
    {
        f(&mut HeapSession::new(self))
    }

    /// Add the value `*p` to the root set, protecting it from GC.
    ///
    /// A value that has been pinned *n* times stays in the root set
    /// until it has been unpinned *n* times.
    ///
    /// # Safety
    ///
    /// `p` must point to a live allocation of type `T` in this heap.
    pub unsafe fn pin<'h, T: IntoHeapAllocation<'h>>(&self, p: Pointer<T::In>) {
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p.into()).or_insert(0);
        *entry += 1;
    }

    /// Unpin a heap-allocated value (see `pin`).
    ///
    /// # Safety
    ///
    /// `p` must point to a pinned allocation of type `T` in this heap.
    pub unsafe fn unpin<'h, T: IntoHeapAllocation<'h>>(&self, p: Pointer<T::In>) {
        let mut pins = self.pins.borrow_mut();
        let done = {
            let entry = pins.entry(p.into()).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        };
        if done {
            pins.remove(&p.into());
        }
    }

    /// Call the given function on each pinned root.
    pub fn each_pin<F>(&self, mut f: F)
    where
        F: FnMut(UntypedPointer),
    {
        for (&ptr, _) in self.pins.borrow().iter() {
            f(ptr);
        }
    }

    pub unsafe fn from_allocation<'h, T: IntoHeapAllocation<'h>>(ptr: Pointer<T::In>) -> *const Heap {
        (*TypedPage::find(ptr)).header.heap
    }

    pub unsafe fn get_mark_bit<'h, T: IntoHeapAllocation<'h>>(ptr: Pointer<T::In>) -> bool {
        (*TypedPage::find(ptr)).get_mark_bit(ptr)
    }

    pub unsafe fn set_mark_bit<'h, T: IntoHeapAllocation<'h>>(ptr: Pointer<T::In>) {
        (*TypedPage::find(ptr)).set_mark_bit(ptr);
    }

    fn take_marking_tracer(&mut self) -> MarkingTracer {
        self.marking_tracer.take().unwrap()
    }

    fn replace_marking_tracer(&mut self, tracer: MarkingTracer) {
        assert!(self.marking_tracer.is_none());
        assert!(tracer.mark_stack_is_empty());
        self.marking_tracer = Some(tracer);
    }

    /// Run the given function with the marking tracer.
    ///
    /// The marking tracer is taken out of the heap and replaced again so we can
    /// have two independent borrows of the heap and the marking tracer and the
    /// same time.
    pub(crate) fn with_marking_tracer<F, O>(&mut self, mut f: F) -> O
    where
        F: FnMut(&mut Self, &mut MarkingTracer) -> O,
    {
        let mut tracer = self.take_marking_tracer();
        let retval = f(self, &mut tracer);
        self.replace_marking_tracer(tracer);
        retval
    }

    /// Clear all mark bits in preparation for GC.
    ///
    /// # Safety
    ///
    /// This must be called only at the beginning of a GC cycle.
    pub(crate) unsafe fn clear_mark_bits(&mut self) {
        for page_set in self.page_sets.values_mut() {
            page_set.clear_mark_bits();
        }
    }

    fn gc(&mut self) {
        mark(self);

        // sweep phase
        for page_set in self.page_sets.values_mut() {
            unsafe {
                page_set.sweep();
            }
        }
    }
}

impl Drop for Heap {
    fn drop(&mut self) {
        // Perform a final GC to call destructors on any remaining allocations.
        assert!(self.pins.borrow().is_empty());
        self.gc();

        for page_set in self.page_sets.values() {
            page_set.assert_no_allocations();
        }
    }
}

impl<'h> HeapSession<'h> {
    fn new(heap: &'h mut Heap) -> HeapSession<'h> {
        HeapSession {
            id: PhantomData,
            heap,
        }
    }

    fn get_page_set<'a, T: IntoHeapAllocation<'h> + 'a>(&'a mut self) -> PageSetRef<'a, 'h, T> {
        let key = heap_type_id::<T>();
        let heap: *mut Heap = self.heap;
        self.heap
            .page_sets
            .entry(key)
            .or_insert_with(|| unsafe { PageSet::new::<T>(heap) })
            .downcast_mut()
    }

    pub fn set_page_limit<T: IntoHeapAllocation<'h>>(&mut self, limit: Option<usize>) {
        self.get_page_set::<T>().set_page_limit(limit);
    }

    pub fn try_alloc<T: IntoHeapAllocation<'h>>(&mut self, value: T) -> Option<T::Ref> {
        // For now, this is done very early, so that if it panics, the heap is
        // left in an OK state. Better wrapping of raw pointers would make it
        // possible to do this later, closer to the `ptr::write()` call. (And
        // the compiler might optimize away this temporary if we do it that
        // way.) Looking forward to placement new!
        let u = value.into_heap();
        unsafe {
            let alloc = self.get_page_set::<T>().try_alloc();
            alloc
                .or_else(|| {
                    self.heap.gc();
                    self.get_page_set::<T>().try_alloc()
                })
                .map(move |p| {
                    ptr::write(p.as_raw() as *mut _, u);
                    T::wrap_gcref(GcRef::new(p))
                })
        }
    }

    pub fn alloc<T: IntoHeapAllocation<'h>>(&mut self, value: T) -> T::Ref {
        self.try_alloc(value)
            .expect("out of memory (gc did not collect anything)")
    }

    pub fn force_gc(&mut self) {
        self.heap.gc();
    }
}
<commit_msg>Comments.<commit_after>//! GC heap allocator.
//!
//! ### Safety
//!
//! First, a few general observations about safety in Rust.
//!
//! *   If a `mut` reference to a value exists, and other references to the value
//!     also exist, we can definitely crash.
//!
//!     One way it can happen is that the `mut` value is or contains an
//!     `enum`. Using the other reference, we can borrow a refrence to a
//!     current field of the `enum`. Then, using the `mut` reference, we can
//!     assign some other variant to the `enum`, invalidating the reference.
//!     Rust does not detect that the reference is invalid, so when we use it,
//!     we are accessing gibberish.
//!
//!     Another way is if a callback is called while we're in the middle of
//!     mutating a value, while it's in an invalid state. When you read
//!     "callback", think of `deref` and `drop` methods, which are called
//!     implicitly all over the place. These callbacks are normally safe,
//!     because they simply can't have a reference to the value that's in an
//!     intermediate state. But if another reference exists, it might be used
//!     to try to read from the half-mutated value.
//!
//! *   If a data structure contains two paths to a value, under Rust's usual
//!     rules, you can get two `mut` references to that value.
//!
//!     This is why you tend to build ownership trees in Rust and it's why GC
//!     is particularly challenging in Rust: GCs build an arbitrary graph of
//!     values and references.
//!
//! This GC takes the following approach to ensure safety.
//!
//! *   Minimize access to values stored in the heap. For the most part,
//!     application code *never* sees a direct reference to any value that is
//!     physically stored someplace where it's subject to GC.
//!
//! *   Minimize the times when direct references to in-heap values exist at
//!     all, and during these operations, prevent control from escaping to
//!     arbitrary application code.
//!
//! *   Ensure that when any direct references to in-heap values exist, they
//!     obey Rust's rules: for any given value, either only non-`mut`
//!     references, or at most one `mut` reference, exists at a time.
//!
//! Thus we are particularly keen to avoid the possibility of "reentering" the
//! heap, creating new references to in-heap values while others already exist.
//!
//! References to heap values therefore exist only during the following
//! operations:
//!
//! *   Allocation - That is, moving values into the heap. This is safe because
//!     it never triggers any user code at all while heap references exist.
//!
//! * - Heap reads and writes - The only way to do these is via macro-generated
//!     accessors which do not expose references.  Reads call `from_heap()` on
//!     in-heap values, which is dangerous because `from_heap()` receives a
//!     direct reference.  Writes call `drop()`, which is even more dangerous:
//!     (1) it receives a direct `mut` reference; and (2) it leaves in-heap
//!     values uninitialized.
//!
//! *   GC marking - The code for this is all macro-generated.
//!
//! *   GC sweeping - This calls `drop()`, which is dangerous for the reasons
//!     noted above.
//!
//! To make this scheme safe, `from_heap()` and `drop()` must be tightly controlled.
//! `from_heap()` is therefore in an unsafe trait; users are expected to use
//! the `gc_heap_type!` to autogenerate instances.
//!
//! However, **we leave it up to the user to exercise care with `drop()`.**
//! We suggest *never* implementing `Drop` for a heap type. If you must,
//! avoid reading pointer fields while dropping, and avoid calling into
//! arbitrary code.

use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ptr;
use traits::IntoHeapAllocation;
use pages::{heap_type_id, TypedPage, PageSet, PageSetRef};
use ptr::{Pointer, UntypedPointer};
use gcref::GcRef;
use marking::{mark, MarkingTracer};

pub struct Heap {
    page_sets: HashMap<usize, PageSet>,
    pins: RefCell<HashMap<UntypedPointer, usize>>,
    marking_tracer: Option<MarkingTracer>,
}

// What does this do? You'll never guess!
pub type HeapSessionId<'h> = PhantomData<::std::cell::Cell<&'h mut ()>>;

pub struct HeapSession<'h> {
    id: HeapSessionId<'h>,
    heap: &'h mut Heap,
}

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<R, F>(f: F) -> R
where
    F: for<'h> FnOnce(&mut HeapSession<'h>) -> R,
{
    Heap::new().enter(f)
}

impl Heap {
    /// Create a new, empty heap.
    pub fn new() -> Heap {
        Heap {
            page_sets: HashMap::new(),
            pins: RefCell::new(HashMap::new()),
            marking_tracer: Some(MarkingTracer::default()),
        }
    }

    /// Run some code using this Heap.
    ///
    /// # Example
    ///
    ///     use cell_gc::{Heap, GCLeaf};
    ///
    ///     let mut heap = Heap::new();
    ///     heap.enter(|hs| {
    ///         // ... hs.alloc(MyHeapStruct { ... }) ...
    ///         # hs.force_gc();
    ///     });
    ///
    pub fn enter<R, F>(&mut self, f: F) -> R
    where
        F: for<'h> FnOnce(&mut HeapSession<'h>) -> R,
    {
        f(&mut HeapSession::new(self))
    }

    /// Add the value `*p` to the root set, protecting it from GC.
    ///
    /// A value that has been pinned *n* times stays in the root set
    /// until it has been unpinned *n* times.
    ///
    /// # Safety
    ///
    /// `p` must point to a live allocation of type `T` in this heap.
    pub unsafe fn pin<'h, T: IntoHeapAllocation<'h>>(&self, p: Pointer<T::In>) {
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p.into()).or_insert(0);
        *entry += 1;
    }

    /// Unpin a heap-allocated value (see `pin`).
    ///
    /// # Safety
    ///
    /// `p` must point to a pinned allocation of type `T` in this heap.
    pub unsafe fn unpin<'h, T: IntoHeapAllocation<'h>>(&self, p: Pointer<T::In>) {
        let mut pins = self.pins.borrow_mut();
        let done = {
            let entry = pins.entry(p.into()).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        };
        if done {
            pins.remove(&p.into());
        }
    }

    /// Call the given function on each pinned root.
    pub fn each_pin<F>(&self, mut f: F)
    where
        F: FnMut(UntypedPointer),
    {
        for (&ptr, _) in self.pins.borrow().iter() {
            f(ptr);
        }
    }

    pub unsafe fn from_allocation<'h, T: IntoHeapAllocation<'h>>(ptr: Pointer<T::In>) -> *const Heap {
        (*TypedPage::find(ptr)).header.heap
    }

    pub unsafe fn get_mark_bit<'h, T: IntoHeapAllocation<'h>>(ptr: Pointer<T::In>) -> bool {
        (*TypedPage::find(ptr)).get_mark_bit(ptr)
    }

    pub unsafe fn set_mark_bit<'h, T: IntoHeapAllocation<'h>>(ptr: Pointer<T::In>) {
        (*TypedPage::find(ptr)).set_mark_bit(ptr);
    }

    fn take_marking_tracer(&mut self) -> MarkingTracer {
        self.marking_tracer.take().unwrap()
    }

    fn replace_marking_tracer(&mut self, tracer: MarkingTracer) {
        assert!(self.marking_tracer.is_none());
        assert!(tracer.mark_stack_is_empty());
        self.marking_tracer = Some(tracer);
    }

    /// Run the given function with the marking tracer.
    ///
    /// The marking tracer is taken out of the heap and replaced again so we can
    /// have two independent borrows of the heap and the marking tracer and the
    /// same time.
    pub(crate) fn with_marking_tracer<F, O>(&mut self, mut f: F) -> O
    where
        F: FnMut(&mut Self, &mut MarkingTracer) -> O,
    {
        let mut tracer = self.take_marking_tracer();
        let retval = f(self, &mut tracer);
        self.replace_marking_tracer(tracer);
        retval
    }

    /// Clear all mark bits in preparation for GC.
    ///
    /// # Safety
    ///
    /// This must be called only at the beginning of a GC cycle.
    pub(crate) unsafe fn clear_mark_bits(&mut self) {
        for page_set in self.page_sets.values_mut() {
            page_set.clear_mark_bits();
        }
    }

    fn gc(&mut self) {
        mark(self);

        // sweep phase
        for page_set in self.page_sets.values_mut() {
            unsafe {
                page_set.sweep();
            }
        }
    }
}

impl Drop for Heap {
    fn drop(&mut self) {
        // Perform a final GC to call destructors on any remaining allocations.
        assert!(self.pins.borrow().is_empty());
        self.gc();

        for page_set in self.page_sets.values() {
            page_set.assert_no_allocations();
        }
    }
}

impl<'h> HeapSession<'h> {
    fn new(heap: &'h mut Heap) -> HeapSession<'h> {
        HeapSession {
            id: PhantomData,
            heap,
        }
    }

    fn get_page_set<'a, T: IntoHeapAllocation<'h> + 'a>(&'a mut self) -> PageSetRef<'a, 'h, T> {
        let key = heap_type_id::<T>();
        let heap: *mut Heap = self.heap;
        self.heap
            .page_sets
            .entry(key)
            .or_insert_with(|| unsafe { PageSet::new::<T>(heap) })
            .downcast_mut()
    }

    /// Set (or unset) the limit on the number of pages that can be used to
    /// allocate values of type `T` in this heap. By default, no limit is set.
    ///
    /// See `try_alloc` for more.
    ///
    /// If there are already at least `limit` pages for `T` values, this may have no effect;
    /// it doesn't cause pages to be freed.
    pub fn set_page_limit<T: IntoHeapAllocation<'h>>(&mut self, limit: Option<usize>) {
        self.get_page_set::<T>().set_page_limit(limit);
    }

    /// Allocate memory, moving `value` into the heap.
    ///
    /// If a limit has previously been set using `set_page_limit`, and we run
    /// up against the limit (already have at least that many pages for `T`
    /// values, and they are all full of live values), `try_alloc` first
    /// attempts to free some memory by doing garbage collection. If that
    /// doesn't work, `try_alloc` returns `None`.
    pub fn try_alloc<T: IntoHeapAllocation<'h>>(&mut self, value: T) -> Option<T::Ref> {
        // For now, this is done very early, so that if it panics, the heap is
        // left in an OK state. Better wrapping of raw pointers would make it
        // possible to do this later, closer to the `ptr::write()` call. (And
        // the compiler might optimize away this temporary if we do it that
        // way.) Looking forward to placement new!
        let u = value.into_heap();
        unsafe {
            let alloc = self.get_page_set::<T>().try_alloc();
            alloc
                .or_else(|| {
                    self.heap.gc();
                    self.get_page_set::<T>().try_alloc()
                })
                .map(move |p| {
                    ptr::write(p.as_raw() as *mut _, u);
                    T::wrap_gcref(GcRef::new(p))
                })
        }
    }

    /// Allocate memory, moving `T` into the heap. This may cause garbage collection.
    ///
    /// # Panics
    ///
    /// If a page limit has been set, all pages are full, and GC fails to shake
    /// anything loose.
    pub fn alloc<T: IntoHeapAllocation<'h>>(&mut self, value: T) -> T::Ref {
        self.try_alloc(value)
            .expect("out of memory (gc did not collect anything)")
    }

    /// Do garbage collection.
    pub fn force_gc(&mut self) {
        self.heap.gc();
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::net::{Ipv4Addr};

use common::{IpNetworkError, cidr_parts, parse_prefix};

const IPV4_BITS: u8 = 32;

#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

impl Ipv4Network {
    /// Constructs a new `Ipv4Network` from any `Ipv4Addr` and a prefix denoting the network size.
    /// If the prefix is larger than 32 this will return an `IpNetworkError::InvalidPrefix`.
    pub fn new(addr: Ipv4Addr, prefix: u8) -> Result<Ipv4Network, IpNetworkError> {
        if prefix > IPV4_BITS {
            Err(IpNetworkError::InvalidPrefix)
        } else {
            Ok(Ipv4Network {
                addr: addr,
                prefix: prefix,
            })
        }
    }

    /// Returns an iterator over `Ipv4Network`. Each call to `next` will return the next
    /// `Ipv4Addr` in the given network. `None` will be returned when there are no more
    /// addresses.
    pub fn iter(&self) -> Ipv4NetworkIterator {
        let (_, start) = self.network();
        let end = start as u64 + self.size();
        Ipv4NetworkIterator {
            next: start as u64,
            end: end,
        }
    }

    pub fn from_cidr(cidr: &str) -> Result<Ipv4Network, IpNetworkError> {
        let (addr_str, prefix_str) = try!(cidr_parts(cidr));
        let addr = try!(Self::parse_addr(addr_str));
        let prefix = try!(parse_prefix(prefix_str, IPV4_BITS));
        Self::new(addr, prefix)
    }

    pub fn ip(&self) -> Ipv4Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }

    pub fn mask(&self) -> (Ipv4Addr, u32) {
        let prefix = self.prefix;
        let mask = !(0xffffffff as u64 >> prefix) as u32;
        (Ipv4Addr::from(mask), mask)
    }

    pub fn network(&self) -> (Ipv4Addr, u32) {
        let (_, mask) = self.mask();
        let ip = u32::from(self.addr) & mask;
        (Ipv4Addr::from(ip), ip)
    }

    pub fn broadcast(&self) -> (Ipv4Addr, u32) {
        let (_, network) = self.network();
        let (_, mask) = self.mask();
        let broadcast = network | !mask;
        (Ipv4Addr::from(broadcast), broadcast)
    }

    pub fn contains(&self, ip: Ipv4Addr) -> bool {
        let (_, net) = self.network();
        let (_, mask) = self.mask();
        (u32::from(ip) & mask) == net
    }

    /// Returns number of possible host addresses in this `Ipv4Network`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnetwork::Ipv4Network;
    ///
    /// let net = Ipv4Network::from_cidr("10.1.0.0/16").unwrap();
    /// assert_eq!(net.size(), 65536);
    ///
    /// let tinynet = Ipv4Network::from_cidr("0.0.0.0/32").unwrap();
    /// assert_eq!(tinynet.size(), 1);
    /// ```
    pub fn size(&self) -> u64 {
        let host_bits = (IPV4_BITS - self.prefix) as u32;
        (2 as u64).pow(host_bits)
    }

    /// Returns the `n`:th address within this network.
    /// The adresses are indexed from 0 and `n` must be smaller than the size of the network.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnetwork::Ipv4Network;
    ///
    /// let net = Ipv4Network::from_cidr("192.168.0.0/24").unwrap();
    /// assert_eq!(net.nth(0).unwrap(), Ipv4Addr::new(192, 168, 0, 0));
    /// assert_eq!(net.nth(15).unwrap(), Ipv4Addr::new(192, 168, 0, 15));
    /// assert!(net.nth(256).is_none());
    ///
    /// let net2 = Ipv4Network::from_cidr("10.0.0.0/16").unwrap();
    /// assert_eq!(net2.nth(256).unwrap(), Ipv4Addr::new(10, 0, 1, 0));
    /// ```
    pub fn nth(&self, n: u32) -> Option<Ipv4Addr> {
        if (n as u64) < self.size() {
            let (_, net) = self.network();
            Some(Ipv4Addr::from(net + n))
        } else {
            None
        }
    }

    fn parse_addr(addr: &str) -> Result<Ipv4Addr, IpNetworkError> {
        let addr_parts = addr.split('.').map(|b| b.parse::<u8>());
        let mut bytes = [0; 4];
        for (i, byte) in addr_parts.enumerate() {
            if i >= 4 {
                return Err(IpNetworkError::InvalidAddr(format!("More than 4 bytes: {}", addr)));
            }
            bytes[i] = try!(byte.map_err(|_| {
                IpNetworkError::InvalidAddr(format!("All bytes not 0-255: {}", addr))
            }));
        }
        Ok(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))
    }
}

impl fmt::Display for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

pub struct Ipv4NetworkIterator {
    next: u64,
    end: u64,
}

impl Iterator for Ipv4NetworkIterator {
    type Item = Ipv4Addr;

    fn next(&mut self) -> Option<Ipv4Addr> {
        if self.next < self.end {
            let next = Ipv4Addr::from(self.next as u32);
            self.next += 1;
            Some(next)
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::collections::HashMap;
    use std::net::Ipv4Addr;
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24).unwrap();
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v4_invalid_prefix() {
        let net = Ipv4Network::new(Ipv4Addr::new(0, 0, 0, 0), 33);
        assert!(net.is_err());
    }

    #[test]
    fn parse_v4_0bit() {
        let cidr = Ipv4Network::from_cidr("0/0").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(0, 0, 0, 0));
        assert_eq!(cidr.prefix(), 0);
    }

    #[test]
    fn parse_v4_24bit() {
        let cidr = Ipv4Network::from_cidr("127.1.0.0/24").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(127, 1, 0, 0));
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn parse_v4_32bit() {
        let cidr = Ipv4Network::from_cidr("127.0.0.0/32").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(127, 0, 0, 0));
        assert_eq!(cidr.prefix(), 32);
    }

    #[test]
    fn parse_v4_fail_addr() {
        let cidr = Ipv4Network::from_cidr("10.a.b/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_fail_addr2() {
        let cidr = Ipv4Network::from_cidr("10.1.1.1.0/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_fail_addr3() {
        let cidr = Ipv4Network::from_cidr("256/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_non_zero_host_bits() {
        let cidr = Ipv4Network::from_cidr("10.1.1.1/24").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(10, 1, 1, 1));
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn parse_v4_fail_prefix() {
        let cidr = Ipv4Network::from_cidr("0/39");
        assert!(cidr.is_err());
    }

    #[test]
    fn size_v4_24bit() {
        let net = Ipv4Network::from_cidr("0/24").unwrap();
        assert_eq!(net.size(), 256);
    }

    #[test]
    fn size_v4_1bit() {
        let net = Ipv4Network::from_cidr("0/31").unwrap();
        assert_eq!(net.size(), 2);
    }

    #[test]
    fn size_v4_max() {
        let net = Ipv4Network::from_cidr("0/0").unwrap();
        assert_eq!(net.size(), 4_294_967_296);
    }

    #[test]
    fn size_v4_min() {
        let net = Ipv4Network::from_cidr("0/32").unwrap();
        assert_eq!(net.size(), 1);
    }

    #[test]
    fn nth_v4() {
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 24).unwrap();
        assert_eq!(net.nth(0).unwrap(), Ipv4Addr::new(127, 0, 0, 0));
        assert_eq!(net.nth(1).unwrap(), Ipv4Addr::new(127, 0, 0, 1));
        assert_eq!(net.nth(255).unwrap(), Ipv4Addr::new(127, 0, 0, 255));
        assert!(net.nth(256).is_none());
    }

    #[test]
    fn nth_v4_fail() {
        let net = Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 0), 32).unwrap();
        assert!(net.nth(1).is_none());
    }

    #[test]
    fn hash_eq_compatibility_v4() {
        let mut map = HashMap::new();
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 16).unwrap();
        map.insert(net, 137);
        let out = map.get(&net).unwrap();
        assert_eq!(137, *out);
    }

    #[test]
    fn copy_compatibility_v4() {
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 16).unwrap();
        mem::drop(net);
        assert_eq!(16, net.prefix());
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29).unwrap();
        let (ip, int) = cidr.mask();
        assert_eq!(ip, Ipv4Addr::new(255, 255, 255, 248));
        assert_eq!(int, 4294967288);
    }

    #[test]
    fn network_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23).unwrap();
        let (ip, int) = cidr.network();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 0, 0));
        assert_eq!(int, 168427520);
    }

    #[test]
    fn broadcast_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23).unwrap();
        let (ip, int) = cidr.broadcast();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 1, 255));
        assert_eq!(int, 168428031);
    }

    #[test]
    fn contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 25).unwrap();
        let ip = Ipv4Addr::new(74, 125, 227, 4);
        assert!(cidr.contains(ip));
    }

    #[test]
    fn not_contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 50), 24).unwrap();
        let ip = Ipv4Addr::new(10, 1, 0, 1);
        assert!(!cidr.contains(ip));
    }

    #[test]
    fn iterator_v4() {
        let cidr = Ipv4Network::from_cidr("192.168.122.0/30").unwrap();
        let mut iter = cidr.iter();
        assert_eq!(Ipv4Addr::new(192, 168, 122, 0), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 1), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 2), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 3), iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn iterator_v4_tiny() {
        let cidr = Ipv4Network::from_cidr("10/32").unwrap();
        let mut iter = cidr.iter();
        assert_eq!(Ipv4Addr::new(10, 0, 0, 0), iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    // Tests the entire IPv4 space to see if the iterator will stop at the correct place
    // and not overflow or wrap around. Ignored since it takes a long time to run.
    #[test]
    #[ignore]
    fn iterator_v4_huge() {
        let cidr = Ipv4Network::from_cidr("0/0").unwrap();
        let mut iter = cidr.iter();
        for i in 0..(u32::max_value() as u64 + 1) {
            assert_eq!(i as u32, u32::from(iter.next().unwrap()));
        }
        assert_eq!(None, iter.next());
    }
}
<commit_msg>Move ipv4 iter method after constructors<commit_after>use std::fmt;
use std::net::{Ipv4Addr};

use common::{IpNetworkError, cidr_parts, parse_prefix};

const IPV4_BITS: u8 = 32;

#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

impl Ipv4Network {
    /// Constructs a new `Ipv4Network` from any `Ipv4Addr` and a prefix denoting the network size.
    /// If the prefix is larger than 32 this will return an `IpNetworkError::InvalidPrefix`.
    pub fn new(addr: Ipv4Addr, prefix: u8) -> Result<Ipv4Network, IpNetworkError> {
        if prefix > IPV4_BITS {
            Err(IpNetworkError::InvalidPrefix)
        } else {
            Ok(Ipv4Network {
                addr: addr,
                prefix: prefix,
            })
        }
    }

    pub fn from_cidr(cidr: &str) -> Result<Ipv4Network, IpNetworkError> {
        let (addr_str, prefix_str) = try!(cidr_parts(cidr));
        let addr = try!(Self::parse_addr(addr_str));
        let prefix = try!(parse_prefix(prefix_str, IPV4_BITS));
        Self::new(addr, prefix)
    }

    /// Returns an iterator over `Ipv4Network`. Each call to `next` will return the next
    /// `Ipv4Addr` in the given network. `None` will be returned when there are no more
    /// addresses.
    pub fn iter(&self) -> Ipv4NetworkIterator {
        let (_, start) = self.network();
        let end = start as u64 + self.size();
        Ipv4NetworkIterator {
            next: start as u64,
            end: end,
        }
    }

    pub fn ip(&self) -> Ipv4Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }

    pub fn mask(&self) -> (Ipv4Addr, u32) {
        let prefix = self.prefix;
        let mask = !(0xffffffff as u64 >> prefix) as u32;
        (Ipv4Addr::from(mask), mask)
    }

    pub fn network(&self) -> (Ipv4Addr, u32) {
        let (_, mask) = self.mask();
        let ip = u32::from(self.addr) & mask;
        (Ipv4Addr::from(ip), ip)
    }

    pub fn broadcast(&self) -> (Ipv4Addr, u32) {
        let (_, network) = self.network();
        let (_, mask) = self.mask();
        let broadcast = network | !mask;
        (Ipv4Addr::from(broadcast), broadcast)
    }

    pub fn contains(&self, ip: Ipv4Addr) -> bool {
        let (_, net) = self.network();
        let (_, mask) = self.mask();
        (u32::from(ip) & mask) == net
    }

    /// Returns number of possible host addresses in this `Ipv4Network`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnetwork::Ipv4Network;
    ///
    /// let net = Ipv4Network::from_cidr("10.1.0.0/16").unwrap();
    /// assert_eq!(net.size(), 65536);
    ///
    /// let tinynet = Ipv4Network::from_cidr("0.0.0.0/32").unwrap();
    /// assert_eq!(tinynet.size(), 1);
    /// ```
    pub fn size(&self) -> u64 {
        let host_bits = (IPV4_BITS - self.prefix) as u32;
        (2 as u64).pow(host_bits)
    }

    /// Returns the `n`:th address within this network.
    /// The adresses are indexed from 0 and `n` must be smaller than the size of the network.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnetwork::Ipv4Network;
    ///
    /// let net = Ipv4Network::from_cidr("192.168.0.0/24").unwrap();
    /// assert_eq!(net.nth(0).unwrap(), Ipv4Addr::new(192, 168, 0, 0));
    /// assert_eq!(net.nth(15).unwrap(), Ipv4Addr::new(192, 168, 0, 15));
    /// assert!(net.nth(256).is_none());
    ///
    /// let net2 = Ipv4Network::from_cidr("10.0.0.0/16").unwrap();
    /// assert_eq!(net2.nth(256).unwrap(), Ipv4Addr::new(10, 0, 1, 0));
    /// ```
    pub fn nth(&self, n: u32) -> Option<Ipv4Addr> {
        if (n as u64) < self.size() {
            let (_, net) = self.network();
            Some(Ipv4Addr::from(net + n))
        } else {
            None
        }
    }

    fn parse_addr(addr: &str) -> Result<Ipv4Addr, IpNetworkError> {
        let addr_parts = addr.split('.').map(|b| b.parse::<u8>());
        let mut bytes = [0; 4];
        for (i, byte) in addr_parts.enumerate() {
            if i >= 4 {
                return Err(IpNetworkError::InvalidAddr(format!("More than 4 bytes: {}", addr)));
            }
            bytes[i] = try!(byte.map_err(|_| {
                IpNetworkError::InvalidAddr(format!("All bytes not 0-255: {}", addr))
            }));
        }
        Ok(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))
    }
}

impl fmt::Display for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

pub struct Ipv4NetworkIterator {
    next: u64,
    end: u64,
}

impl Iterator for Ipv4NetworkIterator {
    type Item = Ipv4Addr;

    fn next(&mut self) -> Option<Ipv4Addr> {
        if self.next < self.end {
            let next = Ipv4Addr::from(self.next as u32);
            self.next += 1;
            Some(next)
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::collections::HashMap;
    use std::net::Ipv4Addr;
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24).unwrap();
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v4_invalid_prefix() {
        let net = Ipv4Network::new(Ipv4Addr::new(0, 0, 0, 0), 33);
        assert!(net.is_err());
    }

    #[test]
    fn parse_v4_0bit() {
        let cidr = Ipv4Network::from_cidr("0/0").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(0, 0, 0, 0));
        assert_eq!(cidr.prefix(), 0);
    }

    #[test]
    fn parse_v4_24bit() {
        let cidr = Ipv4Network::from_cidr("127.1.0.0/24").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(127, 1, 0, 0));
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn parse_v4_32bit() {
        let cidr = Ipv4Network::from_cidr("127.0.0.0/32").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(127, 0, 0, 0));
        assert_eq!(cidr.prefix(), 32);
    }

    #[test]
    fn parse_v4_fail_addr() {
        let cidr = Ipv4Network::from_cidr("10.a.b/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_fail_addr2() {
        let cidr = Ipv4Network::from_cidr("10.1.1.1.0/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_fail_addr3() {
        let cidr = Ipv4Network::from_cidr("256/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_non_zero_host_bits() {
        let cidr = Ipv4Network::from_cidr("10.1.1.1/24").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(10, 1, 1, 1));
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn parse_v4_fail_prefix() {
        let cidr = Ipv4Network::from_cidr("0/39");
        assert!(cidr.is_err());
    }

    #[test]
    fn size_v4_24bit() {
        let net = Ipv4Network::from_cidr("0/24").unwrap();
        assert_eq!(net.size(), 256);
    }

    #[test]
    fn size_v4_1bit() {
        let net = Ipv4Network::from_cidr("0/31").unwrap();
        assert_eq!(net.size(), 2);
    }

    #[test]
    fn size_v4_max() {
        let net = Ipv4Network::from_cidr("0/0").unwrap();
        assert_eq!(net.size(), 4_294_967_296);
    }

    #[test]
    fn size_v4_min() {
        let net = Ipv4Network::from_cidr("0/32").unwrap();
        assert_eq!(net.size(), 1);
    }

    #[test]
    fn nth_v4() {
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 24).unwrap();
        assert_eq!(net.nth(0).unwrap(), Ipv4Addr::new(127, 0, 0, 0));
        assert_eq!(net.nth(1).unwrap(), Ipv4Addr::new(127, 0, 0, 1));
        assert_eq!(net.nth(255).unwrap(), Ipv4Addr::new(127, 0, 0, 255));
        assert!(net.nth(256).is_none());
    }

    #[test]
    fn nth_v4_fail() {
        let net = Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 0), 32).unwrap();
        assert!(net.nth(1).is_none());
    }

    #[test]
    fn hash_eq_compatibility_v4() {
        let mut map = HashMap::new();
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 16).unwrap();
        map.insert(net, 137);
        let out = map.get(&net).unwrap();
        assert_eq!(137, *out);
    }

    #[test]
    fn copy_compatibility_v4() {
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 16).unwrap();
        mem::drop(net);
        assert_eq!(16, net.prefix());
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29).unwrap();
        let (ip, int) = cidr.mask();
        assert_eq!(ip, Ipv4Addr::new(255, 255, 255, 248));
        assert_eq!(int, 4294967288);
    }

    #[test]
    fn network_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23).unwrap();
        let (ip, int) = cidr.network();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 0, 0));
        assert_eq!(int, 168427520);
    }

    #[test]
    fn broadcast_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23).unwrap();
        let (ip, int) = cidr.broadcast();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 1, 255));
        assert_eq!(int, 168428031);
    }

    #[test]
    fn contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 25).unwrap();
        let ip = Ipv4Addr::new(74, 125, 227, 4);
        assert!(cidr.contains(ip));
    }

    #[test]
    fn not_contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 50), 24).unwrap();
        let ip = Ipv4Addr::new(10, 1, 0, 1);
        assert!(!cidr.contains(ip));
    }

    #[test]
    fn iterator_v4() {
        let cidr = Ipv4Network::from_cidr("192.168.122.0/30").unwrap();
        let mut iter = cidr.iter();
        assert_eq!(Ipv4Addr::new(192, 168, 122, 0), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 1), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 2), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 3), iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn iterator_v4_tiny() {
        let cidr = Ipv4Network::from_cidr("10/32").unwrap();
        let mut iter = cidr.iter();
        assert_eq!(Ipv4Addr::new(10, 0, 0, 0), iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    // Tests the entire IPv4 space to see if the iterator will stop at the correct place
    // and not overflow or wrap around. Ignored since it takes a long time to run.
    #[test]
    #[ignore]
    fn iterator_v4_huge() {
        let cidr = Ipv4Network::from_cidr("0/0").unwrap();
        let mut iter = cidr.iter();
        for i in 0..(u32::max_value() as u64 + 1) {
            assert_eq!(i as u32, u32::from(iter.next().unwrap()));
        }
        assert_eq!(None, iter.next());
    }
}
<|endoftext|>


<commit_before>pub trait IteratorCloneEach<'a, E, It> where E: Clone, It: Iterator<&'a E> {
    /**
Creates an iterator which will clone each element of the input iterator.
    */
    fn clone_each(self) -> CloneItems<It>;
}

impl<'a, E, It> IteratorCloneEach<'a, E, It> for It where E: Clone, It: Iterator<&'a E> {
    fn clone_each(self) -> CloneItems<It> {
        CloneItems {
            iter: self,
        }
    }
}

pub struct CloneItems<It> {
    iter: It,
}

impl<'a, E, It> Iterator<E> for CloneItems<It> where E: 'a+Clone, It: Iterator<&'a E> {
    fn next(&mut self) -> Option<E> {
        match self.iter.next() {
            None => None,
            Some(e) => Some(e.clone())
        }
    }
}

#[test]
fn test_clone_each() {
    let it: Vec<int> = vec![1, 2, 3];
    let mut it = it.iter().clone_each();
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), None);
}

pub trait IteratorFoldl<E> {
    /**
Folds the elements of the iterator together, from left to right, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldl(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldl<E> for It where It: Iterator<E> {
    fn foldl(mut self, f: |E, E| -> E) -> Option<E> {
        let first = match self.next() {
            None => return None,
            Some(e) => e
        };

        Some(self.fold(first, f))
    }
}

#[test]
fn test_foldl() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("((a, b), c)".into_string()), vs.foldl(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorFoldr<E> {
    /**
Folds the elements of the iterator together, from right to left, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldr(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldr<E> for It where It: DoubleEndedIterator<E> {
    fn foldr(mut self, f: |E, E| -> E) -> Option<E> {
        let mut last = match self.next_back() {
            None => return None,
            Some(e) => e
        };

        loop {
            match self.next_back() {
                None => break,
                Some(e) => last = f(e, last)
            }
        }

        Some(last)
    }
}

#[test]
fn test_foldr() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("(a, (b, c))".into_string()), vs.foldr(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorStride<E, It> where It: Iterator<E> {
    /**
Creates an iterator which yields every `n`th element of the input iterator, including the first.
    */
    fn stride(self, n: uint) -> StrideItems<It>;
}

impl<E, It> IteratorStride<E, It> for It where It: Iterator<E> {
    fn stride(self, n: uint) -> StrideItems<It> {
        StrideItems {
            iter: self,
            stride: n
        }
    }
}

pub struct StrideItems<It> {
    iter: It,
    stride: uint,
}

impl<E, It> Iterator<E> for StrideItems<It> where It: Iterator<E> {
    fn next(&mut self) -> Option<E> {
        let v = match self.iter.next() {
            Some(v) => v,
            None => return None
        };

        for _ in range(0, self.stride - 1) {
            match self.iter.next() {
                None => break,
                _ => ()
            }
        }

        Some(v)
    }
}

#[test]
fn test_stride() {
    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut it = v.iter().clone_each().stride(2);
    assert_eq!(it.next(), Some(0));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(4));
    assert_eq!(it.next(), Some(6));
    assert_eq!(it.next(), Some(8));
    assert_eq!(it.next(), None);
}
<commit_msg>Added size_hint for clone_each and stride.<commit_after>pub trait IteratorCloneEach<'a, E, It> where E: Clone, It: Iterator<&'a E> {
    /**
Creates an iterator which will clone each element of the input iterator.
    */
    fn clone_each(self) -> CloneItems<It>;
}

impl<'a, E, It> IteratorCloneEach<'a, E, It> for It where E: Clone, It: Iterator<&'a E> {
    fn clone_each(self) -> CloneItems<It> {
        CloneItems {
            iter: self,
        }
    }
}

pub struct CloneItems<It> {
    iter: It,
}

impl<'a, E, It> Iterator<E> for CloneItems<It> where E: 'a+Clone, It: Iterator<&'a E> {
    fn next(&mut self) -> Option<E> {
        match self.iter.next() {
            None => None,
            Some(e) => Some(e.clone())
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

#[test]
fn test_clone_each() {
    let it: Vec<int> = vec![1, 2, 3];
    let mut it = it.iter().clone_each();
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), None);
}

pub trait IteratorFoldl<E> {
    /**
Folds the elements of the iterator together, from left to right, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldl(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldl<E> for It where It: Iterator<E> {
    fn foldl(mut self, f: |E, E| -> E) -> Option<E> {
        let first = match self.next() {
            None => return None,
            Some(e) => e
        };

        Some(self.fold(first, f))
    }
}

#[test]
fn test_foldl() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("((a, b), c)".into_string()), vs.foldl(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorFoldr<E> {
    /**
Folds the elements of the iterator together, from right to left, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldr(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldr<E> for It where It: DoubleEndedIterator<E> {
    fn foldr(mut self, f: |E, E| -> E) -> Option<E> {
        let mut last = match self.next_back() {
            None => return None,
            Some(e) => e
        };

        loop {
            match self.next_back() {
                None => break,
                Some(e) => last = f(e, last)
            }
        }

        Some(last)
    }
}

#[test]
fn test_foldr() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("(a, (b, c))".into_string()), vs.foldr(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorStride<E, It> where It: Iterator<E> {
    /**
Creates an iterator which yields every `n`th element of the input iterator, including the first.
    */
    fn stride(self, n: uint) -> StrideItems<It>;
}

impl<E, It> IteratorStride<E, It> for It where It: Iterator<E> {
    fn stride(self, n: uint) -> StrideItems<It> {
        StrideItems {
            iter: self,
            stride: n
        }
    }
}

pub struct StrideItems<It> {
    iter: It,
    stride: uint,
}

impl<E, It> Iterator<E> for StrideItems<It> where It: Iterator<E> {
    fn next(&mut self) -> Option<E> {
        let v = match self.iter.next() {
            Some(v) => v,
            None => return None
        };

        for _ in range(0, self.stride - 1) {
            match self.iter.next() {
                None => break,
                _ => ()
            }
        }

        Some(v)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        match self.iter.size_hint() {
            (lb, Some(ub)) => ((lb + self.stride - 1) / self.stride,
                                Some((ub + self.stride - 1) / self.stride)),
            (lb, None) => (lb, None)
        }
    }
}

#[test]
fn test_stride() {
    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut it = v.iter().clone_each().stride(2);
    assert_eq!(it.size_hint(), (5, Some(5)));
    assert_eq!(it.next(), Some(0));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(4));
    assert_eq!(it.next(), Some(6));
    assert_eq!(it.next(), Some(8));
    assert_eq!(it.next(), None);

    let v = vec![0i, 1, 2, 3, 4, 5];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (2, Some(2)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (4, Some(4)));
}
<|endoftext|>