<commit_before>extern crate image;

use std::fs::File;
use std::io::BufReader;
use std::path::Path;

use cgmath::Point2;
use cgmath::conv::*;

use glium::backend::Facade;
use glium::texture::{RawImage2d, SrgbTexture2d};

use crate::obj_load;
use crate::color::Color;

/// Material for CPU rendering
pub struct Material {
    pub diffuse: Color,
    pub diffuse_image: Option<image::RgbaImage>,    // Texture on the CPU
    pub emissive: Option<Color>,
}

/// Material for GPU rendering
pub struct GPUMaterial {
    pub diffuse: [f32; 3],
    pub has_diffuse: bool,
    pub diffuse_texture: SrgbTexture2d,      // Texture on the GPU
    pub has_emissive: bool,
}

impl Material {
    /// Create a new material based on a material loaded from the scene file
    pub fn new(obj_mat: &obj_load::Material) -> Material {
        // Create diffuse texture and load it to the GPU
        let diffuse_image = match obj_mat.tex_diffuse {
            Some(ref tex_path) => Some(Material::load_image(tex_path)),
            None => None
        };
        let emissive = obj_mat.c_emissive.and_then(
            |e| if e == [0.0, 0.0, 0.0] { None }
            else { Some(Color::from(e)) });

        Material {
            diffuse: Color::from(obj_mat.c_diffuse.expect("No diffuse color!")),
            diffuse_image,
            emissive,
        }
    }

    /// Load an image from path
    fn load_image(path: &Path) -> image::RgbaImage {
        let tex_reader = BufReader::new(File::open(path).expect("Failed to open image!"));
        image::load(tex_reader, image::PNG).expect("Failed to load image!").to_rgba()
    }

    /// Upload textures to the GPU
    pub fn upload_textures<F: Facade>(&self, facade: &F) -> GPUMaterial {
        let diffuse_texture = match self.diffuse_image {
            Some(ref image) => {
                let image_dim = image.dimensions();
                let tex_image = RawImage2d::from_raw_rgba_reversed(&image.clone().into_raw(), image_dim);
                SrgbTexture2d::new(facade, tex_image).expect("Failed to upload texture!")
            }
            // Use empty texture as a placeholder
            None => SrgbTexture2d::empty(facade, 0, 0).expect("Failed to upload empty texture!")
        };
        GPUMaterial {
            diffuse: array3(self.diffuse),
            has_diffuse: self.diffuse_image.is_some(),
            diffuse_texture,
            has_emissive: self.emissive.is_some(),
        }
    }

    pub fn diffuse(&self, tex_coords: Point2<f32>) -> Color {
        if let Some(tex) = &self.diffuse_image {
            let (width, height) = tex.dimensions();
            let x = tex_coords.x.mod_euc(1.0) * (width - 1) as f32;
            let y = (1.0 - tex_coords.y.mod_euc(1.0)) * (height - 1) as f32;
            let x_fract = x.fract();
            let y_fract = y.fract();
            let (left, right) = if x >= (width - 1) as f32{
                (width - 1, width - 1)
            } else {
                (x.floor() as u32, x.ceil() as u32)
            };
            let (top, bottom) = if y >= (height - 1) as f32{
                (height - 1, height - 1)
            } else {
                (y.floor() as u32, y.ceil() as u32)
            };
            let tl = Color::from(tex.get_pixel(left, top));
            let bl = Color::from(tex.get_pixel(left, bottom));
            let tr = Color::from(tex.get_pixel(right, top));
            let br = Color::from(tex.get_pixel(right, bottom));
            let top_c = x_fract * tr + (1.0 - x_fract) * tl;
            let bottom_c = x_fract * br + (1.0 - x_fract) * bl;
            y_fract * bottom_c + (1.0 - y_fract) * top_c
        } else {
            self.diffuse
        }
    }
}
<commit_msg>Support more texture formats<commit_after>use std::fs::File;
use std::io::BufReader;
use std::path::Path;

use cgmath::Point2;
use cgmath::conv::*;

use glium::backend::Facade;
use glium::texture::{RawImage2d, SrgbTexture2d};

use image::ImageFormat;

use crate::obj_load;
use crate::color::Color;

/// Material for CPU rendering
pub struct Material {
    pub diffuse: Color,
    pub diffuse_image: Option<image::RgbaImage>,    // Texture on the CPU
    pub emissive: Option<Color>,
}

/// Material for GPU rendering
pub struct GPUMaterial {
    pub diffuse: [f32; 3],
    pub has_diffuse: bool,
    pub diffuse_texture: SrgbTexture2d,      // Texture on the GPU
    pub has_emissive: bool,
}

impl Material {
    /// Create a new material based on a material loaded from the scene file
    pub fn new(obj_mat: &obj_load::Material) -> Material {
        // Create diffuse texture and load it to the GPU
        let diffuse_image = match obj_mat.tex_diffuse {
            Some(ref tex_path) => Some(Material::load_image(tex_path)),
            None => None
        };
        let emissive = obj_mat.c_emissive.and_then(
            |e| if e == [0.0, 0.0, 0.0] { None }
            else { Some(Color::from(e)) });

        Material {
            diffuse: Color::from(obj_mat.c_diffuse.expect("No diffuse color!")),
            diffuse_image,
            emissive,
        }
    }

    /// Load an image from path
    fn load_image(path: &Path) -> image::RgbaImage {
        let image_format = match path.extension().unwrap().to_str().unwrap() {
            "png" => ImageFormat::PNG,
            "jpg" | "jpeg" => ImageFormat::JPEG,
            "gif" => ImageFormat::GIF,
            "webp" => ImageFormat::WEBP,
            "pnm" => ImageFormat::PNM,
            "tiff" => ImageFormat::TIFF,
            "tga" => ImageFormat::TGA,
            "bmp" => ImageFormat::BMP,
            "ico" => ImageFormat::ICO,
            "hdr" => ImageFormat::HDR,
            ext @ _ => panic!("Unknown image extension {}", ext),
        };
        // TODO: dont panic just warn and ignore texture
        let tex_reader = BufReader::new(File::open(path).unwrap_or_else(
            |_| panic!("Failed to open image {:?}!", path)));
        image::load(tex_reader, image_format).expect("Failed to load image!").to_rgba()
    }

    /// Upload textures to the GPU
    pub fn upload_textures<F: Facade>(&self, facade: &F) -> GPUMaterial {
        let diffuse_texture = match self.diffuse_image {
            Some(ref image) => {
                let image_dim = image.dimensions();
                let tex_image = RawImage2d::from_raw_rgba_reversed(&image.clone().into_raw(), image_dim);
                SrgbTexture2d::new(facade, tex_image).expect("Failed to upload texture!")
            }
            // Use empty texture as a placeholder
            None => SrgbTexture2d::empty(facade, 0, 0).expect("Failed to upload empty texture!")
        };
        GPUMaterial {
            diffuse: array3(self.diffuse),
            has_diffuse: self.diffuse_image.is_some(),
            diffuse_texture,
            has_emissive: self.emissive.is_some(),
        }
    }

    pub fn diffuse(&self, tex_coords: Point2<f32>) -> Color {
        if let Some(tex) = &self.diffuse_image {
            let (width, height) = tex.dimensions();
            let x = tex_coords.x.mod_euc(1.0) * (width - 1) as f32;
            let y = (1.0 - tex_coords.y.mod_euc(1.0)) * (height - 1) as f32;
            let x_fract = x.fract();
            let y_fract = y.fract();
            let (left, right) = if x >= (width - 1) as f32{
                (width - 1, width - 1)
            } else {
                (x.floor() as u32, x.ceil() as u32)
            };
            let (top, bottom) = if y >= (height - 1) as f32{
                (height - 1, height - 1)
            } else {
                (y.floor() as u32, y.ceil() as u32)
            };
            let tl = Color::from(tex.get_pixel(left, top));
            let bl = Color::from(tex.get_pixel(left, bottom));
            let tr = Color::from(tex.get_pixel(right, top));
            let br = Color::from(tex.get_pixel(right, bottom));
            let top_c = x_fract * tr + (1.0 - x_fract) * tl;
            let bottom_c = x_fract * br + (1.0 - x_fract) * bl;
            y_fract * bottom_c + (1.0 - y_fract) * top_c
        } else {
            self.diffuse
        }
    }
}
<|endoftext|>


