<commit_before>use glium;
use graphics::draw_state;

pub fn convert_draw_state(draw_state: &draw_state::DrawState)
-> glium::draw_parameters::DrawParameters<'static> {
    glium::draw_parameters::DrawParameters {
        blend: convert_blend(draw_state.blend),
        scissor: convert_scissor(draw_state.scissor),
        stencil: convert_stencil(draw_state.stencil),
        // polygon_mode: use default (Fill)
        // We don't override Graphics::line, so no need to set line_width.
        // Always draw triangles, whether they are facing clockwise or counterclockwise.
        backface_culling:
            glium::draw_parameters::BackfaceCullingMode::CullingDisabled,
        .. Default::default()
    }
}

pub fn convert_scissor(rect: Option<[u32; 4]>)
-> Option<glium::Rect> {
    rect.map(|rect| {
        // scissor: [x, y, w, h]
        glium::Rect {
            left: rect[0] as u32,
            bottom: rect[1] as u32,
            width: rect[2] as u32,
            height: rect[3] as u32,
        }
    })
}

pub fn convert_stencil(stencil: Option<draw_state::Stencil>)
-> glium::draw_parameters::Stencil {
    use graphics::draw_state::Stencil;
    use glium::{ StencilTest, StencilOperation };

    match stencil {
        None => Default::default(),
        Some(stencil) => {
            let (stencil_test,
                 stencil_test_fail_operation,
                 reference_value) = {
                match stencil {
                    Stencil::Clip(val) => {
                        (StencilTest::AlwaysFail,
                         StencilOperation::Replace,
                         val)
                    }
                    Stencil::Inside(val) => {
                        (StencilTest::IfEqual { mask: 255 },
                         StencilOperation::Keep,
                         val)
                    }
                    Stencil::Outside(val) => {
                        (StencilTest::IfNotEqual { mask: 255 },
                         StencilOperation::Keep,
                         val)
                    }
                }
            };

            // Use triangles for stencil operations, whether they are
            // facing clockwise or counterclockwise.
            glium::draw_parameters::Stencil {
                // Clockwise side.
                test_clockwise: stencil_test,
                reference_value_clockwise: reference_value as i32,
                write_mask_clockwise: 255,
                fail_operation_clockwise: stencil_test_fail_operation,
                pass_depth_fail_operation_clockwise:
                    StencilOperation::Keep,
                depth_pass_operation_clockwise: StencilOperation::Keep,
                // Counter clockwise side.
                test_counter_clockwise: stencil_test,
                reference_value_counter_clockwise: reference_value as i32,
                write_mask_counter_clockwise: 255,
                fail_operation_counter_clockwise:
                    stencil_test_fail_operation,
                pass_depth_fail_operation_counter_clockwise:
                    StencilOperation::Keep,
                depth_pass_operation_counter_clockwise:
                    StencilOperation::Keep,
            }
        }
    }
}

pub fn convert_blend(blend: Option<draw_state::Blend>) -> glium::Blend {
    use graphics::draw_state::Blend;
    use glium::{ BlendingFunction, LinearBlendingFactor };

    match blend {
        None => Default::default(),
        Some(blend) => {
            match blend {
                Blend::Alpha => {
                    glium::Blend {
                        color: BlendingFunction::Addition {
                            source: LinearBlendingFactor::SourceAlpha,
                            destination: LinearBlendingFactor::OneMinusSourceAlpha
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::One,
                            destination: LinearBlendingFactor::One
                        },
                        constant_value: (0.0, 0.0, 0.0, 0.0)
                    }
                }
                Blend::Add => {
                    glium::Blend {
                        color: BlendingFunction::Addition {
                            source: LinearBlendingFactor::One,
                            destination: LinearBlendingFactor::One
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::One,
                            destination: LinearBlendingFactor::One
                        },
                        constant_value: (0.0, 0.0, 0.0, 0.0)
                    }
                }
                Blend::Multiply => {
                    glium::Blend {
                        color: BlendingFunction::Addition {
                            source: LinearBlendingFactor::DestinationColor,
                            destination: LinearBlendingFactor::Zero
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::DestinationAlpha,
                            destination: LinearBlendingFactor::Zero
                        },
                        constant_value: (0.0, 0.0, 0.0, 0.0)
                    }
                }
                Blend::Invert => {
                    glium::Blend {
                        color: BlendingFunction::Subtraction {
                            source: LinearBlendingFactor::ConstantColor,
                            destination: LinearBlendingFactor::SourceColor
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::Zero,
                            destination: LinearBlendingFactor::One
                        },
                        constant_value: (1.0, 1.0, 1.0, 1.0)
                    }
                }
            }
        }
    }
}
<commit_msg>add comment about constructing alpha blending<commit_after>use glium;
use graphics::draw_state;

pub fn convert_draw_state(draw_state: &draw_state::DrawState)
-> glium::draw_parameters::DrawParameters<'static> {
    glium::draw_parameters::DrawParameters {
        blend: convert_blend(draw_state.blend),
        scissor: convert_scissor(draw_state.scissor),
        stencil: convert_stencil(draw_state.stencil),
        // polygon_mode: use default (Fill)
        // We don't override Graphics::line, so no need to set line_width.
        // Always draw triangles, whether they are facing clockwise or counterclockwise.
        backface_culling:
            glium::draw_parameters::BackfaceCullingMode::CullingDisabled,
        .. Default::default()
    }
}

pub fn convert_scissor(rect: Option<[u32; 4]>)
-> Option<glium::Rect> {
    rect.map(|rect| {
        // scissor: [x, y, w, h]
        glium::Rect {
            left: rect[0] as u32,
            bottom: rect[1] as u32,
            width: rect[2] as u32,
            height: rect[3] as u32,
        }
    })
}

pub fn convert_stencil(stencil: Option<draw_state::Stencil>)
-> glium::draw_parameters::Stencil {
    use graphics::draw_state::Stencil;
    use glium::{ StencilTest, StencilOperation };

    match stencil {
        None => Default::default(),
        Some(stencil) => {
            let (stencil_test,
                 stencil_test_fail_operation,
                 reference_value) = {
                match stencil {
                    Stencil::Clip(val) => {
                        (StencilTest::AlwaysFail,
                         StencilOperation::Replace,
                         val)
                    }
                    Stencil::Inside(val) => {
                        (StencilTest::IfEqual { mask: 255 },
                         StencilOperation::Keep,
                         val)
                    }
                    Stencil::Outside(val) => {
                        (StencilTest::IfNotEqual { mask: 255 },
                         StencilOperation::Keep,
                         val)
                    }
                }
            };

            // Use triangles for stencil operations, whether they are
            // facing clockwise or counterclockwise.
            glium::draw_parameters::Stencil {
                // Clockwise side.
                test_clockwise: stencil_test,
                reference_value_clockwise: reference_value as i32,
                write_mask_clockwise: 255,
                fail_operation_clockwise: stencil_test_fail_operation,
                pass_depth_fail_operation_clockwise:
                    StencilOperation::Keep,
                depth_pass_operation_clockwise: StencilOperation::Keep,
                // Counter clockwise side.
                test_counter_clockwise: stencil_test,
                reference_value_counter_clockwise: reference_value as i32,
                write_mask_counter_clockwise: 255,
                fail_operation_counter_clockwise:
                    stencil_test_fail_operation,
                pass_depth_fail_operation_counter_clockwise:
                    StencilOperation::Keep,
                depth_pass_operation_counter_clockwise:
                    StencilOperation::Keep,
            }
        }
    }
}

