<commit_before>extern crate libc;

pub mod assembler;
pub use assembler::{Arch, Reloc, assemble, assemble2};

#[test]
fn x86_int3() {
    assert_eq!(assemble(Arch::X86, "int3").unwrap(), [0xcc]);
}

#[test]
fn x86_jcc() {
    let bytes = assemble(Arch::X86_64, "nop; jz here; nop; nop; here:").unwrap();
    assert_eq!(bytes, [0x90, 0x74, 0x02, 0x90, 0x90]);
}

#[test]
fn x86_jmp_rel() {
    let addr = 0x1000;
    let reloc = Reloc::new("here", 0x1003);
    let bytes = assemble2(Arch::X86_64, "jmp here", addr, &[reloc]).unwrap();
    assert_eq!(bytes, [0xeb, 0x01]);
}

#[test]
fn missing_label() {
    assert_eq!(assemble(Arch::X86_64, "jz here"), None);
}
<commit_msg>adding another test<commit_after>extern crate libc;

pub mod assembler;
pub use assembler::{Arch, Reloc, assemble, assemble2};

#[test]
fn x86_int3() {
    assert_eq!(assemble(Arch::X86, "int3").unwrap(), [0xcc]);
}

#[test]
fn x86_jcc() {
    let bytes = assemble(Arch::X86_64, "nop; jz here; nop; nop; here:").unwrap();
    assert_eq!(bytes, [0x90, 0x74, 0x02, 0x90, 0x90]);
}

#[test]
fn x86_je() {
    let bytes = assemble(Arch::X86_64, "je here;here:").unwrap();
    assert_eq!(bytes, [0x74, 0x00]);
}

#[test]
fn x86_jmp_rel() {
    let addr = 0x1000;
    let reloc = Reloc::new("here", 0x1003);
    let bytes = assemble2(Arch::X86_64, "jmp here", addr, &[reloc]).unwrap();
    assert_eq!(bytes, [0xeb, 0x01]);
}

#[test]
fn missing_label() {
    assert_eq!(assemble(Arch::X86_64, "jz here"), None);
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]

//! # Configuring your dependency
//! `toml-config` can be configured to use `rustc_serialize` or `serde`
//!
//! ### Using `toml-config` with `rustc_serialize`
//! By default `toml-config` uses `rustc_serialize`, so just add the dependency in Cargo.toml normally:
//!
//! ```toml
//! [dependencies]
//! toml-config = "0.2"
//! ```
//! ### Using `toml-config` with `serde`
//! To use toml-config with `serde`, opt out from the default features and enable the `serde-serialization`
//! feature:
//!
//! ```toml
//! [dependencies.toml-config]
//! version = "0.2"
//! default-features = false
//! features = ["serde-serialization"]
//! ```

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde-serialization")] extern crate serde;

#[macro_use] extern crate log;

extern crate toml;

#[cfg(feature = "rustc-serialize")] use rustc_serialize::{Encodable, Decodable};
#[cfg(feature = "serde-serialization")] use serde::{Serialize, Deserialize};

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

/// Implements helper functions for loading TOML files into a structure
///
/// # Examples
/// To load a file into a Config struct, use `ConfigFactory`.
///
/// Either `rustc_serialize` or `serde` can be used for serialization.
///
/// ## Example using rustc_serialize
/// ```no_run
/// # #[cfg(feature = "rustc-serialize")]
/// extern crate rustc_serialize;
/// extern crate toml_config;
///
/// # #[cfg(feature = "rustc-serialize")]
/// # fn main() {
/// use rustc_serialize::{Encodable, Decodable};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "serde-serialization")] fn main() { }
/// ```
/// ## Example using serde
/// ```no_run
/// # #![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
/// # #![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]
/// # #[cfg(feature = "serde-serialization")]
/// extern crate serde;
/// extern crate toml_config;
///
/// # #[cfg(feature = "serde-serialization")]
/// # fn main() {
/// use serde::{Serialize, Deserialize};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(Serialize, Deserialize)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(Serialize, Deserialize)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "rustc-serialize")] fn main() { }
/// ```
pub struct ConfigFactory;

impl ConfigFactory {
    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "rustc-serialize")]
    pub fn load<T>(path: &Path) -> T where T: Encodable + Decodable + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => {
                let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
                let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
                toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
            },
            None => T::default()
        }
    }

    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "serde-serialization")]
    pub fn load<T>(path: &Path) -> T where T: Serialize + Deserialize + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => {
                let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
                let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
                toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
            },
            None => T::default()
        }
    }

    fn parse_toml_file(path: &Path) -> Option<toml::Table> {
        let mut toml_config = String::new();

        let mut file = match File::open(path) {
            Ok(file) => file,
            Err(_)  => {
                warn!("Config file not found: {}, using defaults..", path.display());
                return None;
            }
        };

        file.read_to_string(&mut toml_config)
            .unwrap_or_else(|err| panic!("Unable to read config file: {}", err));

        let mut parser = toml::Parser::new(&toml_config);
        let toml_table = parser.parse();

        if toml_table.is_none() {
            for err in &parser.errors {
                let (line, col) = parser.to_linecol(err.lo);
                error!("Parsing of {} failed [{}:{}] - {}", path.display(), line + 1, col + 1, err.desc);
            }
            error!("Unable to parse config file: {}, using defaults..", path.display());
            return None;
        }

        toml_table
    }

    fn apply_overrides(defaults: toml::Table, overrides: toml::Table) -> toml::Table {
        let mut merged = defaults.clone();
        for (k, v) in overrides.into_iter() {
            match defaults.get(&k) {
                Some(default_value) =>
                    if v.type_str() == default_value.type_str() {
                        match v {
                            toml::Value::Table(overrides_table) => {
                                let defaults_table = default_value.as_table().unwrap().clone();
                                let merged_table = ConfigFactory::apply_overrides(defaults_table, overrides_table);
                                merged.insert(k, toml::Value::Table(merged_table))
                            },
                            any => merged.insert(k, any)
                        };
                    } else {
                        warn!("Wrong type for config: {}. Expected: {}, found: {}, using default value..",
                            k, default_value.type_str(), v.type_str());
                    },
                None => {
                    merged.insert(k, v);
                }
            }
        }
        merged
    }
}

#[cfg(test)]
mod tests {
    use super::ConfigFactory;

    extern crate tempfile;
    use std::io::Write;