<commit_before>pub mod variables;
pub mod relationships;
pub mod expressions;

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use math::variables::{AbstVar, new_var, new_const, new_slack_var};
    use math::relationships::Relationship;
    use math::expressions::Expression;

    #[test]
    fn can_create_variables() {
        let v: AbstVar = new_var("x", 2.0);
        assert_eq!(AbstVar::Variable {
                       name: "x".to_string(),
                       coefficient: 2.0,
                   },
                   v);
        assert_eq!("x", v.name());
        assert_eq!(2.0, v.get_data());
    }

    #[test]
    fn can_set_coefficient() {
        let abst_var_state: RefCell<AbstVar> = RefCell::new(new_var("x", 2.0));
        {
            let mut abst_var = abst_var_state.borrow_mut();
            abst_var.set_data(3.0);
        }
        assert_eq!(3.0, abst_var_state.borrow().get_data());
    }

    #[test]
    fn can_create_constants() {
        let c: AbstVar = new_const("barrels in stock", 450.0);
        assert_eq!(AbstVar::Constant {
                       name: "barrels in stock".to_string(),
                       value: 450.0,
                   },
                   c);
        assert_eq!("barrels in stock", c.name());
        assert_eq!(450.0, c.get_data());
    }

    #[test]
    fn can_set_value() {
        let abst_var_state: RefCell<AbstVar> = RefCell::new(new_const("days", 365.0));
        {
            let mut abst_var = abst_var_state.borrow_mut();
            abst_var.set_data(366.0);
        }
        assert_eq!(366.0, abst_var_state.borrow().get_data());
    }

    #[test]
    fn can_create_slack_var() {
        let s_var: AbstVar = new_slack_var("s1".to_string());
        assert_eq!("s1", s_var.name());
    }

    #[test]
    fn can_get_from_slack_var() {
        let s_var: AbstVar = new_slack_var("s1".to_string());
        assert_eq!(1.0, s_var.get_data());
    }

    #[test]
    fn can_create_relationships() {
        let r: Relationship = Relationship::EQ;
        assert_eq!(Relationship::EQ, r);
        let r: Relationship = Relationship::LEQ;
        assert_eq!(Relationship::LEQ, r);
        let r: Relationship = Relationship::GEQ;
        assert_eq!(Relationship::GEQ, r);
    }

    #[test]
    fn can_create_expressions() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        assert_eq!("Z", e.lhs()[0].name());
        assert_eq!(1.0, e.lhs()[0].get_data());
        assert_eq!(Relationship::EQ, *e.rel());
        assert_eq!("x", e.rhs()[0].name());
        assert_eq!(2.0, e.rhs()[0].get_data());
        assert_eq!("y", e.rhs()[1].name());
        assert_eq!(3.0, e.rhs()[1].get_data());
        assert_eq!("bonus", e.rhs()[2].name());
        assert_eq!(1000.0, e.rhs()[2].get_data());
    }

    #[test]
    fn can_set_rels() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::LEQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        let e_state: RefCell<Expression> = RefCell::new(e);
        {
            let mut exp = e_state.borrow_mut();
            exp.set_rel(Relationship::EQ);
        }
        let exp = e_state.borrow();
        assert_eq!(Relationship::EQ, *exp.rel());
    }

    #[test]
    fn can_add_lhs() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        let e_state: RefCell<Expression> = RefCell::new(e);
        {
            let mut exp = e_state.borrow_mut();
            exp.add_lhs(new_var("w", 9.0));
            exp.add_lhs(new_const("weight", 700.0));
            exp.add_lhs(new_slack_var("s1".to_string()));
        }
        let exp = e_state.borrow();
        assert_eq!("Z", exp.lhs()[0].name());
        assert_eq!(1.0, exp.lhs()[0].get_data());
        assert_eq!("w", exp.lhs()[1].name());
        assert_eq!(9.0, exp.lhs()[1].get_data());
        assert_eq!("weight", exp.lhs()[2].name());
        assert_eq!(700.0, exp.lhs()[2].get_data());
        assert_eq!("s1", exp.lhs()[3].name());
        assert_eq!(Relationship::EQ, *exp.rel());
        assert_eq!("x", exp.rhs()[0].name());
        assert_eq!(2.0, exp.rhs()[0].get_data());
        assert_eq!("y", exp.rhs()[1].name());
        assert_eq!(3.0, exp.rhs()[1].get_data());
        assert_eq!("bonus", exp.rhs()[2].name());
        assert_eq!(1000.0, exp.rhs()[2].get_data());
    }

    #[test]
    fn can_move_from_lhs_side() {
        let mut e1: Expression =
            Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)],
                            Relationship::GEQ,
                            vec![new_var("Z", 1.0)]);

        e1.move_from_lhs_side(1, false);
        assert_eq!(2, e1.lhs().len());
        assert_eq!("x", e1.lhs()[0].name());
        assert_eq!(2.0, e1.lhs()[0].get_data());
        assert_eq!("bonus", e1.lhs()[1].name());
        assert_eq!(1000.0, e1.lhs()[1].get_data());
        assert_eq!(Relationship::GEQ, *e1.rel());
        assert_eq!(2, e1.rhs().len());
        assert_eq!("Z", e1.rhs()[0].name());
        assert_eq!(1.0, e1.rhs()[0].get_data());
        assert_eq!("y", e1.rhs()[1].name());
        assert_eq!(-3.0, e1.rhs()[1].get_data());

        e1.move_from_lhs_side(0, true);
        assert_eq!(1, e1.lhs().len());
        assert_eq!("bonus", e1.lhs()[0].name());
        assert_eq!(1000.0, e1.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e1.rel());
        assert_eq!(3, e1.rhs().len());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].get_data());
        assert_eq!("Z", e1.rhs()[1].name());
        assert_eq!(1.0, e1.rhs()[1].get_data());
        assert_eq!("y", e1.rhs()[2].name());
        assert_eq!(-3.0, e1.rhs()[2].get_data());

        e1.move_from_lhs_side(0, false);
        assert_eq!(1, e1.lhs().len());
        assert_eq!("zero", e1.lhs()[0].name());
        assert_eq!(0.0, e1.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e1.rel());
        assert_eq!(4, e1.rhs().len());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].get_data());
        assert_eq!("Z", e1.rhs()[1].name());
        assert_eq!(1.0, e1.rhs()[1].get_data());
        assert_eq!("y", e1.rhs()[2].name());
        assert_eq!(-3.0, e1.rhs()[2].get_data());
        assert_eq!("bonus", e1.rhs()[3].name());
        assert_eq!(-1000.0, e1.rhs()[3].get_data());

        let mut e2: Expression =
            Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)],
                            Relationship::GEQ,
                            vec![new_var("Z", 1.0), new_slack_var("s1".to_string())]);

        e2.move_from_lhs_side(1, false);
        assert_eq!(2, e2.lhs().len());
        assert_eq!("x", e2.lhs()[0].name());
        assert_eq!(2.0, e2.lhs()[0].get_data());
        assert_eq!("bonus", e2.lhs()[1].name());
        assert_eq!(1000.0, e2.lhs()[1].get_data());
        assert_eq!(Relationship::GEQ, *e2.rel());
        assert_eq!(3, e2.rhs().len());
        assert_eq!("Z", e2.rhs()[0].name());
        assert_eq!(1.0, e2.rhs()[0].get_data());
        assert_eq!("y", e2.rhs()[1].name());
        assert_eq!(-3.0, e2.rhs()[1].get_data());
        assert_eq!("s1", e2.rhs()[2].name());
        assert_eq!(1.0, e2.rhs()[2].get_data());

        e2.move_from_lhs_side(0, true);
        assert_eq!(1, e2.lhs().len());
        assert_eq!("bonus", e2.lhs()[0].name());
        assert_eq!(1000.0, e2.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e2.rel());
        assert_eq!(4, e2.rhs().len());
        assert_eq!("x", e2.rhs()[0].name());
        assert_eq!(-2.0, e2.rhs()[0].get_data());
        assert_eq!("Z", e2.rhs()[1].name());
        assert_eq!(1.0, e2.rhs()[1].get_data());
        assert_eq!("y", e2.rhs()[2].name());
        assert_eq!(-3.0, e2.rhs()[2].get_data());
        assert_eq!("s1", e2.rhs()[3].name());
        assert_eq!(1.0, e2.rhs()[3].get_data());

        e2.move_from_lhs_side(0, true);
        assert_eq!(1, e2.lhs().len());
        assert_eq!("zero", e2.lhs()[0].name());
        assert_eq!(0.0, e2.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e2.rel());
        assert_eq!(5, e2.rhs().len());
        assert_eq!("bonus", e2.rhs()[0].name());
        assert_eq!(-1000.0, e2.rhs()[0].get_data());
        assert_eq!("x", e2.rhs()[1].name());
        assert_eq!(-2.0, e2.rhs()[1].get_data());
        assert_eq!("Z", e2.rhs()[2].name());
        assert_eq!(1.0, e2.rhs()[2].get_data());
        assert_eq!("y", e2.rhs()[3].name());
        assert_eq!(-3.0, e2.rhs()[3].get_data());
        assert_eq!("s1", e2.rhs()[4].name());
        assert_eq!(1.0, e2.rhs()[4].get_data());
    }

    #[test]
    fn can_mul_both_sides_of_expressions() {
        let mut e1: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::GEQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        e1.mul_both_sides(-1.0);
        assert_eq!("Z", e1.lhs()[0].name());
        assert_eq!(-1.0, e1.lhs()[0].get_data());
        assert_eq!(Relationship::LEQ, *e1.rel());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].get_data());
        assert_eq!("y", e1.rhs()[1].name());
        assert_eq!(-3.0, e1.rhs()[1].get_data());
        assert_eq!("bonus", e1.rhs()[2].name());
        assert_eq!(-1000.0, e1.rhs()[2].get_data());
    }

    #[test]
    fn can_swap_sides() {
        let mut exp: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);

        exp.swap_sides().unwrap();
        assert_eq!(3, exp.lhs().len());
        assert_eq!("x", exp.lhs()[0].name());
        assert_eq!(2.0, exp.lhs()[0].get_data());
        assert_eq!("y", exp.lhs()[1].name());
        assert_eq!(3.0, exp.lhs()[1].get_data());
        assert_eq!("bonus", exp.lhs()[2].name());
        assert_eq!(1000.0, exp.lhs()[2].get_data());
        assert_eq!(Relationship::EQ, *exp.rel());
        assert_eq!(1, exp.rhs().len());
        assert_eq!("Z", exp.rhs()[0].name());
        assert_eq!(1.0, exp.rhs()[0].get_data());

        exp.set_rel(Relationship::LEQ);
        assert!(exp.swap_sides().is_err());

        exp.set_rel(Relationship::GEQ);
        assert!(exp.swap_sides().is_err());
    }
}
<commit_msg>Refactor the math module tests.<commit_after>pub mod variables;
pub mod relationships;
pub mod expressions;