pub fn convert_blend(blend: Option<draw_state::Blend>) -> glium::Blend {
    use graphics::draw_state::Blend;
    use glium::{ BlendingFunction, LinearBlendingFactor };

    match blend {
        None => Default::default(),
        Some(blend) => {
            match blend {
                // What we need is different from glium::Blend::alpha_blending(),
                // so we have to construct this manually.
                Blend::Alpha => {
                    glium::Blend {
                        color: BlendingFunction::Addition {
                            source: LinearBlendingFactor::SourceAlpha,
                            destination: LinearBlendingFactor::OneMinusSourceAlpha
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::One,
                            destination: LinearBlendingFactor::One
                        },
                        constant_value: (0.0, 0.0, 0.0, 0.0)
                    }
                }
                Blend::Add => {
                    glium::Blend {
                        color: BlendingFunction::Addition {
                            source: LinearBlendingFactor::One,
                            destination: LinearBlendingFactor::One
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::One,
                            destination: LinearBlendingFactor::One
                        },
                        constant_value: (0.0, 0.0, 0.0, 0.0)
                    }
                }
                Blend::Multiply => {
                    glium::Blend {
                        color: BlendingFunction::Addition {
                            source: LinearBlendingFactor::DestinationColor,
                            destination: LinearBlendingFactor::Zero
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::DestinationAlpha,
                            destination: LinearBlendingFactor::Zero
                        },
                        constant_value: (0.0, 0.0, 0.0, 0.0)
                    }
                }
                Blend::Invert => {
                    glium::Blend {
                        color: BlendingFunction::Subtraction {
                            source: LinearBlendingFactor::ConstantColor,
                            destination: LinearBlendingFactor::SourceColor
                        },
                        alpha: BlendingFunction::Addition {
                            source: LinearBlendingFactor::Zero,
                            destination: LinearBlendingFactor::One
                        },
                        constant_value: (1.0, 1.0, 1.0, 1.0)
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "
Use this for catching various errors that
can happen when using V1Kpdb.
"]
pub enum V1KpdbError {
    /// Couldn't open the database or file is to
    /// small.
    FileErr,
    /// Something went wrong while the database is
    /// readed in
    ReadErr,
    /// The file signature in the header is wrong
    SignatureErr,
    /// Not supported encryption used
    EncFlagErr,
    /// Wrong database version
    VersionErr,
    /// Some error in decryption
    DecryptErr,
    /// Hash of decrypted content is wrong.
    /// Probably the wrong password and/or keyfile
    /// was used
    HashErr,
    /// Some error in parsing
    ConvertErr,
    /// Some error in parsing. Probably corrupted database
    OffsetErr,
    /// Group tree is corrupted
    TreeErr,
}
<commit_msg>make error handling more convinient<commit_after>use std::fmt;
use std::error;

pub use self::V1KpdbError::*;

#[doc = "
Use this for catching various errors that
can happen when using V1Kpdb.
"]
#[derive(Show, Clone, PartialEq, Eq)]
pub enum V1KpdbError {
    /// E.g. Couldn't open a file or file is to
    /// small.
    FileErr,
    /// Something went wrong while the database is
    /// readed in
    ReadErr,
    /// The file signature in the header is wrong
    SignatureErr,
    /// Not supported encryption used
    EncFlagErr,
    /// Wrong database version
    VersionErr,
    /// Some error in decryption
    DecryptErr,
    /// Hash of decrypted content is wrong.
    /// Probably the wrong password and/or keyfile
    /// was used
    HashErr,
    /// Some error in parsing
    ConvertErr,
    /// Some error in parsing. Probably corrupted database
    OffsetErr,
    /// Group tree is corrupted
    TreeErr,
}

impl fmt::Display for V1KpdbError {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt.write_str(error::Error::description(self))
     }
}

impl error::Error for V1KpdbError {
    fn description(&self) -> &str {
        match *self {
            FileErr => "Couldn't open file or database is too small",
            ReadErr => "Couldn't read file",
            SignatureErr => "File signature in header is wrong",
            EncFlagErr => "Encryption algorithm not supported",
            VersionErr => "Wrong database version",
            DecryptErr => "Something went wrong during decryption",
            HashErr => "Content's hash is wrong, probably wrong password",
            ConvertErr => "Some error while parsing the database",
            OffsetErr => "Some error while parsing the database. Probably a corrupted file",
            TreeErr => "Group tree is corrupted",
        }
    }
}
<|endoftext|>


<commit_before>use bson::{Bson, Document};
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::wire_protocol::flags::{OpInsertFlags, OpQueryFlags, OpUpdateFlags};
use mongodb::wire_protocol::operations::Message;
use std::net::TcpStream;

#[test]
fn insert_single_key_doc() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_single_key_doc");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc = doc! { "foo" => 42.0 };

            let docs = vec![doc];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_single_key_doc.single_key".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_single_key_doc.single_key".to_owned();
            let res = Message::new_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}

#[test]
fn insert_multi_key_doc() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_multi_key_doc");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc = doc! {
                "foo" => 42.0,
                "bar" => "__z&"
            };

            let docs = vec![doc];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_multi_key_doc.multi_key".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_multi_key_doc.multi_key".to_owned();
            let res = Message::new_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!"),
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}

#[test]
fn insert_docs() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_docs");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc1 = doc! {
                "foo" => 42.0,
                "bar" => "__z&"
            };

            let doc2 = doc! {
                "booyah" => 23
            };

            let docs = vec![doc1, doc2];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_docs.multi_doc".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_docs.multi_doc".to_owned();
            let res = Message::new_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 2);

            match docs[0].get("foo") {
                Some(&Bson::FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!"),
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!"),
            };

            match docs[1].get("booyah") {
                Some(&Bson::I32(23)) => (),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}

#[test]
fn insert_update_then_query() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_update_then_query");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc = doc! { "foo" => 42.0 };

            let docs = vec![doc];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_update_then_query.update".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create insert message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let selector = Document::new();

            let update = doc! { "foo" => "bar" };

            let flags = OpUpdateFlags::empty();
            let name = "test-client-wire_protocol-insert_update_then_query.update".to_owned();
            let res = Message::new_update(2, name, flags, selector, update);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create update message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_update_then_query.update".to_owned();
            let res = Message::new_query(3, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create query message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("Could not read response: {}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "bar"),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}
<commit_msg>remove floating points for literals in patterns (#231)<commit_after>use bson::{Bson, Document};
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::wire_protocol::flags::{OpInsertFlags, OpQueryFlags, OpUpdateFlags};
use mongodb::wire_protocol::operations::Message;
use std::net::TcpStream;

#[test]
fn insert_single_key_doc() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_single_key_doc");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc = doc! { "foo" => 42.0 };

            let docs = vec![doc];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_single_key_doc.single_key".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_single_key_doc.single_key".to_owned();
            let res = Message::new_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::FloatingPoint(f)) if f == 42.0 => (),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}

#[test]
fn insert_multi_key_doc() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_multi_key_doc");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc = doc! {
                "foo" => 42.0,
                "bar" => "__z&"
            };

            let docs = vec![doc];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_multi_key_doc.multi_key".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_multi_key_doc.multi_key".to_owned();
            let res = Message::new_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::FloatingPoint(f)) if f == 42.0 => (),
                _ => panic!("Wrong value returned!"),
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}

#[test]
fn insert_docs() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_docs");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc1 = doc! {
                "foo" => 42.0,
                "bar" => "__z&"
            };

            let doc2 = doc! {
                "booyah" => 23
            };

            let docs = vec![doc1, doc2];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_docs.multi_doc".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_docs.multi_doc".to_owned();
            let res = Message::new_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 2);

            match docs[0].get("foo") {
                Some(&Bson::FloatingPoint(f)) if f == 42.0 => (),
                _ => panic!("Wrong value returned!"),
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!"),
            };

            match docs[1].get("booyah") {
                Some(&Bson::I32(23)) => (),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}