    macro_rules! tempfile {
        ($content:expr) => {
            {
                let mut f = tempfile::NamedTempFile::new().unwrap();
                f.write_all($content.as_bytes()).unwrap();
                f.flush().unwrap();
                f
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct Config  {
        pub nested: NestedConfig,
        pub optional: Option<String>
    }

    impl Default for Config {
        fn default() -> Config {
            Config {
                nested: NestedConfig::default(),
                optional: None
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct NestedConfig  {
        pub value: String,
        pub values: Vec<u16>
    }

    impl Default for NestedConfig {
        fn default() -> NestedConfig {
            NestedConfig {
                value: "default".to_owned(),
                values: vec![0, 0, 0]
            }
        }
    }

    #[test]
    fn it_should_parse_and_decode_a_valid_toml_file() {
        let toml_file = tempfile!(r#"
            optional = "override"
            [nested]
            value = "test"
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
        assert_eq!(config.optional, Some("override".to_owned()));
    }

    #[test]
    fn it_should_use_the_default_for_missing_config() {
        let toml_file = tempfile!("");
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_use_the_default_values_for_missing_config_values() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_return_the_default_config_value_for_misconfigured_properties() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = "wrong-type"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_ignore_unexpected_config() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = [1, 2, 3]
            unexpected = "ignore-me"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
    }

    #[test]
    fn it_should_return_the_default_config_when_parsing_fails() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }
}
<commit_msg>Exposing a decode() method to directly decode a TOML table into a target struct<commit_after>#![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]

//! # Configuring your dependency
//! `toml-config` can be configured to use `rustc_serialize` or `serde`
//!
//! ### Using `toml-config` with `rustc_serialize`
//! By default `toml-config` uses `rustc_serialize`, so just add the dependency in Cargo.toml normally:
//!
//! ```toml
//! [dependencies]
//! toml-config = "0.2"
//! ```
//! ### Using `toml-config` with `serde`
//! To use toml-config with `serde`, opt out from the default features and enable the `serde-serialization`
//! feature:
//!
//! ```toml
//! [dependencies.toml-config]
//! version = "0.2"
//! default-features = false
//! features = ["serde-serialization"]
//! ```

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde-serialization")] extern crate serde;

#[macro_use] extern crate log;

extern crate toml;

#[cfg(feature = "rustc-serialize")] use rustc_serialize::{Encodable, Decodable};
#[cfg(feature = "serde-serialization")] use serde::{Serialize, Deserialize};

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

/// Implements helper functions for loading TOML files into a structure
///
/// # Examples
/// To load a file into a Config struct, use `ConfigFactory`.
///
/// Either `rustc_serialize` or `serde` can be used for serialization.
///
/// ## Example using rustc_serialize
/// ```no_run
/// # #[cfg(feature = "rustc-serialize")]
/// extern crate rustc_serialize;
/// extern crate toml_config;
///
/// # #[cfg(feature = "rustc-serialize")]
/// # fn main() {
/// use rustc_serialize::{Encodable, Decodable};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(RustcEncodable, RustcDecodable)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "serde-serialization")] fn main() { }
/// ```
/// ## Example using serde
/// ```no_run
/// # #![cfg_attr(feature = "serde-serialization", feature(custom_derive, plugin))]
/// # #![cfg_attr(feature = "serde-serialization", plugin(serde_macros))]
/// # #[cfg(feature = "serde-serialization")]
/// extern crate serde;
/// extern crate toml_config;
///
/// # #[cfg(feature = "serde-serialization")]
/// # fn main() {
/// use serde::{Serialize, Deserialize};
/// use std::path::Path;
/// use toml_config::ConfigFactory;
///
/// #[derive(Serialize, Deserialize)]
/// struct Config  {
///     nested: NestedConfig
/// }
///
/// // Defaults will be used for missing/invalid configurations in the TOML config file
/// impl Default for Config {
///     fn default() -> Config {
///         Config {
///             nested: NestedConfig::default()
///         }
///     }
/// }
///
/// #[derive(Serialize, Deserialize)]
/// struct NestedConfig  {
///     value: String,
///     values: Vec<u16>
/// }
///
/// impl Default for NestedConfig {
///     fn default() -> NestedConfig {
///         NestedConfig {
///             value: "default".to_owned(),
///             values: vec![0, 0, 0]
///         }
///     }
/// }
///
/// /* config.toml:
///  * [nested]
///  * value = "test"
///  * values = [1, 2, 3]
///  */
///
/// let config: Config = ConfigFactory::load(Path::new("config.toml"));
/// assert_eq!(config.nested.value, "test");
/// assert_eq!(config.nested.values, vec![1, 2, 3]);
/// # }
/// # #[cfg(feature = "rustc-serialize")] fn main() { }
/// ```
pub struct ConfigFactory;

impl ConfigFactory {
    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "rustc-serialize")]
    pub fn load<T>(path: &Path) -> T where T: Encodable + Decodable + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => ConfigFactory::decode(toml_table),
            None => T::default()
        }
    }

    /// Loads a TOML file and decodes it into a target structure, using default values
    /// for missing or invalid file configurations
    #[cfg(feature = "serde-serialization")]
    pub fn load<T>(path: &Path) -> T where T: Serialize + Deserialize + Default {
        match ConfigFactory::parse_toml_file(path) {
            Some(toml_table) => ConfigFactory::decode(toml_table),
            None => T::default()
        }
    }

    /// Decodes a TOML table into a target structure, using default values
    /// for missing or invalid configurations
    #[cfg(feature = "rustc-serialize")]
    pub fn decode<T>(toml_table: toml::Table) -> T where T: Encodable + Decodable + Default {
        let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
        let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
        toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
    }

    /// Decodes a TOML table into a target structure, using default values
    /// for missing or invalid configurations
    #[cfg(feature = "serde-serialization")]
    pub fn decode<T>(toml_table: toml::Table) -> T where T: Serialize + Deserialize + Default {
        let default_table = toml::encode(&T::default()).as_table().unwrap().clone();
        let table_with_overrides = ConfigFactory::apply_overrides(default_table, toml_table);
        toml::decode(toml::Value::Table(table_with_overrides)).unwrap()
    }

    fn parse_toml_file(path: &Path) -> Option<toml::Table> {
        let mut toml_config = String::new();

        let mut file = match File::open(path) {
            Ok(file) => file,
            Err(_)  => {
                warn!("Config file not found: {}, using defaults..", path.display());
                return None;
            }
        };

        file.read_to_string(&mut toml_config)
            .unwrap_or_else(|err| panic!("Unable to read config file: {}", err));

        let mut parser = toml::Parser::new(&toml_config);
        let toml_table = parser.parse();

        if toml_table.is_none() {
            for err in &parser.errors {
                let (line, col) = parser.to_linecol(err.lo);
                error!("Parsing of {} failed [{}:{}] - {}", path.display(), line + 1, col + 1, err.desc);
            }
            error!("Unable to parse config file: {}, using defaults..", path.display());
            return None;
        }

        toml_table
    }

    fn apply_overrides(defaults: toml::Table, overrides: toml::Table) -> toml::Table {
        let mut merged = defaults.clone();
        for (k, v) in overrides.into_iter() {
            match defaults.get(&k) {
                Some(default_value) =>
                    if v.type_str() == default_value.type_str() {
                        match v {
                            toml::Value::Table(overrides_table) => {
                                let defaults_table = default_value.as_table().unwrap().clone();
                                let merged_table = ConfigFactory::apply_overrides(defaults_table, overrides_table);
                                merged.insert(k, toml::Value::Table(merged_table))
                            },
                            any => merged.insert(k, any)
                        };
                    } else {
                        warn!("Wrong type for config: {}. Expected: {}, found: {}, using default value..",
                            k, default_value.type_str(), v.type_str());
                    },
                None => {
                    merged.insert(k, v);
                }
            }
        }
        merged
    }
}

#[cfg(test)]
mod tests {
    use super::ConfigFactory;

    extern crate tempfile;
    use std::io::Write;

    macro_rules! tempfile {
        ($content:expr) => {
            {
                let mut f = tempfile::NamedTempFile::new().unwrap();
                f.write_all($content.as_bytes()).unwrap();
                f.flush().unwrap();
                f
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct Config  {
        pub nested: NestedConfig,
        pub optional: Option<String>
    }

    impl Default for Config {
        fn default() -> Config {
            Config {
                nested: NestedConfig::default(),
                optional: None
            }
        }
    }

    #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
    #[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
    pub struct NestedConfig  {
        pub value: String,
        pub values: Vec<u16>
    }

    impl Default for NestedConfig {
        fn default() -> NestedConfig {
            NestedConfig {
                value: "default".to_owned(),
                values: vec![0, 0, 0]
            }
        }
    }

    #[test]
    fn it_should_parse_and_decode_a_valid_toml_file() {
        let toml_file = tempfile!(r#"
            optional = "override"
            [nested]
            value = "test"
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
        assert_eq!(config.optional, Some("override".to_owned()));
    }

    #[test]
    fn it_should_use_the_default_for_missing_config() {
        let toml_file = tempfile!("");
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_use_the_default_values_for_missing_config_values() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_return_the_default_config_value_for_misconfigured_properties() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = "wrong-type"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }

    #[test]
    fn it_should_ignore_unexpected_config() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test"
            values = [1, 2, 3]
            unexpected = "ignore-me"
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "test");
        assert_eq!(config.nested.values, vec![1, 2, 3]);
    }

    #[test]
    fn it_should_return_the_default_config_when_parsing_fails() {
        let toml_file = tempfile!(r#"
            [nested]
            value = "test
            values = [1, 2, 3]
        "#);
        let config: Config = ConfigFactory::load(toml_file.path());
        assert_eq!(config.nested.value, "default");
        assert_eq!(config.nested.values, vec![0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

extern crate rustrt;

use std::sync::atomic::{AtomicBool, SeqCst};
use std::cell::UnsafeCell;
use rustrt::local::Local;
use rustrt::task::Task;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

impl<T: Send> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: AtomicBool::new(false),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline(always)]
    fn lock_check(&self) -> bool
    {
        self.lock.compare_and_swap(false, true, SeqCst) != false
    }

    fn obtain_lock(&self)
    {
        if Local::exists(None::<Task>)
        {
            self.obtain_lock_with_runtime();
        }
        else
        {
            self.obtain_lock_without_runtime();
        }
    }

    fn obtain_lock_with_runtime(&self)
    {
        while self.lock_check()
        {
            std::task::deschedule();
        }
    }

    fn obtain_lock_without_runtime(&self)
    {
        while self.lock_check()
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T: Send> Deref<T> for SpinlockGuard<'a, T>
{
    fn deref<'a>(&'a self) -> &'a T { &*self.data }
}

impl<'a, T: Send> DerefMut<T> for SpinlockGuard<'a, T>
{
    fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T: Send> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, SeqCst);
    }
}
<commit_msg>Rename lifetimes of deref and deref_mut to avoid lifetime shadowing (deprecated and will be removed). See Deref Implementation of core::cell::Ref for a similar case<commit_after>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

extern crate rustrt;

use std::sync::atomic::{AtomicBool, SeqCst};
use std::cell::UnsafeCell;
use rustrt::local::Local;
use rustrt::task::Task;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

impl<T: Send> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: AtomicBool::new(false),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline(always)]
    fn lock_check(&self) -> bool
    {
        self.lock.compare_and_swap(false, true, SeqCst) != false
    }

    fn obtain_lock(&self)
    {
        if Local::exists(None::<Task>)
        {
            self.obtain_lock_with_runtime();
        }
        else
        {
            self.obtain_lock_without_runtime();
        }
    }

    fn obtain_lock_with_runtime(&self)
    {
        while self.lock_check()
        {
            std::task::deschedule();
        }
    }

    fn obtain_lock_without_runtime(&self)
    {
        while self.lock_check()
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T: Send> Deref<T> for SpinlockGuard<'a, T>
{
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T: Send> DerefMut<T> for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T: Send> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, SeqCst);
    }
}
<|endoftext|>


<commit_before>extern crate libc;
/*
 * seccomp actions
 */
#[allow(non_camel_case_types)]
pub type scmp_filter_ctx = libc::c_void;

/**
 * Kill the process
 */
pub const SCMP_ACT_KILL: u32  = 0x00000000;
/**
 * Throw a SIGSYS signal
 */
pub const SCMP_ACT_TRAP: u32 = 0x00030000;
/**
 * Return the specified error code
 */
//pub const SCMP_ACT_ERRNO(x)       (0x00050000U | ((x) & 0x0000ffffU))
/**
 * Notify a tracing process with the specified value
 */
//pub const SCMP_ACT_TRACE(x)       (0x7ff00000U | ((x) & 0x0000ffffU))
/**
 * Allow the syscall to be executed
 */
pub const SCMP_ACT_ALLOW: u32 = 0x7fff0000;

/**
 * Filter attributes
 */
#[repr(C)]
pub enum scmp_filter_attr {
    _SCMP_FLTATR_MIN,
    SCMP_FLTATR_ACT_DEFAULT, /**< default filter action */
    SCMP_FLTATR_ACT_BADARCH, /**< bad architecture action */
    SCMP_FLTATR_CTL_NNP, /**< set NO_NEW_PRIVS on filter load */
    _SCMP_FLTATR_MAX,
}

/**
 * Comparison operators
 */
#[repr(C)]
pub enum scmp_compare {
        _SCMP_CMP_MIN = 0,
        SCMP_CMP_NE = 1,                /**< not equal */
        SCMP_CMP_LT = 2,                /**< less than */
        SCMP_CMP_LE = 3,                /**< less than or equal */
        SCMP_CMP_EQ = 4,                /**< equal */
        SCMP_CMP_GE = 5,                /**< greater than or equal */
        SCMP_CMP_GT = 6,                /**< greater than */
        SCMP_CMP_MASKED_EQ = 7,         /**< masked equality */
        _SCMP_CMP_MAX,
}

/**
 * Argument datum
 */
#[allow(non_camel_case_types)]
pub type scmp_datum_t = libc::uint64_t;

/**
 * Argument / Value comparison definition
 */
#[repr(C)]
pub struct scmp_arg_cmp {
        pub arg: libc::c_uint,        /**< argument number, starting at 0 */
        pub op: scmp_compare,       /**< the comparison op, e.g. SCMP_CMP_* */
        pub datum_a: scmp_datum_t,
        pub datum_b: scmp_datum_t,
}

#[link(name = "seccomp")]
extern {
    /**
     * Initialize the filter state
     *
     * @param def_action the default filter action
     *
     * This function initializes the internal seccomp filter state and should
     * be called before any other functions in this library to ensure the filter
     * state is initialized.  Returns a filter context on success, NULL on failure.
     *
     */
    pub fn seccomp_init(def_action: libc::uint32_t) -> *mut scmp_filter_ctx;
    /**
     * Reset the filter state
     *
     * @param ctx the filter context
     * @param def_action the default filter action
     *
     * This function resets the given seccomp filter state and ensures the
     * filter state is reinitialized.  This function does not reset any seccomp
     * filters already loaded into the kernel.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_reset(ctx: *mut scmp_filter_ctx, def_action: libc::uint32_t) -> libc::c_int;
    /**
     * Destroys the filter state and releases any resources
     *
     * @param ctx the filter context
     *
     * This functions destroys the given seccomp filter state and releases any
     * resources, including memory, associated with the filter state.  This
     * function does not reset any seccomp filters already loaded into the kernel.
     * The filter context can no longer be used after calling this function.
     *
     */
    pub fn seccomp_release(ctx: *mut scmp_filter_ctx);
    /**
     * Loads the filter into the kernel
     *
     * @param ctx the filter context
     *
     * This function loads the given seccomp filter context into the kernel.  If
     * the filter was loaded correctly, the kernel will be enforcing the filter
     * when this function returns.  Returns zero on success, negative values on
     * error.
     *
     */
    pub fn seccomp_load(ctx: *const scmp_filter_ctx) -> libc::c_int;

    /**
     * Get the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function fetches the value of the given attribute name and returns it
     * via @value.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_attr_get(ctx: *const scmp_filter_ctx,
                         attr: scmp_filter_attr, value: *mut libc::uint32_t) -> libc::c_int;

    /**
     * Set the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function sets the value of the given attribute.  Returns zero on
     * success, negative values on failure.
     *
     */
    pub fn seccomp_attr_set(ctx: *mut scmp_filter_ctx,
                         attr: scmp_filter_attr, value: libc::uint32_t) -> libc::c_int;

    /**
     * Set the priority of a given syscall
     *
     * @param ctx the filter context
     * @param syscall the syscall number
     * @param priority priority value, higher value == higher priority
     *
     * This function sets the priority of the given syscall; this value is used
     * when generating the seccomp filter code such that higher priority syscalls
     * will incur less filter code overhead than the lower priority syscalls in the
     * filter.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_syscall_priority(ctx: *mut scmp_filter_ctx,
                                 syscall: libc::c_int, priority: libc::uint8_t) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule needs to be adjusted due to architecture specifics it
     * will be adjusted without notification.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_rule_add(ctx: *mut scmp_filter_ctx,
                         action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule can not be represented on the architecture the
     * function will fail.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_rule_add_exact(ctx: *mut scmp_filter_ctx, action: libc::uint32_t,
                               syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Generate seccomp Pseudo Filter Code (PFC) and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Pseudo Filter Code (PFC) and writes it to
     * the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_pfc(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;

    /**
     * Generate seccomp Berkley Packet Filter (BPF) code and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Berkley Packer Filter (BPF) code and writes
     * it to the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_bpf(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;
}

#[test]
fn does_it_even_work() {
    unsafe {
        let context = seccomp_init(SCMP_ACT_ALLOW);
        let comparator = scmp_arg_cmp {
            arg: 0,
            op: scmp_compare::SCMP_CMP_EQ,
            datum_a: 1000,
            datum_b: 0,
        };
        assert!(seccomp_rule_add(context, SCMP_ACT_KILL, 105, 1, comparator) == 0);
        assert!(seccomp_load(context) == 0);
        //assert!(libc::setuid(1000) == 0);
    }
}
<commit_msg>Add errno & trace actions<commit_after>extern crate libc;
/*
 * seccomp actions
 */
#[allow(non_camel_case_types)]
pub type scmp_filter_ctx = libc::c_void;

/**
 * Kill the process
 */
pub const SCMP_ACT_KILL: u32  = 0x00000000;
/**
 * Throw a SIGSYS signal
 */
pub const SCMP_ACT_TRAP: u32 = 0x00030000;
/**
 * Return the specified error code
 */
#[allow(non_snake_case)]
pub fn SCMP_ACT_ERRNO(x: u32) -> u32 { 0x00050000 | ((x) & 0x0000ffff) }
/**
 * Notify a tracing process with the specified value
 */
#[allow(non_snake_case)]
pub fn SCMP_ACT_TRACE(x: u32) -> u32 { 0x7ff00000 | ((x) & 0x0000ffff) }
/**
 * Allow the syscall to be executed
 */
pub const SCMP_ACT_ALLOW: u32 = 0x7fff0000;

/**
 * Filter attributes
 */
#[repr(C)]
pub enum scmp_filter_attr {
    _SCMP_FLTATR_MIN,
    SCMP_FLTATR_ACT_DEFAULT, /**< default filter action */
    SCMP_FLTATR_ACT_BADARCH, /**< bad architecture action */
    SCMP_FLTATR_CTL_NNP, /**< set NO_NEW_PRIVS on filter load */
    _SCMP_FLTATR_MAX,
}

/**
 * Comparison operators
 */
#[repr(C)]
pub enum scmp_compare {
        _SCMP_CMP_MIN = 0,
        SCMP_CMP_NE = 1,                /**< not equal */
        SCMP_CMP_LT = 2,                /**< less than */
        SCMP_CMP_LE = 3,                /**< less than or equal */
        SCMP_CMP_EQ = 4,                /**< equal */
        SCMP_CMP_GE = 5,                /**< greater than or equal */
        SCMP_CMP_GT = 6,                /**< greater than */
        SCMP_CMP_MASKED_EQ = 7,         /**< masked equality */
        _SCMP_CMP_MAX,
}

/**
 * Argument datum
 */
#[allow(non_camel_case_types)]
pub type scmp_datum_t = libc::uint64_t;

/**
 * Argument / Value comparison definition
 */
#[repr(C)]
pub struct scmp_arg_cmp {
        pub arg: libc::c_uint,        /**< argument number, starting at 0 */
        pub op: scmp_compare,       /**< the comparison op, e.g. SCMP_CMP_* */
        pub datum_a: scmp_datum_t,
        pub datum_b: scmp_datum_t,
}

#[link(name = "seccomp")]
extern {
    /**
     * Initialize the filter state
     *
     * @param def_action the default filter action
     *
     * This function initializes the internal seccomp filter state and should
     * be called before any other functions in this library to ensure the filter
     * state is initialized.  Returns a filter context on success, NULL on failure.
     *
     */
    pub fn seccomp_init(def_action: libc::uint32_t) -> *mut scmp_filter_ctx;
    /**
     * Reset the filter state
     *
     * @param ctx the filter context
     * @param def_action the default filter action
     *
     * This function resets the given seccomp filter state and ensures the
     * filter state is reinitialized.  This function does not reset any seccomp
     * filters already loaded into the kernel.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_reset(ctx: *mut scmp_filter_ctx, def_action: libc::uint32_t) -> libc::c_int;
    /**
     * Destroys the filter state and releases any resources
     *
     * @param ctx the filter context
     *
     * This functions destroys the given seccomp filter state and releases any
     * resources, including memory, associated with the filter state.  This
     * function does not reset any seccomp filters already loaded into the kernel.
     * The filter context can no longer be used after calling this function.
     *
     */
    pub fn seccomp_release(ctx: *mut scmp_filter_ctx);
    /**
     * Loads the filter into the kernel
     *
     * @param ctx the filter context
     *
     * This function loads the given seccomp filter context into the kernel.  If
     * the filter was loaded correctly, the kernel will be enforcing the filter
     * when this function returns.  Returns zero on success, negative values on
     * error.
     *
     */
    pub fn seccomp_load(ctx: *const scmp_filter_ctx) -> libc::c_int;

    /**
     * Get the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function fetches the value of the given attribute name and returns it
     * via @value.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_attr_get(ctx: *const scmp_filter_ctx,
                         attr: scmp_filter_attr, value: *mut libc::uint32_t) -> libc::c_int;

    /**
     * Set the value of a filter attribute
     *
     * @param ctx the filter context
     * @param attr the filter attribute name
     * @param value the filter attribute value
     *
     * This function sets the value of the given attribute.  Returns zero on
     * success, negative values on failure.
     *
     */
    pub fn seccomp_attr_set(ctx: *mut scmp_filter_ctx,
                         attr: scmp_filter_attr, value: libc::uint32_t) -> libc::c_int;

    /**
     * Set the priority of a given syscall
     *
     * @param ctx the filter context
     * @param syscall the syscall number
     * @param priority priority value, higher value == higher priority
     *
     * This function sets the priority of the given syscall; this value is used
     * when generating the seccomp filter code such that higher priority syscalls
     * will incur less filter code overhead than the lower priority syscalls in the
     * filter.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_syscall_priority(ctx: *mut scmp_filter_ctx,
                                 syscall: libc::c_int, priority: libc::uint8_t) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule needs to be adjusted due to architecture specifics it
     * will be adjusted without notification.  Returns zero on success, negative
     * values on failure.
     *
     */
    pub fn seccomp_rule_add(ctx: *mut scmp_filter_ctx,
                         action: libc::uint32_t, syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Add a new rule to the filter
     *
     * @param ctx the filter context
     * @param action the filter action
     * @param syscall the syscall number
     * @param arg_cnt the number of argument filters in the argument filter chain
     * @param ... scmp_arg_cmp structs (use of SCMP_ARG_CMP() recommended)
     *
     * This function adds a series of new argument/value checks to the seccomp
     * filter for the given syscall; multiple argument/value checks can be
     * specified and they will be chained together (AND'd together) in the filter.
     * If the specified rule can not be represented on the architecture the
     * function will fail.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_rule_add_exact(ctx: *mut scmp_filter_ctx, action: libc::uint32_t,
                               syscall: libc::c_int, arg_cnt: libc::c_uint, ...) -> libc::c_int;

    /**
     * Generate seccomp Pseudo Filter Code (PFC) and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Pseudo Filter Code (PFC) and writes it to
     * the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_pfc(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;

    /**
     * Generate seccomp Berkley Packet Filter (BPF) code and export it to a file
     *
     * @param ctx the filter context
     * @param fd the destination fd
     *
     * This function generates seccomp Berkley Packer Filter (BPF) code and writes
     * it to the given fd.  Returns zero on success, negative values on failure.
     *
     */
    pub fn seccomp_export_bpf(ctx: *const scmp_filter_ctx, fd: libc::c_int) -> libc::c_int;
}

#[test]
fn does_it_even_work() {
    unsafe {
        let context = seccomp_init(SCMP_ACT_ALLOW);
        let comparator = scmp_arg_cmp {
            arg: 0,
            op: scmp_compare::SCMP_CMP_EQ,
            datum_a: 1000,
            datum_b: 0,
        };
        assert!(seccomp_rule_add(context, SCMP_ACT_KILL, 105, 1, comparator) == 0);
        assert!(seccomp_load(context) == 0);
        //assert!(libc::setuid(1000) == 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate num_traits;

pub mod checkers;
pub mod types;
mod float_impl;

pub mod prelude {
    pub use types::*;

    pub use num_traits::Float;
    pub use num_traits::cast::{ToPrimitive, NumCast};
}

use std::marker::PhantomData;
use std::fmt;
use num_traits::Float;

//FIXME add doc comments
//FIXME proofread rustdocs, make sure the impls from float_impl are included

pub trait FloatChecker<F> {
    fn assert(value: F);
    fn check(value: F) -> bool;
}

pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
    value: F,
    checker: PhantomData<C>
}

//note: not implementing From<F>, because From conversion is never supposed to fail, according to the docs
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
    #[inline]
    pub fn new(value: F) -> NoisyFloat<F, C> {
        C::assert(value);
        Self::unchecked_new(value)
    }

    #[inline]
    fn unchecked_new(value: F) -> NoisyFloat<F, C> {
        NoisyFloat {
            value: value,
            checker: PhantomData
        }
    }

    #[inline]
    pub fn try_new(value: F) -> Option<NoisyFloat<F, C>> {
        if C::check(value) {
            Some(NoisyFloat {
                value: value,
                checker: PhantomData
            })
        } else {
            None
        }
    }

    #[inline]
    pub fn raw(self) -> F {
        self.value
    }
}

impl<C: FloatChecker<f32>> Into<f32> for NoisyFloat<f32, C> {
    #[inline]
    fn into(self) -> f32 {
        self.value
    }
}

impl<C: FloatChecker<f64>> Into<f64> for NoisyFloat<f64, C> {
    #[inline]
    fn into(self) -> f64 {
        self.value
    }
}

impl<F: Float + fmt::Debug, C: FloatChecker<F>> fmt::Debug for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Debug::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::Display, C: FloatChecker<F>> fmt::Display for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::LowerExp, C: FloatChecker<F>> fmt::LowerExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::LowerExp::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::UpperExp, C: FloatChecker<F>> fmt::UpperExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::UpperExp::fmt(&self.value, f)
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use std::f32;
    use std::f64::{self, consts};

    #[test]
    fn smoke_test() {
        assert!(n64(1.0) + n64(2.0) == n64(3.0));
        assert!(n64(3.0) != n64(2.9));
        assert!(r64(1.0) < r64(2.0));
        let mut value = n64(18.0);
        value %= n64(5.0);
        assert!(-value == n64(-3.0));
        assert!(r64(1.0).exp() == r64(consts::E));
        assert!((N64::try_new(1.0).unwrap() / N64::infinity()) == n64(0.0));
        assert!(NumCast::from(f32::INFINITY) == N64::try_new(f64::INFINITY));
        assert!(R64::try_new(f64::NEG_INFINITY) == None);
        assert!(N64::try_new(f64::NAN) == None);
        assert!(R64::try_new(f64::NAN) == None);
    }

    #[test]
    #[should_panic]
    fn n64_nan() {
        n64(0.0) / n64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_nan() {
        r64(0.0) / r64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_infinity() {
        r64(1.0) / r64(0.0);
    }
}
<commit_msg>working on documentation...<commit_after>// Copyright 2016 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This crate contains floating point types that panic if they are set
//! to an illegal value, such as NaN.
//!
//! The name "Noisy Float" comes from
//! the terms "quiet NaN" and "signaling NaN"; "signaling" was too long
//! to put in a struct/crate name, so "noisy" is used instead, being the opposite
//! of "quiet."
//!
//! The standard types defined in `noisy_float::types` follow the principle
//! demonstrated by Rust's handling of integer overflow:
//! a bad arithmetic operation is considered an error,
//! but it is too costly to check everywhere in optimized builds.
//! For each floating point value that is created, a `debug_assert!` invocation is used
//! to check if it is valid or not.
//! This way, there are guarantees when developing code that floating point
//! numbers have valid values,
//! but during a release run there is *no overhead* for using these floating
//! point types compared to using `f32` or `f64` directly.
//!
//! This crate makes use of the floating point and number traits in the
//! popular `num_traits` crate.
//!
//! #Examples
//! An example using the `R64` type, which corresponds to *finite* `f64` values.
//!
//! ```
//! use noisy_float::prelude::*;
//!
//! fn geometric_mean(a: R64, b: R64) -> R64 {
//!     (a * b).sqrt() //used just like regular floating-point numbers
//! }
//!
//! println!("geometric_mean(10.0, 20.0) = {}", geometric_mean(r64(10.0), r64(20.0)));
//! //prints 14.142...
//! ```
//!
//! An example using the `N32` type, which corresponds to *non-NaN* `f32` values.
//! The float types in this crate are able to implement `Eq` and `Ord` properly,
//! since NaN is not allowed.
//!
//! ```
//! use noisy_float::prelude::*;
//!
//! let values = vec![n32(3.0), n32(-1.5), n32(71.3), N32::infinity()];
//! assert!(values.iter().cloned().min() == Some(n32(-1.5)));
//! assert!(values.iter().cloned().max() == Some(N32::infinity()));
//! ```

extern crate num_traits;

pub mod checkers;
pub mod types;
mod float_impl;

/// Prelude for the `noisy_float` crate.
///
/// This includes all of the types defined in the `noisy_float::types` module,
/// as well as re-exports of traits from the `num_traits` crate.
/// It is important to have these re-exports here, because they allow the user
/// to access common floating point methods like `abs()`, `sqrt()`, etc.
pub mod prelude {
    pub use types::*;

    pub use num_traits::Float;
    pub use num_traits::cast::{ToPrimitive, NumCast};
}

use std::marker::PhantomData;
use std::fmt;
use num_traits::Float;

/// Trait for checking whether a floating point value is *valid*.
///
/// The implementation defines its own criteria for what constitutes a *valid* value.
pub trait FloatChecker<F> {
    /// Returns `true` if (and only if) the given floating point value is *valid*
    /// according to this checker's criteria.  The only hard requirement is that NaN *must* be considered *invalid*
    /// for all implementations of `FloatChecker`.
    fn check(value: F) -> bool;

    /// A function that may panic if the floating point value is *invalid*.
    /// Should either call `assert!(check(value), ...)` or `debug_assert!(check(value), ...)`.
    fn assert(value: F);
}

//FIXME: finish documenting

pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
    value: F,
    checker: PhantomData<C>
}

//note: not implementing From<F>, because From conversion is never supposed to fail, according to the docs
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
    #[inline]
    pub fn new(value: F) -> NoisyFloat<F, C> {
        C::assert(value);
        Self::unchecked_new(value)
    }

    #[inline]
    fn unchecked_new(value: F) -> NoisyFloat<F, C> {
        NoisyFloat {
            value: value,
            checker: PhantomData
        }
    }

    #[inline]
    pub fn try_new(value: F) -> Option<NoisyFloat<F, C>> {
        if C::check(value) {
            Some(NoisyFloat {
                value: value,
                checker: PhantomData
            })
        } else {
            None
        }
    }

    #[inline]
    pub fn raw(self) -> F {
        self.value
    }
}

/// Note: due to complications with Rust's type system, cannot implement `Into` generically like
/// `impl<F: Float, C: FloatChecker<F>> Into<F> for NoisyFloat<F, C>`.
impl<C: FloatChecker<f32>> Into<f32> for NoisyFloat<f32, C> {
    #[inline]
    fn into(self) -> f32 {
        self.value
    }
}

/// Note: due to complications with Rust's type system, cannot implement `Into` generically like
/// `impl<F: Float, C: FloatChecker<F>> Into<F> for NoisyFloat<F, C>`.
impl<C: FloatChecker<f64>> Into<f64> for NoisyFloat<f64, C> {
    #[inline]
    fn into(self) -> f64 {
        self.value
    }
}

impl<F: Float + fmt::Debug, C: FloatChecker<F>> fmt::Debug for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Debug::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::Display, C: FloatChecker<F>> fmt::Display for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::LowerExp, C: FloatChecker<F>> fmt::LowerExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::LowerExp::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::UpperExp, C: FloatChecker<F>> fmt::UpperExp for NoisyFloat<F, C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::UpperExp::fmt(&self.value, f)
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use std::f32;
    use std::f64::{self, consts};

    #[test]
    fn smoke_test() {
        assert!(n64(1.0) + n64(2.0) == n64(3.0));
        assert!(n64(3.0) != n64(2.9));
        assert!(r64(1.0) < r64(2.0));
        let mut value = n64(18.0);
        value %= n64(5.0);
        assert!(-value == n64(-3.0));
        assert!(r64(1.0).exp() == r64(consts::E));
        assert!((N64::try_new(1.0).unwrap() / N64::infinity()) == n64(0.0));
        assert!(NumCast::from(f32::INFINITY) == N64::try_new(f64::INFINITY));
        assert!(R64::try_new(f64::NEG_INFINITY) == None);
        assert!(N64::try_new(f64::NAN) == None);
        assert!(R64::try_new(f64::NAN) == None);
    }

    #[test]
    #[should_panic]
    fn n64_nan() {
        n64(0.0) / n64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_nan() {
        r64(0.0) / r64(0.0);
    }

    #[test]
    #[should_panic]
    fn r64_infinity() {
        r64(1.0) / r64(0.0);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Bincode is a crate for encoding and decoding using a tiny binary
//! serialization strategy.  Using it, you can easily go from having
//! an object in memory, quickly serialize it to bytes, and then
//! deserialize it back just as fast!
//!
//! ### Using Basic Functions
//!
//! ```rust
//! extern crate bincode;
//! use bincode::{serialize, deserialize};
//! fn main() {
//!     // The object that we will serialize.
//!     let target: Option<String>  = Some("hello world".to_string());
//!
//!     let encoded: Vec<u8>        = serialize(&target).unwrap();
//!     let decoded: Option<String> = deserialize(&encoded[..]).unwrap();
//!     assert_eq!(target, decoded);
//! }
//! ```
//!
//! ### 128bit numbers
//!
//! Support for `i128` and `u128` on Rust toolchains after `1.26.0` is
//! enabled through the `i128` feature. Add the following to your
//! `Cargo.toml`:
//!
//! ```toml,ignore
//! [dependencies.bincode]
//! features = ["i128"]
//! ```

#![crate_name = "bincode"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

extern crate byteorder;
#[macro_use]
extern crate serde;

mod config;
mod de;
mod error;
mod internal;
mod ser;

pub use config::Config;
pub use de::read::{BincodeRead, IoReader, SliceReader};
pub use error::{Error, ErrorKind, Result};

/// An object that implements this trait can be passed a
/// serde::Deserializer without knowing its concrete type.
///
/// This trait should be used only for `with_deserializer` functions.
#[doc(hidden)]
pub trait DeserializerAcceptor<'a> {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Deserializer and do whatever you want with it.
    fn accept<T: serde::Deserializer<'a>>(self, T) -> Self::Output;
}

/// An object that implements this trait can be passed a
/// serde::Serializer without knowing its concrete type.
///
/// This trait should be used only for `with_serializer` functions.
#[doc(hidden)]
pub trait SerializerAcceptor {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Serializer and do whatever you want with it.
    fn accept<T: serde::Serializer>(self, T) -> Self::Output;
}

/// Get a default configuration object.
///
/// ### Default Configuration:
///
/// | Byte limit | Endianness |
/// |------------|------------|
/// | Unlimited  | Little     |
pub fn config() -> Config {
    Config::new()
}

/// Serializes an object directly into a `Writer` using the default configuration.
///
/// If the serialization would take more bytes than allowed by the size limit, an error
/// is returned and *no bytes* will be written into the `Writer`.
pub fn serialize_into<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
    W: std::io::Write,
    T: serde::Serialize,
{
    config().serialize_into(writer, value)
}

/// Serializes a serializable object into a `Vec` of bytes using the default configuration.
pub fn serialize<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: serde::Serialize,
{
    config().serialize(value)
}

/// Deserializes an object directly from a `Read`er using the default configuration.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from<R, T>(reader: R) -> Result<T>
where
    R: std::io::Read,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from(reader)
}

/// Deserializes an object from a custom `BincodeRead`er using the default configuration.
/// It is highly recommended to use `deserialize_from` unless you need to implement
/// `BincodeRead` for performance reasons.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result<T>
where
    R: de::read::BincodeRead<'a>,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from_custom(reader)
}

/// Only use this if you know what you're doing.
///
/// This is part of the public API.
#[doc(hidden)]
pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()>
where
    T: serde::de::Deserialize<'a>,
    R: BincodeRead<'a>,
{
    config().deserialize_in_place(reader, place)
}

/// Deserializes a slice of bytes into an instance of `T` using the default configuration.
pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result<T>
where
    T: serde::de::Deserialize<'a>,
{
    config().deserialize(bytes)
}

/// Returns the size that an object would be if serialized using Bincode with the default configuration.
pub fn serialized_size<T: ?Sized>(value: &T) -> Result<u64>
where
    T: serde::Serialize,
{
    config().serialized_size(value)
}

/// Executes the acceptor with a serde::Deserializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_deserializer<'a, A, R>(reader: R, acceptor: A) -> A::Output
where
    A: DeserializerAcceptor<'a>,
    R: BincodeRead<'a>,
{
    config().with_deserializer(reader, acceptor)
}

/// Executes the acceptor with a serde::Serializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_serializer<A, W>(writer: W, acceptor: A) -> A::Output
where
    A: SerializerAcceptor,
    W: std::io::Write,
{
    config().with_serializer(writer, acceptor)
}
<commit_msg>Make config() inline(always)<commit_after>#![deny(missing_docs)]

//! Bincode is a crate for encoding and decoding using a tiny binary
//! serialization strategy.  Using it, you can easily go from having
//! an object in memory, quickly serialize it to bytes, and then
//! deserialize it back just as fast!
//!
//! ### Using Basic Functions
//!
//! ```rust
//! extern crate bincode;
//! use bincode::{serialize, deserialize};
//! fn main() {
//!     // The object that we will serialize.
//!     let target: Option<String>  = Some("hello world".to_string());
//!
//!     let encoded: Vec<u8>        = serialize(&target).unwrap();
//!     let decoded: Option<String> = deserialize(&encoded[..]).unwrap();
//!     assert_eq!(target, decoded);
//! }
//! ```
//!
//! ### 128bit numbers
//!
//! Support for `i128` and `u128` on Rust toolchains after `1.26.0` is
//! enabled through the `i128` feature. Add the following to your
//! `Cargo.toml`:
//!
//! ```toml,ignore
//! [dependencies.bincode]
//! features = ["i128"]
//! ```

#![crate_name = "bincode"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

extern crate byteorder;
#[macro_use]
extern crate serde;

mod config;
mod de;
mod error;
mod internal;
mod ser;

pub use config::Config;
pub use de::read::{BincodeRead, IoReader, SliceReader};
pub use error::{Error, ErrorKind, Result};

/// An object that implements this trait can be passed a
/// serde::Deserializer without knowing its concrete type.
///
/// This trait should be used only for `with_deserializer` functions.
#[doc(hidden)]
pub trait DeserializerAcceptor<'a> {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Deserializer and do whatever you want with it.
    fn accept<T: serde::Deserializer<'a>>(self, T) -> Self::Output;
}

/// An object that implements this trait can be passed a
/// serde::Serializer without knowing its concrete type.
///
/// This trait should be used only for `with_serializer` functions.
#[doc(hidden)]
pub trait SerializerAcceptor {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Serializer and do whatever you want with it.
    fn accept<T: serde::Serializer>(self, T) -> Self::Output;
}

/// Get a default configuration object.
///
/// ### Default Configuration:
///
/// | Byte limit | Endianness |
/// |------------|------------|
/// | Unlimited  | Little     |
#[inline(always)]
pub fn config() -> Config {
    Config::new()
}

/// Serializes an object directly into a `Writer` using the default configuration.
///
/// If the serialization would take more bytes than allowed by the size limit, an error
/// is returned and *no bytes* will be written into the `Writer`.
pub fn serialize_into<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
    W: std::io::Write,
    T: serde::Serialize,
{
    config().serialize_into(writer, value)
}

/// Serializes a serializable object into a `Vec` of bytes using the default configuration.
pub fn serialize<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: serde::Serialize,
{
    config().serialize(value)
}

/// Deserializes an object directly from a `Read`er using the default configuration.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from<R, T>(reader: R) -> Result<T>
where
    R: std::io::Read,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from(reader)
}

/// Deserializes an object from a custom `BincodeRead`er using the default configuration.
/// It is highly recommended to use `deserialize_from` unless you need to implement
/// `BincodeRead` for performance reasons.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result<T>
where
    R: de::read::BincodeRead<'a>,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from_custom(reader)
}

/// Only use this if you know what you're doing.
///
/// This is part of the public API.
#[doc(hidden)]
pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()>
where
    T: serde::de::Deserialize<'a>,
    R: BincodeRead<'a>,
{
    config().deserialize_in_place(reader, place)
}

/// Deserializes a slice of bytes into an instance of `T` using the default configuration.
pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result<T>
where
    T: serde::de::Deserialize<'a>,
{
    config().deserialize(bytes)
}

/// Returns the size that an object would be if serialized using Bincode with the default configuration.
pub fn serialized_size<T: ?Sized>(value: &T) -> Result<u64>
where
    T: serde::Serialize,
{
    config().serialized_size(value)
}

/// Executes the acceptor with a serde::Deserializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_deserializer<'a, A, R>(reader: R, acceptor: A) -> A::Output
where
    A: DeserializerAcceptor<'a>,
    R: BincodeRead<'a>,
{
    config().with_deserializer(reader, acceptor)
}

/// Executes the acceptor with a serde::Serializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_serializer<A, W>(writer: W, acceptor: A) -> A::Output
where
    A: SerializerAcceptor,
    W: std::io::Write,
{
    config().with_serializer(writer, acceptor)
}
<|endoftext|>


<commit_before>//! A minimal implementation of SHA1 for rust.
//!
//! Example:
//!
//! ```rust
//! extern crate sha1;
//! # fn main() {
//!
//! let mut m = sha1::Sha1::new();
//! m.update("Hello World!".as_bytes());
//! assert_eq!(m.hexdigest().as_slice(),
//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
//! # }
//! ```

#![feature(core, collections, old_io)]
#![unstable]

use std::old_io::BufWriter;

/// Represents a Sha1 hash object in memory.
#[derive(Clone)]
pub struct Sha1 {
    state: [u32; 5],
    data: Vec<u8>,
    len: u64,
}

const DEFAULT_STATE : [u32; 5] =
    [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];

fn to_hex(input: &[u8]) -> String {
    let mut s = String::new();
    for b in input.iter() {
        s.push_str(&format!("{:02x}", *b));
    }
    return s;
}

impl Sha1 {

    /// Creates an fresh sha1 hash object.
    pub fn new() -> Sha1 {
        Sha1 {
            state: DEFAULT_STATE,
            data: Vec::new(),
            len: 0,
        }
    }

    fn process_block(&mut self, block: &[u8]) {
        assert_eq!(block.len(), 64);

        let mut words = [0u32; 80];
        for (i, chunk) in block.chunks(4).enumerate() {
            words[i] = (chunk[3] as u32) |
                       ((chunk[2] as u32) << 8) |
                       ((chunk[1] as u32) << 16) |
                       ((chunk[0] as u32) << 24);
        }

        fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) }
        fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }
        fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) }
        fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }

        fn left_rotate(x: u32, n: u32) -> u32 { (x << n as usize) | (x >> (32 - n) as usize) }

        for i in range(16, 80) {
            let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16];
            words[i] = left_rotate(n, 1);
        }

        let mut a = self.state[0];
        let mut b = self.state[1];
        let mut c = self.state[2];
        let mut d = self.state[3];
        let mut e = self.state[4];

        for i in range(0, 80) {
            let (f, k) = match i {
                0 ... 19 => (ff(b, c, d), 0x5a827999),
                20 ... 39 => (gg(b, c, d), 0x6ed9eba1),
                40 ... 59 => (hh(b, c, d), 0x8f1bbcdc),
                60 ... 79 => (ii(b, c, d), 0xca62c1d6),
                _ => (0, 0),
            };

            let tmp = left_rotate(a, 5)
                .wrapping_add(f)
                .wrapping_add(e)
                .wrapping_add(k)
                .wrapping_add(words[i]);
            e = d;
            d = c;
            c = left_rotate(b, 30);
            b = a;
            a = tmp;
        }

        self.state[0] = self.state[0].wrapping_add(a);
        self.state[1] = self.state[1].wrapping_add(b);
        self.state[2] = self.state[2].wrapping_add(c);
        self.state[3] = self.state[3].wrapping_add(d);
        self.state[4] = self.state[4].wrapping_add(e);
    }

    /// Resets the hash object to it's initial state.
    pub fn reset(&mut self) {
        self.state = DEFAULT_STATE;
        self.data.clear();
        self.len = 0;
    }

    /// Update hash with input data.
    pub fn update(&mut self, data: &[u8]) {
        let mut d = self.data.clone();
        self.data.clear();

        d.push_all(data);

        for chunk in d.chunks(64) {
            self.len += chunk.len() as u64;

            if chunk.len() == 64 {
                self.process_block(chunk);
            } else {
                self.data.push_all(chunk);
            }
        }
    }

    /// Retrieve digest result.  The output must be large enough to
    /// contain result (20 bytes).
    pub fn output(&self, out: &mut [u8]) {
        // these are unlikely to fail, since we're writing to memory
        #![allow(unused_must_use)]

        let mut m = Sha1 {
            state: self.state,
            data: Vec::new(),
            len: 0,
        };

        let mut w : Vec<u8> = Vec::new();
        w.write_all(&self.data);
        w.write_u8(0x80 as u8);
        let padding = (((56 - self.len as isize - 1) % 64) + 64) % 64;
        for _ in range(0, padding) {
            w.write_u8(0u8);
        }

        w.write_be_u64(self.len * 8);
        for chunk in w.chunks(64) {
            m.process_block(chunk);
        }

        let mut w = BufWriter::new(out);
        for &n in m.state.iter() {
            w.write_be_u32(n);
        }
    }

    /// Shortcut for getting `output` into a new vector.
    pub fn digest(&self) -> Vec<u8> {
        let mut buf = [0u8; 20].to_vec();
        self.output(&mut buf);
        buf
    }

    /// Shortcut for getting a hex output of the vector.
    pub fn hexdigest(&self) -> String {
        to_hex(&self.digest())
    }
}