#[cfg(test)]
mod tests {
    use math::variables::{AbstVar, new_var, new_const, new_slack_var};
    use math::relationships::Relationship;
    use math::expressions::Expression;

    #[test]
    fn can_create_variables() {
        let v1 = new_var("x", 2.0);
        assert_eq!(AbstVar::Variable {
                       name: "x".to_string(),
                       coefficient: 2.0,
                   },
                   v1);
        assert_eq!("x", v1.name());
        assert_eq!(2.0, v1.get_data());

        let c1 = new_const("barrels in stock", 450.0);
        assert_eq!(AbstVar::Constant {
                       name: "barrels in stock".to_string(),
                       value: 450.0,
                   },
                   c1);
        assert_eq!("barrels in stock", c1.name());
        assert_eq!(450.0, c1.get_data());

        let s_var = new_slack_var("s1".to_string());
        assert_eq!(AbstVar::SlackVar {
                       name: "s1".to_string(),
                   },
                   s_var);
       assert_eq!("s1", s_var.name());
       assert_eq!(1.0, s_var.get_data());
    }

    #[test]
    fn can_set_data() {
        let mut c2 = new_const("barrels in stock", 450.0);
        c2.set_data(366.0);
        assert_eq!("barrels in stock", c2.name());
        assert_eq!(366.0, c2.get_data());

        let mut v2 = new_var("x", 2.0);
        v2.set_data(3.0);
        assert_eq!(3.0, v2.get_data());
        assert_eq!("x", v2.name());
    }

    #[test]
    fn can_create_relationships() {
        let r1: Relationship = Relationship::EQ;
        assert_eq!(Relationship::EQ, r1);
        let r2: Relationship = Relationship::LEQ;
        assert_eq!(Relationship::LEQ, r2);
        let r3: Relationship = Relationship::GEQ;
        assert_eq!(Relationship::GEQ, r3);
    }

    #[test]
    fn can_create_expressions() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        assert_eq!("Z", e.lhs()[0].name());
        assert_eq!(1.0, e.lhs()[0].get_data());
        assert_eq!(Relationship::EQ, *e.rel());
        assert_eq!("x", e.rhs()[0].name());
        assert_eq!(2.0, e.rhs()[0].get_data());
        assert_eq!("y", e.rhs()[1].name());
        assert_eq!(3.0, e.rhs()[1].get_data());
        assert_eq!("bonus", e.rhs()[2].name());
        assert_eq!(1000.0, e.rhs()[2].get_data());
    }

    #[test]
    fn can_set_rels() {
        let mut exp: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::LEQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        exp.set_rel(Relationship::EQ);
        assert_eq!(Relationship::EQ, *exp.rel());
    }

    #[test]
    fn can_add_lhs() {
        let mut exp: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        exp.add_lhs(new_var("w", 9.0));
        exp.add_lhs(new_const("weight", 700.0));
        exp.add_lhs(new_slack_var("s1".to_string()));
        assert_eq!("Z", exp.lhs()[0].name());
        assert_eq!(1.0, exp.lhs()[0].get_data());
        assert_eq!("w", exp.lhs()[1].name());
        assert_eq!(9.0, exp.lhs()[1].get_data());
        assert_eq!("weight", exp.lhs()[2].name());
        assert_eq!(700.0, exp.lhs()[2].get_data());
        assert_eq!("s1", exp.lhs()[3].name());
        assert_eq!(Relationship::EQ, *exp.rel());
        assert_eq!("x", exp.rhs()[0].name());
        assert_eq!(2.0, exp.rhs()[0].get_data());
        assert_eq!("y", exp.rhs()[1].name());
        assert_eq!(3.0, exp.rhs()[1].get_data());
        assert_eq!("bonus", exp.rhs()[2].name());
        assert_eq!(1000.0, exp.rhs()[2].get_data());
    }

    #[test]
    fn can_move_from_lhs_side() {
        let mut e1: Expression =
            Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)],
                            Relationship::GEQ,
                            vec![new_var("Z", 1.0)]);
        e1.move_from_lhs_side(1, false);
        assert_eq!(2, e1.lhs().len());
        assert_eq!("x", e1.lhs()[0].name());
        assert_eq!(2.0, e1.lhs()[0].get_data());
        assert_eq!("bonus", e1.lhs()[1].name());
        assert_eq!(1000.0, e1.lhs()[1].get_data());
        assert_eq!(Relationship::GEQ, *e1.rel());
        assert_eq!(2, e1.rhs().len());
        assert_eq!("Z", e1.rhs()[0].name());
        assert_eq!(1.0, e1.rhs()[0].get_data());
        assert_eq!("y", e1.rhs()[1].name());
        assert_eq!(-3.0, e1.rhs()[1].get_data());

        e1.move_from_lhs_side(0, true);
        assert_eq!(1, e1.lhs().len());
        assert_eq!("bonus", e1.lhs()[0].name());
        assert_eq!(1000.0, e1.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e1.rel());
        assert_eq!(3, e1.rhs().len());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].get_data());
        assert_eq!("Z", e1.rhs()[1].name());
        assert_eq!(1.0, e1.rhs()[1].get_data());
        assert_eq!("y", e1.rhs()[2].name());
        assert_eq!(-3.0, e1.rhs()[2].get_data());

        e1.move_from_lhs_side(0, false);
        assert_eq!(1, e1.lhs().len());
        assert_eq!("zero", e1.lhs()[0].name());
        assert_eq!(0.0, e1.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e1.rel());
        assert_eq!(4, e1.rhs().len());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].get_data());
        assert_eq!("Z", e1.rhs()[1].name());
        assert_eq!(1.0, e1.rhs()[1].get_data());
        assert_eq!("y", e1.rhs()[2].name());
        assert_eq!(-3.0, e1.rhs()[2].get_data());
        assert_eq!("bonus", e1.rhs()[3].name());
        assert_eq!(-1000.0, e1.rhs()[3].get_data());

        let mut e2: Expression =
            Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)],
                            Relationship::GEQ,
                            vec![new_var("Z", 1.0), new_slack_var("s1".to_string())]);
        e2.move_from_lhs_side(1, false);
        assert_eq!(2, e2.lhs().len());
        assert_eq!("x", e2.lhs()[0].name());
        assert_eq!(2.0, e2.lhs()[0].get_data());
        assert_eq!("bonus", e2.lhs()[1].name());
        assert_eq!(1000.0, e2.lhs()[1].get_data());
        assert_eq!(Relationship::GEQ, *e2.rel());
        assert_eq!(3, e2.rhs().len());
        assert_eq!("Z", e2.rhs()[0].name());
        assert_eq!(1.0, e2.rhs()[0].get_data());
        assert_eq!("y", e2.rhs()[1].name());
        assert_eq!(-3.0, e2.rhs()[1].get_data());
        assert_eq!("s1", e2.rhs()[2].name());
        assert_eq!(1.0, e2.rhs()[2].get_data());

        e2.move_from_lhs_side(0, true);
        assert_eq!(1, e2.lhs().len());
        assert_eq!("bonus", e2.lhs()[0].name());
        assert_eq!(1000.0, e2.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e2.rel());
        assert_eq!(4, e2.rhs().len());
        assert_eq!("x", e2.rhs()[0].name());
        assert_eq!(-2.0, e2.rhs()[0].get_data());
        assert_eq!("Z", e2.rhs()[1].name());
        assert_eq!(1.0, e2.rhs()[1].get_data());
        assert_eq!("y", e2.rhs()[2].name());
        assert_eq!(-3.0, e2.rhs()[2].get_data());
        assert_eq!("s1", e2.rhs()[3].name());
        assert_eq!(1.0, e2.rhs()[3].get_data());

        e2.move_from_lhs_side(0, true);
        assert_eq!(1, e2.lhs().len());
        assert_eq!("zero", e2.lhs()[0].name());
        assert_eq!(0.0, e2.lhs()[0].get_data());
        assert_eq!(Relationship::GEQ, *e2.rel());
        assert_eq!(5, e2.rhs().len());
        assert_eq!("bonus", e2.rhs()[0].name());
        assert_eq!(-1000.0, e2.rhs()[0].get_data());
        assert_eq!("x", e2.rhs()[1].name());
        assert_eq!(-2.0, e2.rhs()[1].get_data());
        assert_eq!("Z", e2.rhs()[2].name());
        assert_eq!(1.0, e2.rhs()[2].get_data());
        assert_eq!("y", e2.rhs()[3].name());
        assert_eq!(-3.0, e2.rhs()[3].get_data());
        assert_eq!("s1", e2.rhs()[4].name());
        assert_eq!(1.0, e2.rhs()[4].get_data());
    }

    #[test]
    fn can_mul_both_sides_of_expressions() {
        let mut exp: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::GEQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        exp.mul_both_sides(-1.0);
        assert_eq!("Z", exp.lhs()[0].name());
        assert_eq!(-1.0, exp.lhs()[0].get_data());
        assert_eq!(Relationship::LEQ, *exp.rel());
        assert_eq!("x", exp.rhs()[0].name());
        assert_eq!(-2.0, exp.rhs()[0].get_data());
        assert_eq!("y", exp.rhs()[1].name());
        assert_eq!(-3.0, exp.rhs()[1].get_data());
        assert_eq!("bonus", exp.rhs()[2].name());
        assert_eq!(-1000.0, exp.rhs()[2].get_data());
    }

    #[test]
    fn can_swap_sides() {
        let mut exp: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        exp.swap_sides().unwrap();
        assert_eq!(3, exp.lhs().len());
        assert_eq!("x", exp.lhs()[0].name());
        assert_eq!(2.0, exp.lhs()[0].get_data());
        assert_eq!("y", exp.lhs()[1].name());
        assert_eq!(3.0, exp.lhs()[1].get_data());
        assert_eq!("bonus", exp.lhs()[2].name());
        assert_eq!(1000.0, exp.lhs()[2].get_data());
        assert_eq!(Relationship::EQ, *exp.rel());
        assert_eq!(1, exp.rhs().len());
        assert_eq!("Z", exp.rhs()[0].name());
        assert_eq!(1.0, exp.rhs()[0].get_data());

        exp.set_rel(Relationship::LEQ);
        assert!(exp.swap_sides().is_err());

        exp.set_rel(Relationship::GEQ);
        assert!(exp.swap_sides().is_err());
    }
}
<|endoftext|>