#[test]
fn insert_update_then_query() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("test-client-wire_protocol-insert_update_then_query");
    db.drop_database().unwrap();

    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let doc = doc! { "foo" => 42.0 };

            let docs = vec![doc];
            let flags = OpInsertFlags::empty();
            let name = "test-client-wire_protocol-insert_update_then_query.update".to_owned();
            let res = Message::new_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create insert message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let selector = Document::new();

            let update = doc! { "foo" => "bar" };

            let flags = OpUpdateFlags::empty();
            let name = "test-client-wire_protocol-insert_update_then_query.update".to_owned();
            let res = Message::new_update(2, name, flags, selector, update);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create update message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let doc = Document::new();
            let flags = OpQueryFlags::empty();
            let name = "test-client-wire_protocol-insert_update_then_query.update".to_owned();
            let res = Message::new_query(3, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create query message!"),
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s),
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("Could not read response: {}", s),
            };

            let docs = match reply {
                Message::OpReply { documents: d, .. } => d,
                _ => panic!("Invalid response read from server"),
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "bar"),
                _ => panic!("Wrong value returned!"),
            };
        }
        Err(_) => panic!("Could not connect to server"),
    }
}
<|endoftext|>


<commit_before>
use futures::future;
use futures::{
  IntoFuture,
  Future,
  Stream
};

use futures::stream;

use fred::error::{
  RedisErrorKind,
  RedisError
};
use fred::types::*;
use fred::RedisClient;
use fred::owned::RedisClientOwned;

use super::utils;

static FOOBAR: &'static str = "foobar";

pub fn should_expire_and_persist(client: RedisClient)-> Box<Future<Item=(), Error=RedisError>>{
  Box::new(client.set("foo", "bar", None, None).and_then(|(client, _)| {
    client.get("foo")
  })
  .and_then(|(client, val)| {
    let val = match val {
      Some(v) => v,
      None => panic!("Expected value for foo not found.")
    };

    assert_eq!(val.into_string().unwrap(), "bar");
    client.expire("foo",10)
  })
  .and_then(|(client, success)| {
    assert!(success);
    client.persist("foo")
  })
  .and_then(|(client, success)| {
    assert!(success);
    Ok(())
  }))
}

pub fn should_set_and_get_simple_key(client: RedisClient) -> Box<Future<Item=(), Error=RedisError>> {
  Box::new(client.set("foo", "bar", None, None).and_then(|(client, set)| {
    assert!(set);
    client.get("foo")
  })
  .and_then(|(client, val)| {
    let val = match val {
      Some(v) => v,
      None => panic!("Expected value for foo not found.")
    };

    assert_eq!(val.into_string().unwrap(), "bar");
    client.del("foo")
  })
  .and_then(|(client, count)| {
    assert_eq!(count, 1);
    client.get("foo")
  })
  .and_then(|(client, val)| {
    assert!(val.is_none());
    Ok(())
  }))
}

pub fn should_set_and_get_large_key(client: RedisClient) -> Box<Future<Item=(), Error=RedisError>> {
  let value = utils::random_string(1000000);

  Box::new(client.set(FOOBAR, value.clone(), None, None).and_then(|(client, set)| {
    assert!(set);
    client.get(FOOBAR)
  })
  .and_then(move |(client, val)| {
    let val = match val {
      Some(v) => v,
      None => panic!("Expected value for foo not found.")
    };

    assert_eq!(val.into_string().unwrap(), value);
    client.del(FOOBAR)
  })
  .and_then(|(client, count)| {
    assert_eq!(count, 1);
    client.get(FOOBAR)
  })
  .and_then(|(client, val)| {
    assert!(val.is_none());
    Ok(())
  }))
}

pub fn should_set_and_get_random_keys(client: RedisClient) -> Box<Future<Item=(), Error=RedisError>> {
  // set and get 1000 random keys

  Box::new(stream::iter_ok(0..1000).fold(client, |client, _| {
    let key = utils::random_string(32);
    let val = utils::random_string(1000);

    let get_key = key.clone();
    let del_key = key.clone();
    let get_val = val.clone();
    client.set(&key, val, None, None).and_then(move |(client, set)| {
      assert!(set);
      client.get(get_key)
    })
    .and_then(move |(client, result)| {
      let result = result.unwrap().into_string().unwrap();
      assert_eq!(result, get_val);
      client.del(del_key)
    })
    .and_then(move |(client, deleted)| {
      assert_eq!(deleted, 1);
      client.get(key)
    })
    .and_then(|(client, result)| {
      assert_eq!(result, None);
      Ok(client)
    })
  })
  .map(|_| ()))
}<commit_msg>Some reordering<commit_after>
use futures::future;
use futures::{
  IntoFuture,
  Future,
  Stream
};

use futures::stream;

use fred::error::{
  RedisErrorKind,
  RedisError
};
use fred::types::*;
use fred::RedisClient;
use fred::owned::RedisClientOwned;

use super::utils;

static FOOBAR: &'static str = "foobar";

pub fn should_set_and_get_simple_key(client: RedisClient) -> Box<Future<Item=(), Error=RedisError>> {
  Box::new(client.set("foo", "bar", None, None).and_then(|(client, set)| {
    assert!(set);
    client.get("foo")
  })
  .and_then(|(client, val)| {
    let val = match val {
      Some(v) => v,
      None => panic!("Expected value for foo not found.")
    };

    assert_eq!(val.into_string().unwrap(), "bar");
    client.del("foo")
  })
  .and_then(|(client, count)| {
    assert_eq!(count, 1);
    client.get("foo")
  })
  .and_then(|(client, val)| {
    assert!(val.is_none());
    Ok(())
  }))
}

pub fn should_set_and_get_large_key(client: RedisClient) -> Box<Future<Item=(), Error=RedisError>> {
  let value = utils::random_string(1000000);

  Box::new(client.set(FOOBAR, value.clone(), None, None).and_then(|(client, set)| {
    assert!(set);
    client.get(FOOBAR)
  })
  .and_then(move |(client, val)| {
    let val = match val {
      Some(v) => v,
      None => panic!("Expected value for foo not found.")
    };

    assert_eq!(val.into_string().unwrap(), value);
    client.del(FOOBAR)
  })
  .and_then(|(client, count)| {
    assert_eq!(count, 1);
    client.get(FOOBAR)
  })
  .and_then(|(client, val)| {
    assert!(val.is_none());
    Ok(())
  }))
}

pub fn should_set_and_get_random_keys(client: RedisClient) -> Box<Future<Item=(), Error=RedisError>> {
  // set and get 1000 random keys

  Box::new(stream::iter_ok(0..1000).fold(client, |client, _| {
    let key = utils::random_string(32);
    let val = utils::random_string(1000);

    let get_key = key.clone();
    let del_key = key.clone();
    let get_val = val.clone();
    client.set(&key, val, None, None).and_then(move |(client, set)| {
      assert!(set);
      client.get(get_key)
    })
    .and_then(move |(client, result)| {
      let result = result.unwrap().into_string().unwrap();
      assert_eq!(result, get_val);
      client.del(del_key)
    })
    .and_then(move |(client, deleted)| {
      assert_eq!(deleted, 1);
      client.get(key)
    })
    .and_then(|(client, result)| {
      assert_eq!(result, None);
      Ok(client)
    })
  })
  .map(|_| ()))
}

pub fn should_expire_and_persist(client: RedisClient)-> Box<Future<Item=(), Error=RedisError>>{
  Box::new(client.set("foo", "bar", None, None).and_then(|(client, _)| {
    client.get("foo")
  })
  .and_then(|(client, val)| {
    let val = match val {
      Some(v) => v,
      None => panic!("Expected value for foo not found.")
    };

    assert_eq!(val.into_string().unwrap(), "bar");
    client.expire("foo",10)
  })
  .and_then(|(client, success)| {
    assert!(success);
    client.persist("foo")
  })
  .and_then(|(client, success)| {
    assert!(success);
    Ok(())
  }))
}<|endoftext|>