#[test]
fn test_simple() {
    let mut m = Sha1::new();

    let tests = [
        ("The quick brown fox jumps over the lazy dog",
         "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
        ("The quick brown fox jumps over the lazy cog",
         "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
        ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
        ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
        ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
         "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
    ];

    for &(s, ref h) in tests.iter() {
        let data = s.as_bytes();

        m.reset();
        m.update(data);
        let hh = m.hexdigest();

        assert_eq!(hh.len(), h.len());
		assert_eq!(hh, *h);
    }
}
<commit_msg>Use inbuilt left rotate<commit_after>//! A minimal implementation of SHA1 for rust.
//!
//! Example:
//!
//! ```rust
//! extern crate sha1;
//! # fn main() {
//!
//! let mut m = sha1::Sha1::new();
//! m.update("Hello World!".as_bytes());
//! assert_eq!(m.hexdigest().as_slice(),
//!            "2ef7bde608ce5404e97d5f042f95f89f1c232871");
//! # }
//! ```

#![feature(core, collections, old_io)]
#![unstable]

use std::old_io::BufWriter;
use std::num::Int;

/// Represents a Sha1 hash object in memory.
#[derive(Clone)]
pub struct Sha1 {
    state: [u32; 5],
    data: Vec<u8>,
    len: u64,
}

const DEFAULT_STATE : [u32; 5] =
    [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];

fn to_hex(input: &[u8]) -> String {
    let mut s = String::new();
    for b in input.iter() {
        s.push_str(&format!("{:02x}", *b));
    }
    return s;
}

impl Sha1 {

    /// Creates an fresh sha1 hash object.
    pub fn new() -> Sha1 {
        Sha1 {
            state: DEFAULT_STATE,
            data: Vec::new(),
            len: 0,
        }
    }

    fn process_block(&mut self, block: &[u8]) {
        assert_eq!(block.len(), 64);

        let mut words = [0u32; 80];
        for (i, chunk) in block.chunks(4).enumerate() {
            words[i] = (chunk[3] as u32) |
                       ((chunk[2] as u32) << 8) |
                       ((chunk[1] as u32) << 16) |
                       ((chunk[0] as u32) << 24);
        }

        fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) }
        fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }
        fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) }
        fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }

        for i in range(16, 80) {
            let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16];
            words[i] = n.rotate_left(1);
        }

        let mut a = self.state[0];
        let mut b = self.state[1];
        let mut c = self.state[2];
        let mut d = self.state[3];
        let mut e = self.state[4];

        for i in range(0, 80) {
            let (f, k) = match i {
                0 ... 19 => (ff(b, c, d), 0x5a827999),
                20 ... 39 => (gg(b, c, d), 0x6ed9eba1),
                40 ... 59 => (hh(b, c, d), 0x8f1bbcdc),
                60 ... 79 => (ii(b, c, d), 0xca62c1d6),
                _ => (0, 0),
            };

            let tmp = a.rotate_left(5)
                .wrapping_add(f)
                .wrapping_add(e)
                .wrapping_add(k)
                .wrapping_add(words[i]);
            e = d;
            d = c;
            c = b.rotate_left(30);
            b = a;
            a = tmp;
        }

        self.state[0] = self.state[0].wrapping_add(a);
        self.state[1] = self.state[1].wrapping_add(b);
        self.state[2] = self.state[2].wrapping_add(c);
        self.state[3] = self.state[3].wrapping_add(d);
        self.state[4] = self.state[4].wrapping_add(e);
    }

    /// Resets the hash object to it's initial state.
    pub fn reset(&mut self) {
        self.state = DEFAULT_STATE;
        self.data.clear();
        self.len = 0;
    }

    /// Update hash with input data.
    pub fn update(&mut self, data: &[u8]) {
        let mut d = self.data.clone();
        self.data.clear();

        d.push_all(data);

        for chunk in d.chunks(64) {
            self.len += chunk.len() as u64;

            if chunk.len() == 64 {
                self.process_block(chunk);
            } else {
                self.data.push_all(chunk);
            }
        }
    }

    /// Retrieve digest result.  The output must be large enough to
    /// contain result (20 bytes).
    pub fn output(&self, out: &mut [u8]) {
        // these are unlikely to fail, since we're writing to memory
        #![allow(unused_must_use)]

        let mut m = Sha1 {
            state: self.state,
            data: Vec::new(),
            len: 0,
        };

        let mut w : Vec<u8> = Vec::new();
        w.write_all(&self.data);
        w.write_u8(0x80 as u8);
        let padding = (((56 - self.len as isize - 1) % 64) + 64) % 64;
        for _ in range(0, padding) {
            w.write_u8(0u8);
        }

        w.write_be_u64(self.len * 8);
        for chunk in w.chunks(64) {
            m.process_block(chunk);
        }

        let mut w = BufWriter::new(out);
        for &n in m.state.iter() {
            w.write_be_u32(n);
        }
    }

    /// Shortcut for getting `output` into a new vector.
    pub fn digest(&self) -> Vec<u8> {
        let mut buf = [0u8; 20].to_vec();
        self.output(&mut buf);
        buf
    }

    /// Shortcut for getting a hex output of the vector.
    pub fn hexdigest(&self) -> String {
        to_hex(&self.digest())
    }
}

#[test]
fn test_simple() {
    let mut m = Sha1::new();

    let tests = [
        ("The quick brown fox jumps over the lazy dog",
         "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
        ("The quick brown fox jumps over the lazy cog",
         "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
        ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
        ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
        ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
         "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
    ];

    for &(s, ref h) in tests.iter() {
        let data = s.as_bytes();

        m.reset();
        m.update(data);
        let hh = m.hexdigest();

        assert_eq!(hh.len(), h.len());
		assert_eq!(hh, *h);
    }
}
<|endoftext|>