<commit_before>// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)
pub enum OscType {
    OscInt(i32),
    OscFloat(f32),
    OscString(String), // padding
    OscBlob(Vec<u8>), // padding
    OscTimetag(u64),
    // nonstandard argument types
    // ignore them if not implemented
    OscInt64(i64), // big-endian
    OscDouble(u64),
    OscChar(u8), // padding
    OscColor(u32), // RGBA
    OscMidi(OscMidiType),
    OscTrue,
    OscFalse,
    OscNil,
    OscInf,
    OscArray(Vec<OscType>),
}

pub struct OscMidiType {
    port: u8,
    status: u8,
    data1: u8, // maybe use an enum for data?
    data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
pub enum OscPacket {
    Message(OscMessage),
    Bundle,
}

pub struct OscMessage {
    pub addr: String,
}
<commit_msg>Add `OscBundle` struct<commit_after>// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)
pub enum OscType {
    OscInt(i32),
    OscFloat(f32),
    OscString(String), // padding
    OscBlob(Vec<u8>), // padding
    OscTimetag(u64),
    // nonstandard argument types
    // ignore them if not implemented
    OscInt64(i64), // big-endian
    OscDouble(u64),
    OscChar(u8), // padding
    OscColor(u32), // RGBA
    OscMidi(OscMidiType),
    OscTrue,
    OscFalse,
    OscNil,
    OscInf,
    OscArray(Vec<OscType>),
}

pub struct OscMidiType {
    port: u8,
    status: u8,
    data1: u8, // maybe use an enum for data?
    data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

pub struct OscMessage {
    pub addr: String,
}
pub struct OscBundle;
<|endoftext|>


<commit_before>// This example uses the callback mechanism to find out which file descriptors
// c-ares cares about.  This is a good fit for an event loop; here we use mio.
extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::mem;
use std::net::{
    Ipv4Addr,
    Ipv6Addr,
    SocketAddr,
    SocketAddrV4,
};
use std::os::unix::io;
use std::sync::mpsc;
use std::thread;

// Messages for the event loop.
enum CAresHandlerMessage {
    // 'Notify me when this file descriptor becomes readable, or writable'
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(io::RawFd, bool, bool),

    // 'Shut down'.
    ShutDown,
}

struct CAresEventHandler {
    // Since the event handler owns the Channel, it's tricky to submit further
    // queries once the event loop is running.  If you want to do that,
    // either:
    //
    // -  share the Channel by using an Arc<Mutex<c_ares::Channel>>, OR
    // -  send requests to the event handler as messages, and have it make the
    //    queries
    ares_channel: c_ares::Channel,
    tracked_fds: HashSet<io::RawFd>,
}

impl mio::Handler for CAresEventHandler {
    type Timeout = ();
    type Message = CAresHandlerMessage;

    // mio notifies us that a file descriptor is readable or writable, so we
    // tell the Channel the same.
    fn ready(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        events: mio::EventSet) {
        let fd = token.as_usize() as io::RawFd;
        let read_fd = if events.is_readable() {
            fd
        } else {
            c_ares::INVALID_FD
        };
        let write_fd = if events.is_writable() {
            fd
        } else {
            c_ares::INVALID_FD
        };
        self.ares_channel.process_fd(read_fd, write_fd);
    }

    // Process received messages.  Either:
    // - we're asked to register interest (or non-interest) in a file
    // descriptor
    // - we're asked to shut down the event loop.
    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, readable, writable) => {
                let io = mio::Io::from(fd);
                if !readable && !writable {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&io)
                        .ok()
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::EventSet::none();
                    if readable {
                        interest = interest | mio::EventSet::readable();
                    }
                    if writable {
                        interest = interest | mio::EventSet::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let register_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    } else {
                        event_loop
                            .register_opt(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    };
                    register_result.ok().expect("failed to register interest");
                }

                // Don't accidentally close the file descriptor by dropping io!
                mem::forget(io);
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }

    // We run a recurring timer so that we can spot non-responsive servers.
    //
    // In that case we won't get a callback saying that anything is happening
    // on any file descriptor, but nevertheless need to give the Channel an
    // opportunity to notice that it has timed-out requests pending.
    fn timeout(
        &mut self,
        event_loop: &mut mio::EventLoop<CAresEventHandler>,
        _timeout: Self::Timeout) {
        self.ares_channel.process_fd(c_ares::INVALID_FD, c_ares::INVALID_FD);
        event_loop.timeout_ms((), 500).unwrap();
    }
}

impl CAresEventHandler {
    fn new(ares_channel: c_ares::Channel) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

fn print_a_results(result: Result<c_ares::AResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("A lookup failed with error '{}'", err_string);
        }
        Ok(a_results) => {
            println!("Successful A lookup...");
            println!("Hostname: {}", a_results.hostname());
            for a_result in &a_results {
                println!("{:}", a_result.ipv4_addr());
            }
        }
    }
}