<commit_before>use error::P25Error;
use nid::NetworkID;
use receiver::DataUnitReceiver;
use status::StreamSymbol;
use trunking::tsbk::{TSBKFields, TSBKReceiver};
use voice::control::LinkControlFields;
use voice::crypto::CryptoControlFields;
use voice::frame::VoiceFrame;
use voice::header::VoiceHeaderFields;

use voice::{
    FrameGroupEvent,
    VoiceCCFrameGroupReceiver,
    VoiceHeaderReceiver,
    VoiceLCFrameGroupReceiver,
    VoiceLCTerminatorReceiver,
};

pub trait MessageHandler {
    fn handle_error(&mut self, err: P25Error);
    fn handle_nid(&mut self, nid: NetworkID);
    fn handle_header(&mut self, header: VoiceHeaderFields);
    fn handle_frame(&mut self, frame: VoiceFrame);
    fn handle_lc(&mut self, lc: LinkControlFields);
    fn handle_cc(&mut self, cc: CryptoControlFields);
    fn handle_data_frag(&mut self, data: u32);
    fn handle_tsbk(&mut self, tsbk: TSBKFields) -> bool;
    fn handle_term(&mut self);
}

enum State {
    Idle,
    DecodeHeader(VoiceHeaderReceiver),
    DecodeLCFrameGroup(VoiceLCFrameGroupReceiver),
    DecodeCCFrameGroup(VoiceCCFrameGroupReceiver),
    DecodeLCTerminator(VoiceLCTerminatorReceiver),
    DecodeTSBK(TSBKReceiver),
}

pub struct MessageReceiver {
    recv: DataUnitReceiver,
    state: State,
}

impl MessageReceiver {
    pub fn new() -> MessageReceiver {
        MessageReceiver {
            recv: DataUnitReceiver::new(),
            state: State::Idle,
        }
    }

    pub fn feed<H: MessageHandler>(&mut self, s: f32, handler: &mut H) {
        use self::State::*;
        use nid::DataUnit::*;
        use receiver::ReceiverEvent;

        let event = match self.recv.feed(s) {
            Some(Ok(event)) => event,
            Some(Err(err)) => {
                handler.handle_error(err);
                self.recv.resync();

                return;
            },
            None => return,
        };

        let dibit = match event {
            ReceiverEvent::NetworkID(nid) => {
                handler.handle_nid(nid);

                self.state = match nid.data_unit() {
                    VoiceHeader =>
                        DecodeHeader(VoiceHeaderReceiver::new()),
                    VoiceSimpleTerminator => {
                        handler.handle_term();
                        self.recv.flush_pads();
                        Idle
                    },
                    VoiceLCTerminator =>
                        DecodeLCTerminator(VoiceLCTerminatorReceiver::new()),
                    VoiceLCFrameGroup =>
                        DecodeLCFrameGroup(VoiceLCFrameGroupReceiver::new()),
                    VoiceCCFrameGroup =>
                        DecodeCCFrameGroup(VoiceCCFrameGroupReceiver::new()),
                    TrunkingSignaling =>
                        DecodeTSBK(TSBKReceiver::new()),
                    DataPacket => {
                        self.recv.resync();
                        Idle
                    },
                };

                return;
            },
            ReceiverEvent::Symbol(StreamSymbol::Status(_)) => return,
            ReceiverEvent::Symbol(StreamSymbol::Data(dibit)) => dibit,
        };

        match self.state {
            DecodeHeader(ref mut head) => match head.feed(dibit) {
                Some(Ok(h)) => {
                    handler.handle_header(h);
                    self.recv.flush_pads();
                },
                Some(Err(err)) => {
                    handler.handle_error(err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeLCFrameGroup(ref mut fg) => match fg.feed(dibit) {
                Some(Ok(event)) => match event {
                    FrameGroupEvent::VoiceFrame(vf) => {
                        handler.handle_frame(vf);

                        if fg.done() {
                            self.recv.flush_pads();
                        }
                    },
                    FrameGroupEvent::Extra(lc) => handler.handle_lc(lc),
                    FrameGroupEvent::DataFragment(data) => handler.handle_data_frag(data),
                },
                Some(Err(err)) => {
                    handler.handle_error(err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeCCFrameGroup(ref mut fg) => match fg.feed(dibit) {
                Some(Ok(event)) => match event {
                    FrameGroupEvent::VoiceFrame(vf) => {
                        handler.handle_frame(vf);

                        if fg.done() {
                            self.recv.flush_pads();
                        }
                    },
                    FrameGroupEvent::Extra(cc) => handler.handle_cc(cc),
                    FrameGroupEvent::DataFragment(data) => handler.handle_data_frag(data),
                },
                Some(Err(err)) => {
                    handler.handle_error(err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeLCTerminator(ref mut term) => match term.feed(dibit) {
                Some(Ok(lc)) => {
                    handler.handle_lc(lc);
                    handler.handle_term();
                    self.recv.flush_pads();
                },
                Some(Err(err)) => {
                    handler.handle_error(err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeTSBK(ref mut dec) => match dec.feed(dibit) {
                Some(Ok(tsbk)) => {
                    if handler.handle_tsbk(tsbk) {
                        self.recv.resync();
                    } else if tsbk.is_tail() {
                        self.recv.flush_pads();
                    }
                },
                Some(Err(err)) => {
                    handler.handle_error(err);
                    self.recv.resync();
                },
                None => {},
            },
            Idle => {},
        }
    }
}
<commit_msg>Pass DataUnitReceiver to all handle_* functions<commit_after>use error::P25Error;
use nid::NetworkID;
use receiver::DataUnitReceiver;
use status::StreamSymbol;
use trunking::tsbk::{TSBKFields, TSBKReceiver};
use voice::control::LinkControlFields;
use voice::crypto::CryptoControlFields;
use voice::frame::VoiceFrame;
use voice::header::VoiceHeaderFields;

use voice::{
    FrameGroupEvent,
    VoiceCCFrameGroupReceiver,
    VoiceHeaderReceiver,
    VoiceLCFrameGroupReceiver,
    VoiceLCTerminatorReceiver,
};

pub trait MessageHandler {
    fn handle_error(&mut self, recv: &mut DataUnitReceiver, err: P25Error);
    fn handle_nid(&mut self, recv: &mut DataUnitReceiver, nid: NetworkID);
    fn handle_header(&mut self, recv: &mut DataUnitReceiver, header: VoiceHeaderFields);
    fn handle_frame(&mut self, recv: &mut DataUnitReceiver, frame: VoiceFrame);
    fn handle_lc(&mut self, recv: &mut DataUnitReceiver, lc: LinkControlFields);
    fn handle_cc(&mut self, recv: &mut DataUnitReceiver, cc: CryptoControlFields);
    fn handle_data_frag(&mut self, recv: &mut DataUnitReceiver, data: u32);
    fn handle_tsbk(&mut self, recv: &mut DataUnitReceiver, tsbk: TSBKFields);
    fn handle_term(&mut self, recv: &mut DataUnitReceiver);
}

enum State {
    Idle,
    DecodeHeader(VoiceHeaderReceiver),
    DecodeLCFrameGroup(VoiceLCFrameGroupReceiver),
    DecodeCCFrameGroup(VoiceCCFrameGroupReceiver),
    DecodeLCTerminator(VoiceLCTerminatorReceiver),
    DecodeTSBK(TSBKReceiver),
}

pub struct MessageReceiver {
    recv: DataUnitReceiver,
    state: State,
}

impl MessageReceiver {
    pub fn new() -> MessageReceiver {
        MessageReceiver {
            recv: DataUnitReceiver::new(),
            state: State::Idle,
        }
    }

    pub fn feed<H: MessageHandler>(&mut self, s: f32, handler: &mut H) {
        use self::State::*;
        use nid::DataUnit::*;
        use receiver::ReceiverEvent;

        let event = match self.recv.feed(s) {
            Some(Ok(event)) => event,
            Some(Err(err)) => {
                handler.handle_error(&mut self.recv, err);
                self.recv.resync();

                return;
            },
            None => return,
        };

        let dibit = match event {
            ReceiverEvent::NetworkID(nid) => {
                handler.handle_nid(&mut self.recv, nid);

                self.state = match nid.data_unit() {
                    VoiceHeader =>
                        DecodeHeader(VoiceHeaderReceiver::new()),
                    VoiceSimpleTerminator => {
                        handler.handle_term(&mut self.recv);
                        self.recv.flush_pads();
                        Idle
                    },
                    VoiceLCTerminator =>
                        DecodeLCTerminator(VoiceLCTerminatorReceiver::new()),
                    VoiceLCFrameGroup =>
                        DecodeLCFrameGroup(VoiceLCFrameGroupReceiver::new()),
                    VoiceCCFrameGroup =>
                        DecodeCCFrameGroup(VoiceCCFrameGroupReceiver::new()),
                    TrunkingSignaling =>
                        DecodeTSBK(TSBKReceiver::new()),
                    DataPacket => {
                        self.recv.resync();
                        Idle
                    },
                };

                return;
            },
            ReceiverEvent::Symbol(StreamSymbol::Status(_)) => return,
            ReceiverEvent::Symbol(StreamSymbol::Data(dibit)) => dibit,
        };

        match self.state {
            DecodeHeader(ref mut head) => match head.feed(dibit) {
                Some(Ok(h)) => {
                    handler.handle_header(&mut self.recv, h);
                    self.recv.flush_pads();
                },
                Some(Err(err)) => {
                    handler.handle_error(&mut self.recv, err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeLCFrameGroup(ref mut fg) => match fg.feed(dibit) {
                Some(Ok(event)) => match event {
                    FrameGroupEvent::VoiceFrame(vf) => {
                        handler.handle_frame(&mut self.recv, vf);

                        if fg.done() {
                            self.recv.flush_pads();
                        }
                    },
                    FrameGroupEvent::Extra(lc) => handler.handle_lc(&mut self.recv, lc),
                    FrameGroupEvent::DataFragment(data) => handler.handle_data_frag(&mut self.recv, data),
                },
                Some(Err(err)) => {
                    handler.handle_error(&mut self.recv, err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeCCFrameGroup(ref mut fg) => match fg.feed(dibit) {
                Some(Ok(event)) => match event {
                    FrameGroupEvent::VoiceFrame(vf) => {
                        handler.handle_frame(&mut self.recv, vf);

                        if fg.done() {
                            self.recv.flush_pads();
                        }
                    },
                    FrameGroupEvent::Extra(cc) => handler.handle_cc(&mut self.recv, cc),
                    FrameGroupEvent::DataFragment(data) =>
                        handler.handle_data_frag(&mut self.recv, data),
                },
                Some(Err(err)) => {
                    handler.handle_error(&mut self.recv, err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeLCTerminator(ref mut term) => match term.feed(dibit) {
                Some(Ok(lc)) => {
                    handler.handle_lc(&mut self.recv, lc);
                    handler.handle_term(&mut self.recv);
                    self.recv.flush_pads();
                },
                Some(Err(err)) => {
                    handler.handle_error(&mut self.recv, err);
                    self.recv.resync();
                },
                None => {},
            },
            DecodeTSBK(ref mut dec) => match dec.feed(dibit) {
                Some(Ok(tsbk)) => {
                    handler.handle_tsbk(&mut self.recv, tsbk);

                    if tsbk.is_tail() {
                        self.recv.flush_pads();
                    }
                },
                Some(Err(err)) => {
                    handler.handle_error(&mut self.recv, err);
                    self.recv.resync();
                },
                None => {},
            },
            Idle => {},
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::Cell;

#[derive(Clone)]
pub struct Monitor {
    pub queue: Arc<Mutex<VecDeque<String>>>,
    pub start: Arc<AtomicUsize>,
    pub stop: Arc<AtomicUsize>,
    pub cond: Arc<Condvar>
}

pub struct Listener<'a> {
    monitor: &'a Monitor,
    position: Cell<usize>
}

const MAX_QUEUE_LENGTH: usize = 100;

impl Monitor {
    pub fn new() -> Monitor {
        Monitor {
            queue: Arc::new(Mutex::new(VecDeque::new())),
            start: Arc::new(AtomicUsize::new(0)),
            stop: Arc::new(AtomicUsize::new(0)),
            cond: Arc::new(Condvar::new())
        }
    }

    pub fn send(&self, payload: String) {
        let mut locked_queue = self.queue.lock().unwrap();

        locked_queue.push_back(payload);
        if locked_queue.len() > MAX_QUEUE_LENGTH {
            locked_queue.pop_front();
            self.start.fetch_add(1, Ordering::Release);
        }

        self.stop.fetch_add(1, Ordering::Release);

        self.cond.notify_all();
    }

    pub fn listen(&self) -> Listener {
        Listener {
            monitor: self,
            position: Cell::new(self.stop.load(Ordering::Acquire))
        }
    }
}

impl<'a> Listener<'a> {
    pub fn recv(&self) -> Option<String> {
        let mut locked_queue = self.monitor.queue.lock().unwrap();

        while self.position.get() == self.monitor.stop.load(Ordering::Acquire) {
            locked_queue = self.monitor.cond.wait(locked_queue).unwrap();
        }

        let start = self.monitor.start.load(Ordering::Acquire);

        if self.position.get() < start {
            // we missed some, notify caller?
            self.position.set(start);
        }

        let payload = locked_queue.get(self.position.get() - start);
        self.position.set(self.position.get() + 1);

        Some(payload.unwrap().clone())
    }
}
<commit_msg>Add monitor tests<commit_after>use std::collections::VecDeque;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::Cell;

#[derive(Clone)]
pub struct Monitor {
    pub queue: Arc<Mutex<VecDeque<String>>>,
    pub start: Arc<AtomicUsize>,
    pub stop: Arc<AtomicUsize>,
    pub cond: Arc<Condvar>
}

pub struct Listener<'a> {
    monitor: &'a Monitor,
    position: Cell<usize>
}

const MAX_QUEUE_LENGTH: usize = 100;

impl Monitor {
    pub fn new() -> Monitor {
        Monitor {
            queue: Arc::new(Mutex::new(VecDeque::new())),
            start: Arc::new(AtomicUsize::new(0)),
            stop: Arc::new(AtomicUsize::new(0)),
            cond: Arc::new(Condvar::new())
        }
    }

    pub fn send(&self, payload: String) {
        let mut locked_queue = self.queue.lock().unwrap();

        locked_queue.push_back(payload);
        if locked_queue.len() > MAX_QUEUE_LENGTH {
            locked_queue.pop_front();
            self.start.fetch_add(1, Ordering::Release);
        }

        self.stop.fetch_add(1, Ordering::Release);

        self.cond.notify_all();
    }

    pub fn listen(&self) -> Listener {
        Listener {
            monitor: self,
            position: Cell::new(self.stop.load(Ordering::Acquire))
        }
    }
}

impl<'a> Listener<'a> {
    pub fn recv(&self) -> Option<String> {
        let mut locked_queue = self.monitor.queue.lock().unwrap();

        while self.position.get() == self.monitor.stop.load(Ordering::Acquire) {
            locked_queue = self.monitor.cond.wait(locked_queue).unwrap();
        }

        let start = self.monitor.start.load(Ordering::Acquire);

        if self.position.get() < start {
            // we missed some, notify caller?
            self.position.set(start);
        }

        let payload = locked_queue.get(self.position.get() - start);
        self.position.set(self.position.get() + 1);

        Some(payload.unwrap().clone())
    }
}

#[cfg(test)]
mod tests {
    use super::Monitor;
    use std::{thread, time};

    #[test]
    fn monitor_acts_as_an_mpmc_queue() {
        let monitor = Monitor::new();

        monitor.send("will never be received".to_string());

        let listener_a = monitor.listen();
        monitor.send("A".to_string());

        let listener_b = monitor.listen();
        monitor.send("B".to_string());

        assert_eq!(listener_a.recv().unwrap(), "A".to_string());
        assert_eq!(listener_a.recv().unwrap(), "B".to_string());
        assert_eq!(listener_b.recv().unwrap(), "B".to_string());
    }

    #[test]
    fn monitor_can_be_shared_with_threads() {
        let monitor = Monitor::new();
        let mut receivers = vec![];

        for _ in 0..4 {
            let local_monitor = monitor.clone();

            receivers.push(thread::spawn(move || {
                let listener = local_monitor.listen();
                let mut payloads = (0..4).map(|_| listener.recv().unwrap()).collect::<Vec<String>>();
                payloads.sort();
                assert_eq!(payloads, vec!["0".to_string(), "1".to_string(), "2".to_string(), "3".to_string()]);
            }));
        }

        thread::sleep(time::Duration::from_millis(100));

        for index in 0..4 {
            let local_monitor = monitor.clone();

            thread::spawn(move || {
                local_monitor.send(index.to_string());
            });
        }

        for receiver in receivers {
            receiver.join().unwrap();
        }
    }

    #[test]
    fn nothing_bad_happens_when_you_send_with_no_listeners() {
        let monitor = Monitor::new();
        monitor.send("some payload".to_string());
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ptr;

use std::ffi::{CString,OsStr};
use std::ops::Deref;
use std::os::unix::io::{RawFd,AsRawFd};

use ::context::{Context};
use ::device::{Device};
use ::error::{Error};
use ::handle::prelude::*;

pub struct MonitorSpec<'a> {
    context: &'a Context,
    monitor: *mut ::ffi::udev_monitor
}

impl<'a> Drop for MonitorSpec<'a> {
    fn drop(&mut self) {
        unsafe {
            ::ffi::udev_monitor_unref(self.monitor);
        }
    }
}

impl<'a> MonitorSpec<'a> {
    pub fn new(context: &'a Context) -> Result<Self,Error> {
        let name = CString::new("udev").unwrap();

        let ptr = try_alloc!(unsafe {
            ::ffi::udev_monitor_new_from_netlink(context.as_ptr(), name.as_ptr())
        });

        Ok(MonitorSpec {
            context: context,
            monitor: ptr
        })
    }

    pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
        })
    }

    pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));
        let devtype = try!(::util::os_str_to_cstring(devtype));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
        })
    }

    pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> Result<(),Error> {
        let tag = try!(::util::os_str_to_cstring(tag));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
        })
    }

    pub fn clear_filters(&mut self) -> Result<(),Error> {
        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_remove(self.monitor)
        })
    }

    pub fn listen(self) -> Result<Monitor<'a>,Error> {
        try!(::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_enable_receiving(self.monitor)
        }));

        Ok(Monitor { spec: self })
    }
}

pub struct Monitor<'a> {
    spec: MonitorSpec<'a>
}

impl<'a> AsRawFd for Monitor<'a> {
    fn as_raw_fd(&self) -> RawFd {
        unsafe {
            ::ffi::udev_monitor_get_fd(self.spec.monitor)
        }
    }
}

impl<'a> Monitor<'a> {
    pub fn receive_event(&mut self) -> Option<MonitorEvent> {
        let device = unsafe {
            ::ffi::udev_monitor_receive_device(self.spec.monitor)
        };

        if device.is_null() {
            None
        }
        else {
            let device = ::device::new(self.spec.context, device);

            Some(MonitorEvent { device: device })
        }
    }
}

#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum EventType {
    Add,
    Change,
    Remove,
    Unknown,
}

impl Default for EventType {
    fn default() -> EventType { EventType::Unknown }
}

impl fmt::Display for EventType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match self {
            &EventType::Add => "add",
            &EventType::Change => "change",
            &EventType::Remove => "remove",
            &EventType::Unknown => "unknown",
        })
    }
}

pub struct MonitorEvent<'a> {
    device: Device<'a>
}

impl<'a> Deref for MonitorEvent<'a> {
    type Target = Device<'a>;

    fn deref(&self) -> &Device<'a> {
        &self.device
    }
}

impl<'a> MonitorEvent<'a> {
    pub fn event_type(&self) -> EventType {
        let value = match self.device.property_value("ACTION") {
            Some(s) => s.to_str(),
            None => None
        };

        match value {
            Some("add") => EventType::Add,
            Some("change") => EventType::Change,
            Some("remove") => EventType::Remove,
            _ => EventType::Unknown
        }
    }