fn print_aaaa_results(result: Result<c_ares::AAAAResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("AAAA lookup failed with error '{}'", err_string);
        }
        Ok(aaaa_results) => {
            println!("Successful AAAA lookup...");
            println!("Hostname: {}", aaaa_results.hostname());
            for aaaa_result in &aaaa_results {
                println!("{:}", aaaa_result.ipv6_addr());
            }
        }
    }
}

fn print_srv_results(result: Result<c_ares::SRVResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("SRV lookup failed with error '{}'", err_string);
        }
        Ok(srv_results) => {
            println!("Successful SRV lookup...");
            for srv_result in &srv_results {
                println!("host: {} (port: {}), priority: {} weight: {}",
                         srv_result.host(),
                         srv_result.port(),
                         srv_result.weight(),
                         srv_result.priority());
            }
        }
    }
}

fn print_cname_result(result: Result<c_ares::CNameResult, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("CNAME lookup failed with error '{}'", err_string);
        }
        Ok(cname_result) => {
            println!("Successful CNAME lookup...");
            println!("{}", cname_result.cname());
        }
    }
}

fn print_mx_results(result: Result<c_ares::MXResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("MX lookup failed with error '{}'", err_string);
        }
        Ok(mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in &mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: Result<c_ares::NAPTRResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("NAPTR lookup failed with error '{}'", err_string);
        }
        Ok(naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in &naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

fn print_ns_results(result: Result<c_ares::NSResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("NS lookup failed with error '{}'", err_string);
        }
        Ok(ns_results) => {
            println!("Successful NS lookup...");
            for ns_result in &ns_results {
                println!("{}", ns_result.name_server());
            }
        }
    }
}

fn print_ptr_results(result: Result<c_ares::PTRResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("PTR lookup failed with error '{}'", err_string);
        }
        Ok(ptr_results) => {
            println!("Successful PTR lookup...");
            for ptr_result in &ptr_results {
                println!("{}", ptr_result.cname());
            }
        }
    }
}

fn print_txt_results(result: Result<c_ares::TXTResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("TXT lookup failed with error '{}'", err_string);
        }
        Ok(txt_results) => {
            println!("Successful TXT lookup...");
            for txt_result in &txt_results {
                println!("{}", txt_result.text());
            }
        }
    }
}

fn print_soa_result(result: Result<c_ares::SOAResult, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("SOA lookup failed with error '{}'", err_string);
        }
        Ok(soa_result) => {
            println!("Successful SOA lookup...");
            println!("Name server: {}", soa_result.name_server());
            println!("Hostmaster: {}", soa_result.hostmaster());
            println!("Serial: {}", soa_result.serial());
            println!("Retry: {}", soa_result.retry());
            println!("Expire: {}", soa_result.expire());
            println!("Min TTL: {}", soa_result.min_ttl());
        }
    }
}

fn print_host_results(result: Result<c_ares::HostResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Host lookup failed with error '{}'", err_string);
        }
        Ok(host_results) => {
            println!("Successful host lookup...");
            println!("Hostname: {}", host_results.hostname());
            for alias in host_results.aliases() {
                println!("Alias: {}", alias.alias());
            }
            for address in host_results.addresses() {
                match address.ip_address() {
                    c_ares::IpAddr::V4(v4) => println!("IPv4: {:}", v4),
                    c_ares::IpAddr::V6(v6) => println!("IPv6: {:}", v6),
                }
            }
        }
    }
}

fn print_name_info_result(
    result: Result<c_ares::NameInfoResult,
    c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Name info lookup failed with error '{}'", err_string);
        }
        Ok(name_info_result) => {
            println!("Successful name info lookup...");
            println!("Node: {}", name_info_result.node().unwrap_or("<None>"));
            println!(
                "Service: {}",
                name_info_result.service().unwrap_or("<None>"));
        }
    }
}

fn main() {
    // Create an event loop, and a c_ares::Channel.
    let mut event_loop = mio::EventLoop::new()
        .ok()
        .expect("failed to create event loop");
    let event_loop_channel = event_loop.channel();
    let event_loop_channel_clone = event_loop_channel.clone();
    let sock_callback = move |fd: io::RawFd, readable: bool, writable: bool| {
        event_loop_channel_clone
            .send(
                CAresHandlerMessage::RegisterInterest(fd, readable, writable))
            .ok()
            .expect("Failed to send RegisterInterest");
    };
    let mut options = c_ares::Options::new();
    options
        .set_socket_state_callback(sock_callback)
        .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .ok()
        .expect("Failed to create channel");

    // Set up some queries.
    let (results_tx, results_rx) = mpsc::channel();
    let tx = results_tx.clone();
    ares_channel.query_a("apple.com", move |results| {
        print_a_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_aaaa("google.com", move |results| {
        print_aaaa_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_srv("_xmpp-server._tcp.gmail.com", move |result| {
        print_srv_results(result);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_cname("dimbleby.github.io", move |result| {
        print_cname_result(result);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_mx("gmail.com", move |results| {
        print_mx_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_naptr(
        "4.3.2.1.5.5.5.0.0.8.1.e164.arpa.",
        move |results| {
            print_naptr_results(results);
            tx.send(()).unwrap()
        }
    );

    let tx = results_tx.clone();
    ares_channel.query_ns("google.com", move |results| {
        print_ns_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_ptr("14.210.58.216.in-addr.arpa", move |results| {
        print_ptr_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_txt("google.com", move |results| {
        print_txt_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_soa("google.com", move |results| {
        print_soa_result(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.get_host_by_name(
        "google.com",
        c_ares::AddressFamily::INET,
        move |results| {
            print_host_results(results);
            tx.send(()).unwrap()
        }
    );

    let tx = results_tx.clone();
    let ipv4 = c_ares::IpAddr::V4(Ipv4Addr::new(216, 58, 208, 78));
    ares_channel.get_host_by_address(&ipv4, move |results| {
        print_host_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    let ipv6 = c_ares::IpAddr::V6(
        Ipv6Addr::new(0x2a00, 0x1450, 0x4009, 0x80a, 0, 0, 0, 0x200e));
    ares_channel.get_host_by_address(&ipv6, move |results| {
        print_host_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    let ipv4 = Ipv4Addr::new(216, 58, 210, 14);
    let sock = SocketAddr::V4(SocketAddrV4::new(ipv4, 80));
    ares_channel.get_name_info(
        &sock,
        c_ares::ni_flags::LOOKUPHOST | c_ares::ni_flags::LOOKUPSERVICE,
        move |result| {
            print_name_info_result(result);
            tx.send(()).unwrap()
        }
    );

    // Set the first instance of the recurring timer on the event loop.
    event_loop.timeout_ms((), 500).unwrap();

    // Kick off the event loop.
    let mut event_handler = CAresEventHandler::new(ares_channel);
    let handle = thread::spawn(move || {
        event_loop
            .run(&mut event_handler)
            .ok()
            .expect("failed to run event loop")
    });

    // Wait for results to roll in.
    for _ in 0..14 {
        results_rx.recv().unwrap();
    }

    // Shut down the event loop and wait for it to finish.
    event_loop_channel
        .send(CAresHandlerMessage::ShutDown)
        .ok()
        .expect("failed to shut down event loop");
    handle.join().unwrap();
}
<commit_msg>Avoid duplication in examples<commit_after>// This example uses the callback mechanism to find out which file descriptors
// c-ares cares about.  This is a good fit for an event loop; here we use mio.
extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::mem;
use std::net::{
    Ipv4Addr,
    Ipv6Addr,
    SocketAddr,
    SocketAddrV4,
};
use std::os::unix::io;
use std::sync::mpsc;
use std::thread;

// Messages for the event loop.
enum CAresHandlerMessage {
    // 'Notify me when this file descriptor becomes readable, or writable'
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(io::RawFd, bool, bool),

    // 'Shut down'.
    ShutDown,
}

struct CAresEventHandler {
    // Since the event handler owns the Channel, it's tricky to submit further
    // queries once the event loop is running.  If you want to do that,
    // either:
    //
    // -  share the Channel by using an Arc<Mutex<c_ares::Channel>>, OR
    // -  send requests to the event handler as messages, and have it make the
    //    queries
    ares_channel: c_ares::Channel,
    tracked_fds: HashSet<io::RawFd>,
}

impl mio::Handler for CAresEventHandler {
    type Timeout = ();
    type Message = CAresHandlerMessage;

    // mio notifies us that a file descriptor is readable or writable, so we
    // tell the Channel the same.
    fn ready(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        events: mio::EventSet) {
        let fd = token.as_usize() as io::RawFd;
        let read_fd = if events.is_readable() {
            fd
        } else {
            c_ares::INVALID_FD
        };
        let write_fd = if events.is_writable() {
            fd
        } else {
            c_ares::INVALID_FD
        };
        self.ares_channel.process_fd(read_fd, write_fd);
    }

    // Process received messages.  Either:
    // - we're asked to register interest (or non-interest) in a file
    // descriptor
    // - we're asked to shut down the event loop.
    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, readable, writable) => {
                let io = mio::Io::from(fd);
                if !readable && !writable {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&io)
                        .ok()
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::EventSet::none();
                    if readable {
                        interest = interest | mio::EventSet::readable();
                    }
                    if writable {
                        interest = interest | mio::EventSet::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let register_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    } else {
                        event_loop
                            .register_opt(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    };
                    register_result.ok().expect("failed to register interest");
                }

                // Don't accidentally close the file descriptor by dropping io!
                mem::forget(io);
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }

    // We run a recurring timer so that we can spot non-responsive servers.
    //
    // In that case we won't get a callback saying that anything is happening
    // on any file descriptor, but nevertheless need to give the Channel an
    // opportunity to notice that it has timed-out requests pending.
    fn timeout(
        &mut self,
        event_loop: &mut mio::EventLoop<CAresEventHandler>,
        _timeout: Self::Timeout) {
        self.ares_channel.process_fd(c_ares::INVALID_FD, c_ares::INVALID_FD);
        event_loop.timeout_ms((), 500).unwrap();
    }
}

impl CAresEventHandler {
    fn new(ares_channel: c_ares::Channel) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

fn print_cname_result(result: Result<c_ares::CNameResult, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("CNAME lookup failed with error '{}'", err_string);
        }
        Ok(cname_result) => {
            println!("Successful CNAME lookup...");
            println!("{}", cname_result.cname());
        }
    }
}

fn print_mx_results(result: Result<c_ares::MXResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("MX lookup failed with error '{}'", err_string);
        }
        Ok(mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in &mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: Result<c_ares::NAPTRResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("NAPTR lookup failed with error '{}'", err_string);
        }
        Ok(naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in &naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

fn print_ns_results(result: Result<c_ares::NSResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("NS lookup failed with error '{}'", err_string);
        }
        Ok(ns_results) => {
            println!("Successful NS lookup...");
            for ns_result in &ns_results {
                println!("{}", ns_result.name_server());
            }
        }
    }
}

fn print_ptr_results(result: Result<c_ares::PTRResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("PTR lookup failed with error '{}'", err_string);
        }
        Ok(ptr_results) => {
            println!("Successful PTR lookup...");
            for ptr_result in &ptr_results {
                println!("{}", ptr_result.cname());
            }
        }
    }
}

fn print_txt_results(result: Result<c_ares::TXTResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("TXT lookup failed with error '{}'", err_string);
        }
        Ok(txt_results) => {
            println!("Successful TXT lookup...");
            for txt_result in &txt_results {
                println!("{}", txt_result.text());
            }
        }
    }
}

fn print_soa_result(result: Result<c_ares::SOAResult, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("SOA lookup failed with error '{}'", err_string);
        }
        Ok(soa_result) => {
            println!("Successful SOA lookup...");
            println!("Name server: {}", soa_result.name_server());
            println!("Hostmaster: {}", soa_result.hostmaster());
            println!("Serial: {}", soa_result.serial());
            println!("Retry: {}", soa_result.retry());
            println!("Expire: {}", soa_result.expire());
            println!("Min TTL: {}", soa_result.min_ttl());
        }
    }
}

fn print_host_results(result: Result<c_ares::HostResults, c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Host lookup failed with error '{}'", err_string);
        }
        Ok(host_results) => {
            println!("Successful host lookup...");
            println!("Hostname: {}", host_results.hostname());
            for alias in host_results.aliases() {
                println!("Alias: {}", alias.alias());
            }
            for address in host_results.addresses() {
                match address.ip_address() {
                    c_ares::IpAddr::V4(v4) => println!("IPv4: {:}", v4),
                    c_ares::IpAddr::V6(v6) => println!("IPv6: {:}", v6),
                }
            }
        }
    }
}

fn print_name_info_result(
    result: Result<c_ares::NameInfoResult,
    c_ares::AresError>) {
    println!("");
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Name info lookup failed with error '{}'", err_string);
        }
        Ok(name_info_result) => {
            println!("Successful name info lookup...");
            println!("Node: {}", name_info_result.node().unwrap_or("<None>"));
            println!(
                "Service: {}",
                name_info_result.service().unwrap_or("<None>"));
        }
    }
}

fn main() {
    // Create an event loop, and a c_ares::Channel.
    let mut event_loop = mio::EventLoop::new()
        .ok()
        .expect("failed to create event loop");
    let event_loop_channel = event_loop.channel();
    let event_loop_channel_clone = event_loop_channel.clone();
    let sock_callback = move |fd: io::RawFd, readable: bool, writable: bool| {
        event_loop_channel_clone
            .send(
                CAresHandlerMessage::RegisterInterest(fd, readable, writable))
            .ok()
            .expect("Failed to send RegisterInterest");
    };
    let mut options = c_ares::Options::new();
    options
        .set_socket_state_callback(sock_callback)
        .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .ok()
        .expect("Failed to create channel");

    // Set up some queries.
    let (results_tx, results_rx) = mpsc::channel();
    let tx = results_tx.clone();
    ares_channel.query_cname("dimbleby.github.io", move |result| {
        print_cname_result(result);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_mx("gmail.com", move |results| {
        print_mx_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_naptr(
        "4.3.2.1.5.5.5.0.0.8.1.e164.arpa.",
        move |results| {
            print_naptr_results(results);
            tx.send(()).unwrap()
        }
    );

    let tx = results_tx.clone();
    ares_channel.query_ns("google.com", move |results| {
        print_ns_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_ptr("14.210.58.216.in-addr.arpa", move |results| {
        print_ptr_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_txt("google.com", move |results| {
        print_txt_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_soa("google.com", move |results| {
        print_soa_result(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.get_host_by_name(
        "google.com",
        c_ares::AddressFamily::INET,
        move |results| {
            print_host_results(results);
            tx.send(()).unwrap()
        }
    );

    let tx = results_tx.clone();
    let ipv4 = c_ares::IpAddr::V4(Ipv4Addr::new(216, 58, 208, 78));
    ares_channel.get_host_by_address(&ipv4, move |results| {
        print_host_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    let ipv6 = c_ares::IpAddr::V6(
        Ipv6Addr::new(0x2a00, 0x1450, 0x4009, 0x80a, 0, 0, 0, 0x200e));
    ares_channel.get_host_by_address(&ipv6, move |results| {
        print_host_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    let ipv4 = Ipv4Addr::new(216, 58, 210, 14);
    let sock = SocketAddr::V4(SocketAddrV4::new(ipv4, 80));
    ares_channel.get_name_info(
        &sock,
        c_ares::ni_flags::LOOKUPHOST | c_ares::ni_flags::LOOKUPSERVICE,
        move |result| {
            print_name_info_result(result);
            tx.send(()).unwrap()
        }
    );

    // Set the first instance of the recurring timer on the event loop.
    event_loop.timeout_ms((), 500).unwrap();

    // Kick off the event loop.
    let mut event_handler = CAresEventHandler::new(ares_channel);
    let handle = thread::spawn(move || {
        event_loop
            .run(&mut event_handler)
            .ok()
            .expect("failed to run event loop")
    });

    // Wait for results to roll in.
    for _ in 0..11 {
        results_rx.recv().unwrap();
    }

    // Shut down the event loop and wait for it to finish.
    event_loop_channel
        .send(CAresHandlerMessage::ShutDown)
        .ok()
        .expect("failed to shut down event loop");
    handle.join().unwrap();
}
<|endoftext|>


<commit_before>use error::*;
use translator::{Translator, BlockTranslationResult};

mod mode;
mod semantics;
mod translator;
mod x86register;

use self::mode::Mode;

/// The X86 translator.
#[derive(Clone, Debug)]
pub struct X86;

impl X86 {
    pub fn new() -> X86 {
        X86
    }
}

impl Translator for X86 {
    fn translate_block(&self, bytes: &[u8], address: u64)
        -> Result<BlockTranslationResult> {

        translator::translate_block(Mode::X86, bytes, address)
    }
}

/// The Amd64 translator.
#[derive(Clone, Debug)]
pub struct Amd64;

impl Amd64 {
    pub fn new() -> Amd64 {
        Amd64
    }
}

impl Translator for Amd64 {
    fn translate_block(&self, bytes: &[u8], address: u64)
        -> Result<BlockTranslationResult> {

        translator::translate_block(Mode::Amd64, bytes, address)
    }
}<commit_msg>Document x86 translator module.<commit_after>//! Capstone-based translator for 32/64-bit x86.

use error::*;
use translator::{Translator, BlockTranslationResult};

mod mode;
mod semantics;
mod translator;
mod x86register;

use self::mode::Mode;

/// The X86 translator.
#[derive(Clone, Debug)]
pub struct X86;

impl X86 {
    pub fn new() -> X86 {
        X86
    }
}

impl Translator for X86 {
    fn translate_block(&self, bytes: &[u8], address: u64)
        -> Result<BlockTranslationResult> {

        translator::translate_block(Mode::X86, bytes, address)
    }
}

/// The Amd64 translator.
#[derive(Clone, Debug)]
pub struct Amd64;

impl Amd64 {
    pub fn new() -> Amd64 {
        Amd64
    }
}

impl Translator for Amd64 {
    fn translate_block(&self, bytes: &[u8], address: u64)
        -> Result<BlockTranslationResult> {

        translator::translate_block(Mode::Amd64, bytes, address)
    }
}<|endoftext|>


<commit_before>use header::EntryHeader;
use content::EntryContent;
use store::StoreId;

/**
 * An Entry of the store
 *
 * Contains location, header and content part.
 */
#[derive(Debug, Clone)]
pub struct Entry {
    location: StoreId,
    header: EntryHeader,
    content: EntryContent,
}

impl Entry {

    pub fn get_location(&self) -> &StoreId {
        &self.location
    }

    pub fn get_header(&self) -> &EntryHeader {
        &self.header
    }

    pub fn get_content(&self) -> &EntryContent {
        &self.content
    }

}

<commit_msg>Add Entry mutable getters<commit_after>use header::EntryHeader;
use content::EntryContent;
use store::StoreId;

/**
 * An Entry of the store
 *
 * Contains location, header and content part.
 */
#[derive(Debug, Clone)]
pub struct Entry {
    location: StoreId,
    header: EntryHeader,
    content: EntryContent,
}

impl Entry {

    pub fn get_location(&self) -> &StoreId {
        &self.location
    }

    pub fn get_header(&self) -> &EntryHeader {
        &self.header
    }

    pub fn get_header_mut(&mut self) -> &mut EntryHeader {
        &mut self.header
    }

    pub fn get_content(&self) -> &EntryContent {
        &self.content
    }

    pub fn get_content_mut(&mut self) -> &mut EntryContent {
        &mut self.content
    }

}

<|endoftext|>


<commit_before>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

extern mod extra;

use extra::treemap::{TreeMap};
use std::c_str;
use std::libc::{c_char, c_int, c_uchar, c_void};
use std::option::{Option};
use std::ptr;
use std::vec;

pub type options = c_int;
pub type study_options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

pub static PCRE_STUDY_JIT_COMPILE: study_options = 0x0001;
pub static PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE: study_options = 0x0002;
pub static PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE: study_options = 0x0004;
pub static PCRE_STUDY_EXTRA_NEEDED: study_options = 0x0008;

mod detail;

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    priv capture_count_: c_int

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv partial_ovector: ~[c_int],

    priv string_count_: c_int

}

pub struct MatchIterator<'self> {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    priv capture_count: c_int,

    priv subject: &'self str,

    priv offset: c_int,

    priv options: options,

    priv ovector: ~[c_int]

}

impl Pcre {
    pub fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    pub fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            unsafe {
                // Use the default character tables.
                let tableptr: *c_uchar = ptr::null();
                let code = detail::pcre_compile(pattern_c_str, options, tableptr) as *detail::pcre;
                assert!(ptr::is_not_null(code));
                // Take a reference.
                detail::pcre_refcount(code as *mut detail::pcre, 1);

                let extra: *detail::pcre_extra = ptr::null();

                let mut capture_count: c_int = 0;
                detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

                Pcre {
                    code: code,
                    extra: extra,
                    capture_count_: capture_count
                }
            }
        }
    }

    pub fn capture_count(&self) -> uint {
        self.capture_count_ as uint
    }

    pub fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    pub fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    pub fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count_ + 1) * 3;
        let mut ovector: ~[c_int] = vec::from_elem(ovecsize as uint, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                let rc = detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc >= 0 {
                    Some(Match {
                        subject: subject,
                        partial_ovector: ovector.slice_to(((self.capture_count_ + 1) * 2) as uint).to_owned(),
                        string_count_: rc
                    })
                } else {
                    None
                }
            }
        }
    }

    pub fn match_iter<'a>(&self, subject: &'a str) -> MatchIterator<'a> {
        self.match_iter_with_options(subject, 0)
    }

    pub fn match_iter_with_options<'a>(&self, subject: &'a str, options: options) -> MatchIterator<'a> {
        unsafe {
            let ovecsize = (self.capture_count_ + 1) * 3;
            MatchIterator {
                code: { detail::pcre_refcount(self.code as *mut detail::pcre, 1); self.code },
                extra: self.extra,
                capture_count: self.capture_count_,
                subject: subject,
                offset: 0,
                options: options,
                ovector: vec::from_elem(ovecsize as uint, 0 as c_int)
            }
        }
    }

    pub fn name_count(&self) -> uint {
        unsafe {
            let mut name_count: c_int = 0;
            detail::pcre_fullinfo(self.code, self.extra, detail::PCRE_INFO_NAMECOUNT, &mut name_count as *mut c_int as *mut c_void);
            name_count as uint
        }
    }

    pub fn name_table(&self) -> TreeMap<~str, ~[uint]> {
        unsafe {
            let name_count = self.name_count();
            let mut tabptr: *c_uchar = ptr::null();
            detail::pcre_fullinfo(self.code, self.extra, detail::PCRE_INFO_NAMETABLE, &mut tabptr as *mut *c_uchar as *mut c_void);
            let mut name_entry_size: c_int = 0;
            detail::pcre_fullinfo(self.code, self.extra, detail::PCRE_INFO_NAMEENTRYSIZE, &mut name_entry_size as *mut c_int as *mut c_void);

            let mut name_table: TreeMap<~str, ~[uint]> = TreeMap::new();

            let mut i = 0u;
            while i < name_count {
                let n: uint = (ptr::read_ptr(tabptr as *mut c_uchar) as uint << 8) | (ptr::read_ptr(ptr::offset(tabptr, 1) as *mut c_uchar) as uint);
                let name_cstring = c_str::CString::new(ptr::offset(tabptr, 2) as *c_char, false);
                let name: ~str = name_cstring.as_str().unwrap().to_owned();
                // TODO Avoid the double lookup.
                // https://github.com/mozilla/rust/issues/9068
                if !name_table.contains_key(&name) {
                    name_table.insert(name, ~[n]);
                } else {
                    name_table.find_mut(&name).unwrap().push(n);
                }
                tabptr = ptr::offset(tabptr, name_entry_size as int);
                i += 1;
            }

            name_table
        }
    }

    pub fn study(&mut self) -> bool {
        self.study_with_options(0)
    }

    pub fn study_with_options(&mut self, options: study_options) -> bool {
        unsafe {
            // If something else has a reference to `code` then it probably has a pointer to
            // the current study data (if any). Thus, we shouldn't free the current study data
            // in that case.
            if detail::pcre_refcount(self.code as *mut detail::pcre, 0) != 1 {
                false
            } else {
                // Free any current study data.
                detail::pcre_free_study(self.extra as *mut detail::pcre_extra);
                self.extra = ptr::null();

                let extra = detail::pcre_study(self.code, options) as *detail::pcre_extra;
                self.extra = extra;
                ptr::is_not_null(extra)
            }
        }
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        unsafe {
            if detail::pcre_refcount(self.code as *mut detail::pcre, -1) == 0 {
                detail::pcre_free_study(self.extra as *mut detail::pcre_extra);
                detail::pcre_free(self.code as *mut detail::pcre as *mut c_void);
            }
            self.extra = ptr::null();
            self.code = ptr::null();
        }
    }
}

impl<'self> Match<'self> {
    pub fn group_start(&self, n: uint) -> uint {
        self.partial_ovector[(n * 2) as uint] as uint
    }

    pub fn group_end(&self, n: uint) -> uint {
        self.partial_ovector[(n * 2 + 1) as uint] as uint
    }

    pub fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.partial_ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    pub fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.partial_ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

    pub fn string_count(&self) -> uint {
        self.string_count_ as uint
    }
}

#[unsafe_destructor]
impl<'self> Drop for MatchIterator<'self> {
    fn drop(&mut self) {
        unsafe {
            if detail::pcre_refcount(self.code as *mut detail::pcre, -1) == 0 {
                detail::pcre_free_study(self.extra as *mut detail::pcre_extra);
                detail::pcre_free(self.code as *mut detail::pcre as *mut c_void);
            }
            self.extra = ptr::null();
            self.code = ptr::null();
        }
    }
}

impl<'self> Iterator<Match<'self>> for MatchIterator<'self> {
    fn next(&mut self) -> Option<Match<'self>> {
        unsafe {
            do self.subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'self>> {
                let rc = detail::pcre_exec(self.code, self.extra, subject_c_str, self.subject.len() as c_int, self.offset, self.options, vec::raw::to_mut_ptr(self.ovector), self.ovector.len() as c_int);
                if rc >= 0 {
                    // Update the iterator state.
                    self.offset = self.ovector[1];

                    Some(Match {
                        subject: self.subject,
                        partial_ovector: self.ovector.slice_to(((self.capture_count + 1) * 2) as uint).to_owned(),
                        string_count_: rc
                    })
                } else {
                    None
                }
            }
        }
    }
}

pub fn pcre_version() -> ~str {
    detail::pcre_version()
}
<commit_msg>Optimize `MatchIterator`<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

extern mod extra;

use extra::treemap::{TreeMap};
use std::c_str;
use std::libc::{c_char, c_int, c_uchar, c_void};
use std::option::{Option};
use std::ptr;
use std::vec;

pub type options = c_int;
pub type study_options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

pub static PCRE_STUDY_JIT_COMPILE: study_options = 0x0001;
pub static PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE: study_options = 0x0002;
pub static PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE: study_options = 0x0004;
pub static PCRE_STUDY_EXTRA_NEEDED: study_options = 0x0008;

mod detail;

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    priv capture_count_: c_int

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv partial_ovector: ~[c_int],

    priv string_count_: c_int

}

pub struct MatchIterator<'self> {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    priv capture_count: c_int,

    priv subject: &'self str,

    /// The subject string as a `CString`. In MatchIterator's next() method, this is re-used
    /// each time so that only one C-string copy of the subject string needs to be allocated.
    priv subject_cstring: c_str::CString,

    priv offset: c_int,

    priv options: options,

    priv ovector: ~[c_int]

}

impl Pcre {
    pub fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    pub fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            unsafe {
                // Use the default character tables.
                let tableptr: *c_uchar = ptr::null();
                let code = detail::pcre_compile(pattern_c_str, options, tableptr) as *detail::pcre;
                assert!(ptr::is_not_null(code));
                // Take a reference.
                detail::pcre_refcount(code as *mut detail::pcre, 1);

                let extra: *detail::pcre_extra = ptr::null();

                let mut capture_count: c_int = 0;
                detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

                Pcre {
                    code: code,
                    extra: extra,
                    capture_count_: capture_count
                }
            }
        }
    }

    pub fn capture_count(&self) -> uint {
        self.capture_count_ as uint
    }

    pub fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    pub fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    pub fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count_ + 1) * 3;
        let mut ovector: ~[c_int] = vec::from_elem(ovecsize as uint, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                let rc = detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc >= 0 {
                    Some(Match {
                        subject: subject,
                        partial_ovector: ovector.slice_to(((self.capture_count_ + 1) * 2) as uint).to_owned(),
                        string_count_: rc
                    })
                } else {
                    None
                }
            }
        }
    }

    pub fn match_iter<'a>(&self, subject: &'a str) -> MatchIterator<'a> {
        self.match_iter_with_options(subject, 0)
    }

    pub fn match_iter_with_options<'a>(&self, subject: &'a str, options: options) -> MatchIterator<'a> {
        unsafe {
            let ovecsize = (self.capture_count_ + 1) * 3;
            MatchIterator {
                code: { detail::pcre_refcount(self.code as *mut detail::pcre, 1); self.code },
                extra: self.extra,
                capture_count: self.capture_count_,
                subject: subject,
                subject_cstring: subject.to_c_str_unchecked(),
                offset: 0,
                options: options,
                ovector: vec::from_elem(ovecsize as uint, 0 as c_int)
            }
        }
    }

    pub fn name_count(&self) -> uint {
        unsafe {
            let mut name_count: c_int = 0;
            detail::pcre_fullinfo(self.code, self.extra, detail::PCRE_INFO_NAMECOUNT, &mut name_count as *mut c_int as *mut c_void);
            name_count as uint
        }
    }

    pub fn name_table(&self) -> TreeMap<~str, ~[uint]> {
        unsafe {
            let name_count = self.name_count();
            let mut tabptr: *c_uchar = ptr::null();
            detail::pcre_fullinfo(self.code, self.extra, detail::PCRE_INFO_NAMETABLE, &mut tabptr as *mut *c_uchar as *mut c_void);
            let mut name_entry_size: c_int = 0;
            detail::pcre_fullinfo(self.code, self.extra, detail::PCRE_INFO_NAMEENTRYSIZE, &mut name_entry_size as *mut c_int as *mut c_void);

            let mut name_table: TreeMap<~str, ~[uint]> = TreeMap::new();

            let mut i = 0u;
            while i < name_count {
                let n: uint = (ptr::read_ptr(tabptr as *mut c_uchar) as uint << 8) | (ptr::read_ptr(ptr::offset(tabptr, 1) as *mut c_uchar) as uint);
                let name_cstring = c_str::CString::new(ptr::offset(tabptr, 2) as *c_char, false);
                let name: ~str = name_cstring.as_str().unwrap().to_owned();
                // TODO Avoid the double lookup.
                // https://github.com/mozilla/rust/issues/9068
                if !name_table.contains_key(&name) {
                    name_table.insert(name, ~[n]);
                } else {
                    name_table.find_mut(&name).unwrap().push(n);
                }
                tabptr = ptr::offset(tabptr, name_entry_size as int);
                i += 1;
            }

            name_table
        }
    }

    pub fn study(&mut self) -> bool {
        self.study_with_options(0)
    }

    pub fn study_with_options(&mut self, options: study_options) -> bool {
        unsafe {
            // If something else has a reference to `code` then it probably has a pointer to
            // the current study data (if any). Thus, we shouldn't free the current study data
            // in that case.
            if detail::pcre_refcount(self.code as *mut detail::pcre, 0) != 1 {
                false
            } else {
                // Free any current study data.
                detail::pcre_free_study(self.extra as *mut detail::pcre_extra);
                self.extra = ptr::null();

                let extra = detail::pcre_study(self.code, options) as *detail::pcre_extra;
                self.extra = extra;
                ptr::is_not_null(extra)
            }
        }
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        unsafe {
            if detail::pcre_refcount(self.code as *mut detail::pcre, -1) == 0 {
                detail::pcre_free_study(self.extra as *mut detail::pcre_extra);
                detail::pcre_free(self.code as *mut detail::pcre as *mut c_void);
            }
            self.extra = ptr::null();
            self.code = ptr::null();
        }
    }
}

impl<'self> Match<'self> {
    pub fn group_start(&self, n: uint) -> uint {
        self.partial_ovector[(n * 2) as uint] as uint
    }

    pub fn group_end(&self, n: uint) -> uint {
        self.partial_ovector[(n * 2 + 1) as uint] as uint
    }

    pub fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.partial_ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    pub fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.partial_ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

    pub fn string_count(&self) -> uint {
        self.string_count_ as uint
    }
}

#[unsafe_destructor]
impl<'self> Drop for MatchIterator<'self> {
    fn drop(&mut self) {
        unsafe {
            if detail::pcre_refcount(self.code as *mut detail::pcre, -1) == 0 {
                detail::pcre_free_study(self.extra as *mut detail::pcre_extra);
                detail::pcre_free(self.code as *mut detail::pcre as *mut c_void);
            }
            self.extra = ptr::null();
            self.code = ptr::null();
        }
    }
}

impl<'self> Iterator<Match<'self>> for MatchIterator<'self> {
    fn next(&mut self) -> Option<Match<'self>> {
        unsafe {
            do self.subject_cstring.with_ref |subject_c_str| -> Option<Match<'self>> {
                let rc = detail::pcre_exec(self.code, self.extra, subject_c_str, self.subject.len() as c_int, self.offset, self.options, vec::raw::to_mut_ptr(self.ovector), self.ovector.len() as c_int);
                if rc >= 0 {
                    // Update the iterator state.
                    self.offset = self.ovector[1];

                    Some(Match {
                        subject: self.subject,
                        partial_ovector: self.ovector.slice_to(((self.capture_count + 1) * 2) as uint).to_owned(),
                        string_count_: rc
                    })
                } else {
                    None
                }
            }
        }
    }
}

pub fn pcre_version() -> ~str {
    detail::pcre_version()
}
<|endoftext|>