    pub fn sequence_number(&self) -> u64 {
        unsafe {
            ::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
        }
    }

    pub fn device(&self) -> &Device {
        &self.device
    }
}
<commit_msg>fixes lifetime of MonitorEvent<commit_after>use std::fmt;
use std::ptr;

use std::ffi::{CString,OsStr};
use std::ops::Deref;
use std::os::unix::io::{RawFd,AsRawFd};

use ::context::{Context};
use ::device::{Device};
use ::error::{Error};
use ::handle::prelude::*;

pub struct MonitorSpec<'a> {
    context: &'a Context,
    monitor: *mut ::ffi::udev_monitor
}

impl<'a> Drop for MonitorSpec<'a> {
    fn drop(&mut self) {
        unsafe {
            ::ffi::udev_monitor_unref(self.monitor);
        }
    }
}

impl<'a> MonitorSpec<'a> {
    pub fn new(context: &'a Context) -> Result<Self,Error> {
        let name = CString::new("udev").unwrap();

        let ptr = try_alloc!(unsafe {
            ::ffi::udev_monitor_new_from_netlink(context.as_ptr(), name.as_ptr())
        });

        Ok(MonitorSpec {
            context: context,
            monitor: ptr
        })
    }

    pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
        })
    }

    pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));
        let devtype = try!(::util::os_str_to_cstring(devtype));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
        })
    }

    pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> Result<(),Error> {
        let tag = try!(::util::os_str_to_cstring(tag));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
        })
    }

    pub fn clear_filters(&mut self) -> Result<(),Error> {
        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_remove(self.monitor)
        })
    }

    pub fn listen(self) -> Result<Monitor<'a>,Error> {
        try!(::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_enable_receiving(self.monitor)
        }));

        Ok(Monitor { spec: self })
    }
}

pub struct Monitor<'a> {
    spec: MonitorSpec<'a>
}

impl<'a> AsRawFd for Monitor<'a> {
    fn as_raw_fd(&self) -> RawFd {
        unsafe {
            ::ffi::udev_monitor_get_fd(self.spec.monitor)
        }
    }
}

impl<'a> Monitor<'a> {
    pub fn receive_event<'b>(&'b mut self) -> Option<MonitorEvent<'a>> {
        let device = unsafe {
            ::ffi::udev_monitor_receive_device(self.spec.monitor)
        };

        if device.is_null() {
            None
        }
        else {
            let device = ::device::new(self.spec.context, device);

            Some(MonitorEvent { device: device })
        }
    }
}

#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum EventType {
    Add,
    Change,
    Remove,
    Unknown,
}

impl Default for EventType {
    fn default() -> EventType { EventType::Unknown }
}

impl fmt::Display for EventType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match self {
            &EventType::Add => "add",
            &EventType::Change => "change",
            &EventType::Remove => "remove",
            &EventType::Unknown => "unknown",
        })
    }
}

pub struct MonitorEvent<'a> {
    device: Device<'a>
}

impl<'a> Deref for MonitorEvent<'a> {
    type Target = Device<'a>;

    fn deref(&self) -> &Device<'a> {
        &self.device
    }
}

impl<'a> MonitorEvent<'a> {
    pub fn event_type(&self) -> EventType {
        let value = match self.device.property_value("ACTION") {
            Some(s) => s.to_str(),
            None => None
        };

        match value {
            Some("add") => EventType::Add,
            Some("change") => EventType::Change,
            Some("remove") => EventType::Remove,
            _ => EventType::Unknown
        }
    }

    pub fn sequence_number(&self) -> u64 {
        unsafe {
            ::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
        }
    }

    pub fn device(&self) -> &Device {
        &self.device
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_value(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (_, val) in (*v).values().enumerate() {
            if rem < (*val).len() {
                let cs = (*val)[rem as uint];
                return cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}
<commit_msg>embedding: cef_string_multimap_clear()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_value(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (_, val) in (*v).values().enumerate() {
            if rem < (*val).len() {
                let cs = (*val)[rem as uint];
                return cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_clear(smm: *mut cef_string_multimap_t) {
    unsafe {
        if smm.is_null() { return; }
        let v = string_multimap_to_treemap(smm);
        if (*v).len() == 0 { return; }
        for (_, val) in (*v).iter_mut() {
            while (*val).len() != 0 {
                let cs = (*val).pop();
                cef_string_userfree_utf8_free(cs.unwrap());
            }
        }
        (*v).clear();
    }
}
<|endoftext|>


<commit_before>enum PackageType {
    Bin, // Binary
    Lib, // Library
    Src, // Source
}

struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

struct List {
    url: String,
    packages: Vec<Package>,
}<commit_msg>Rename List to Repository to avoid ambiguity<commit_after>enum PackageType {
    Bin, // Binary
    Lib, // Library
    Src, // Source
}

struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

struct Repository {
    url: String,
    packages: Vec<Package>,
}
<|endoftext|>


<commit_before>use camera::Camera;
use gl;
use gl::types::*;
use gl_context::GLContext;
use light::Light;
use nalgebra::{Vec3, Mat4};
use std::collections::HashMap;
use std::mem;
use std::ptr;
use std::str;

pub struct Shader {
  pub id: GLuint,
  pub components: Vec<GLuint>,
  pub uniforms: HashMap<String, GLint>,
}

impl Shader {
  pub fn new<T: Iterator<(String, GLenum)>>(
      gl: &mut GLContext,
      shader_components: T,
  ) -> Shader {
    let mut shader_components = shader_components;
    let program = gl::CreateProgram();

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = gl.compile_shader(content, component);
      gl::AttachShader(program, s);
      components.push(s);
    }

    gl::LinkProgram(program);

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        unsafe {
          gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        }
        let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
        unsafe {
          gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        }
        fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      id: program,
      components: components,
      uniforms: HashMap::new(),
    }
  }

  pub fn with_uniform_location<T>(
    &mut self,
    gl: &mut GLContext,
    name: &'static str,
    f: |GLint| -> T,
  ) -> T {
    let s_name = String::from_str(name);
    let name = gl.scache.convert(name).as_ptr();
    let t = match self.uniforms.find(&s_name) {
      None => {
        let (loc, t) = gl.use_shader(self, |_| {
          let loc = unsafe { gl::GetUniformLocation(self.id, name) };
          assert!(loc != -1, "couldn't find shader uniform {}", s_name);

          match gl::GetError() {
            gl::NO_ERROR => {},
            err => fail!("OpenGL error 0x{:x} in GetUniformLocation", err),
          }

          (loc, f(loc))
        });

        self.uniforms.insert(s_name, loc);
        t
      },
      Some(&loc) => gl.use_shader(self, |_| f(loc)),
    };

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x} in with_uniform_location callback", err),
    }

    t
  }

  /// Sets the variable `light` in some shader.
  pub fn set_point_light(&mut self, gl: &mut GLContext, light: &Light) {
    self.with_uniform_location(gl, "light.position", |light_pos| {
      gl::Uniform3f(light_pos, light.position.x, light.position.y, light.position.z);
    });
    self.with_uniform_location(gl, "light.intensity", |light_intensity| {
      gl::Uniform3f(light_intensity, light.intensity.x, light.intensity.y, light.intensity.z);
    });
  }

  pub fn set_ambient_light(&mut self, gl: &mut GLContext, intensity: Vec3<GLfloat>) {
    self.with_uniform_location(gl, "ambient_light", |loc| {
      gl::Uniform3f(loc, intensity.x, intensity.y, intensity.z);
    });
  }

  /// Sets the variable `projection_matrix` in some shader.
  pub fn set_projection_matrix(&mut self, gl: &mut GLContext, m: &Mat4<GLfloat>) {
    self.with_uniform_location(gl, "projection_matrix", |loc| {
      unsafe {
        let p = mem::transmute(m);
        gl::UniformMatrix4fv(loc, 1, 0, p);
      }

      match gl::GetError() {
        gl::NO_ERROR => {},
        err => fail!("OpenGL error 0x{:x} in UniformMat4fv", err),
      }
    })
  }

  pub fn set_camera(&mut self, gl: &mut GLContext, c: &Camera) {
    self.set_projection_matrix(gl, &c.projection_matrix());
  }
}

impl Drop for Shader {
  fn drop(&mut self) {
    gl::DeleteProgram(self.id);
    for &s in self.components.iter() {
      gl::DeleteShader(s);
    }
  }
}
<commit_msg>tiny error message change<commit_after>use camera::Camera;
use gl;
use gl::types::*;
use gl_context::GLContext;
use light::Light;
use nalgebra::{Vec3, Mat4};
use std::collections::HashMap;
use std::mem;
use std::ptr;
use std::str;

pub struct Shader {
  pub id: GLuint,
  pub components: Vec<GLuint>,
  pub uniforms: HashMap<String, GLint>,
}

impl Shader {
  pub fn new<T: Iterator<(String, GLenum)>>(
      gl: &mut GLContext,
      shader_components: T,
  ) -> Shader {
    let mut shader_components = shader_components;
    let program = gl::CreateProgram();

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = gl.compile_shader(content, component);
      gl::AttachShader(program, s);
      components.push(s);
    }

    gl::LinkProgram(program);

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        unsafe {
          gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        }
        let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
        unsafe {
          gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        }
        fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      id: program,
      components: components,
      uniforms: HashMap::new(),
    }
  }

  pub fn with_uniform_location<T>(
    &mut self,
    gl: &mut GLContext,
    name: &'static str,
    f: |GLint| -> T,
  ) -> T {
    let s_name = String::from_str(name);
    let name = gl.scache.convert(name).as_ptr();
    let t = match self.uniforms.find(&s_name) {
      None => {
        let (loc, t) = gl.use_shader(self, |_| {
          let loc = unsafe { gl::GetUniformLocation(self.id, name) };
          assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

          match gl::GetError() {
            gl::NO_ERROR => {},
            err => fail!("OpenGL error 0x{:x} in GetUniformLocation", err),
          }

          (loc, f(loc))
        });

        self.uniforms.insert(s_name, loc);
        t
      },
      Some(&loc) => gl.use_shader(self, |_| f(loc)),
    };

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x} in with_uniform_location callback", err),
    }

    t
  }

  /// Sets the variable `light` in some shader.
  pub fn set_point_light(&mut self, gl: &mut GLContext, light: &Light) {
    self.with_uniform_location(gl, "light.position", |light_pos| {
      gl::Uniform3f(light_pos, light.position.x, light.position.y, light.position.z);
    });
    self.with_uniform_location(gl, "light.intensity", |light_intensity| {
      gl::Uniform3f(light_intensity, light.intensity.x, light.intensity.y, light.intensity.z);
    });
  }

  pub fn set_ambient_light(&mut self, gl: &mut GLContext, intensity: Vec3<GLfloat>) {
    self.with_uniform_location(gl, "ambient_light", |loc| {
      gl::Uniform3f(loc, intensity.x, intensity.y, intensity.z);
    });
  }

  /// Sets the variable `projection_matrix` in some shader.
  pub fn set_projection_matrix(&mut self, gl: &mut GLContext, m: &Mat4<GLfloat>) {
    self.with_uniform_location(gl, "projection_matrix", |loc| {
      unsafe {
        let p = mem::transmute(m);
        gl::UniformMatrix4fv(loc, 1, 0, p);
      }

      match gl::GetError() {
        gl::NO_ERROR => {},
        err => fail!("OpenGL error 0x{:x} in UniformMat4fv", err),
      }
    })
  }

  pub fn set_camera(&mut self, gl: &mut GLContext, c: &Camera) {
    self.set_projection_matrix(gl, &c.projection_matrix());
  }
}

impl Drop for Shader {
  fn drop(&mut self) {
    gl::DeleteProgram(self.id);
    for &s in self.components.iter() {
      gl::DeleteShader(s);
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::ffi::CString;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Write;
use std::os::linux::fs::MetadataExt;
use std::path::Path;
use std::result;
use std::thread;
use std::time::Duration;

use libc;

use gpio::Trigger;

/// Result type returned from methods that can have `io::Error`s.
pub type Result<T> = result::Result<T, io::Error>;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Direction {
    In,
    Out,
    Low,
    High,
}

// Find group ID for specified group name
fn group_name_to_gid(name: &str) -> Option<u32> {
    if let Ok(name_cstr) = CString::new(name) {
        unsafe {
            let group_ptr = libc::getgrnam(name_cstr.as_ptr());

            if !group_ptr.is_null() {
                return Some((*group_ptr).gr_gid);
            }
        }
    }

    None
}

pub fn export(pin: u8) -> Result<()> {
    // Only export if the pin isn't already exported
    if !Path::new(&format!("/sys/class/gpio/gpio{}", pin)).exists() {
        File::create("/sys/class/gpio/export")?.write_fmt(format_args!("{}", pin))?;
    }

    // The symlink created by exporting a pin starts off owned by root:root. There's
    // a short delay before the group is changed to gpio. Since rppal should work for
    // non-root users, we'll wait for max. 1s for the group to change to gpio.
    let gid_gpio = if let Some(gid) = group_name_to_gid("gpio") {
        gid
    } else {
        0
    };

    let mut counter = 0;
    while counter < 20 {
        let meta = fs::metadata(format!("/sys/class/gpio/gpio{}", pin))?;
        if meta.st_gid() == gid_gpio {
            break;
        }

        thread::sleep(Duration::from_millis(50));
        counter += 1;
    }

    Ok(())
}

pub fn unexport(pin: u8) -> Result<()> {
    // Only unexport if the pin is actually exported
    if Path::new(&format!("/sys/class/gpio/gpio{}", pin)).exists() {
        File::create("/sys/class/gpio/unexport")?.write_fmt(format_args!("{}", pin))?;
    }

    Ok(())
}

pub fn set_direction(pin: u8, direction: Direction) -> Result<()> {
    let b_direction: &[u8] = match direction {
        Direction::In => b"in",
        Direction::Out => b"out",
        Direction::Low => b"low",
        Direction::High => b"high",
    };

    File::create(format!("/sys/class/gpio/gpio{}/direction", pin))?.write_all(b_direction)?;

    Ok(())
}

pub fn set_edge(pin: u8, trigger: Trigger) -> Result<()> {
    let b_trigger: &[u8] = match trigger {
        Trigger::Disabled => b"none",
        Trigger::RisingEdge => b"rising",
        Trigger::FallingEdge => b"falling",
        Trigger::Both => b"both",
    };

    File::create(format!("/sys/class/gpio/gpio{}/edge", pin))?.write_all(b_trigger)?;

    Ok(())
}

pub fn open_value(pin: u8) -> Result<File> {
    Ok(File::open(format!("/sys/class/gpio/gpio{}/value", pin))?)
}
<commit_msg>Add troubleshooting comments<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::ffi::CString;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Write;
use std::os::linux::fs::MetadataExt;
use std::path::Path;
use std::result;
use std::thread;
use std::time::Duration;

use libc;

use gpio::Trigger;

/// Result type returned from methods that can have `io::Error`s.
pub type Result<T> = result::Result<T, io::Error>;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Direction {
    In,
    Out,
    Low,
    High,
}

// Find group ID for specified group name
fn group_name_to_gid(name: &str) -> Option<u32> {
    if let Ok(name_cstr) = CString::new(name) {
        unsafe {
            let group_ptr = libc::getgrnam(name_cstr.as_ptr());

            if !group_ptr.is_null() {
                return Some((*group_ptr).gr_gid);
            }
        }
    }

    None
}

pub fn export(pin: u8) -> Result<()> {
    // Only export if the pin isn't already exported
    if !Path::new(&format!("/sys/class/gpio/gpio{}", pin)).exists() {
        File::create("/sys/class/gpio/export")?.write_fmt(format_args!("{}", pin))?;
    }

    // The symlink created by exporting a pin starts off owned by root:root. There's
    // a short delay before the group is changed to gpio. Since rppal should work for
    // non-root users, we'll wait for max. 1s for the group to change to gpio. If
    // this isn't working, check the udev rules (/etc/udev/rules.d/99-com.rules).
    let gid_gpio = if let Some(gid) = group_name_to_gid("gpio") {
        gid
    } else {
        0
    };

    let mut counter = 0;
    while counter < 20 {
        let meta = fs::metadata(format!("/sys/class/gpio/gpio{}", pin))?;
        if meta.st_gid() == gid_gpio {
            break;
        }

        thread::sleep(Duration::from_millis(50));
        counter += 1;
    }

    Ok(())
}

pub fn unexport(pin: u8) -> Result<()> {
    // Only unexport if the pin is actually exported
    if Path::new(&format!("/sys/class/gpio/gpio{}", pin)).exists() {
        File::create("/sys/class/gpio/unexport")?.write_fmt(format_args!("{}", pin))?;
    }

    Ok(())
}

pub fn set_direction(pin: u8, direction: Direction) -> Result<()> {
    let b_direction: &[u8] = match direction {
        Direction::In => b"in",
        Direction::Out => b"out",
        Direction::Low => b"low",
        Direction::High => b"high",
    };

    File::create(format!("/sys/class/gpio/gpio{}/direction", pin))?.write_all(b_direction)?;

    Ok(())
}

pub fn set_edge(pin: u8, trigger: Trigger) -> Result<()> {
    let b_trigger: &[u8] = match trigger {
        Trigger::Disabled => b"none",
        Trigger::RisingEdge => b"rising",
        Trigger::FallingEdge => b"falling",
        Trigger::Both => b"both",
    };

    File::create(format!("/sys/class/gpio/gpio{}/edge", pin))?.write_all(b_trigger)?;

    Ok(())
}

pub fn open_value(pin: u8) -> Result<File> {
    Ok(File::open(format!("/sys/class/gpio/gpio{}/value", pin))?)
}
<|endoftext|>