<commit_before>use cocoa::base::id;
use std::convert::{From, Into};
use std::error::Error;
use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut};

/// A type which can be constructed from an Objective-C pointer.
pub trait FromRaw: Sized {
    /// Creates the object from the pointer. If there is a problem with the pointer,
    /// this function will return a FromRawError.
    fn from_raw(raw_pointer: id) -> Result<Self, FromRawError>;
}

/// A type which can be borrowed as an Objective-C pointer.
pub trait AsRaw {
    /// Get an immutable reference to the pointer.
    fn as_raw(&self) -> &id;

    /// Get a mutable reference to the pointer.
    fn as_raw_mut(&mut self) -> &mut id;
}

/// A type which can be converted into an Objective-C pointer.
pub trait IntoRaw {
    /// Get the underlying pointer to the object. Releases ownership.
    fn into_raw(self) -> id;
}

impl FromRaw for id {
    fn from_raw(ptr: id) -> Result<Self, FromRawError> {
        Ok(ptr)
    }
}

impl AsRaw for id {
    fn as_raw(&self) -> &id {
        self
    }

    fn as_raw_mut(&mut self) -> &mut id {
        self
    }
}

impl IntoRaw for id {
    fn into_raw(self) -> id {
        self
    }
}

/// An Objective-C pointer which sends the `release` message to its object on drop
#[derive(Eq, PartialEq)]
pub struct StrongPtr(id);

impl fmt::Debug for StrongPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "StrongPtr({:p})", self.0)
    }
}

impl fmt::Display for StrongPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(self, f)
    }
}

impl fmt::Pointer for StrongPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:p}", self.0)
    }
}

impl Deref for StrongPtr {
    type Target = id;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl AsRaw for StrongPtr {
    fn as_raw(&self) -> &id {
        self.deref()
    }

    fn as_raw_mut(&mut self) -> &mut id {
        self.deref_mut()
    }
}

impl IntoRaw for StrongPtr {
    fn into_raw(self) -> id {
        self.into()
    }
}

impl DerefMut for StrongPtr {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.0
    }
}

impl Drop for StrongPtr {
    fn drop(&mut self) {
        unsafe { msg_send![self.0, release] }
    }
}

impl From<id> for StrongPtr {
    fn from(ptr: id) -> Self {
        StrongPtr(ptr)
    }
}

impl Into<id> for StrongPtr {
    /// Get the underlying pointer from `Self`. The pointer will no longer be released on drop.
    fn into(self) -> id {
        let self_ptr = self.0;
        mem::forget(self);
        self_ptr
    }
}

/// Represents errors which may occur when constructing an object from a pointer.
#[derive(Clone, Debug)]
pub enum FromRawError {
    /// The pointer was nil.
    NilPointer,

    /// The pointer does not point to either:
    ///
    /// * an object of the correct type,
    /// * an object which does not have a certain base class,
    /// * an object which does not implement a particular protocol.
    WrongPointerType
}

macro_rules! impl_from_into_raw {
    ($wrapper_type:ident, of protocol $protocol:expr) => (
        impl $crate::FromRaw for $wrapper_type {
            fn from_raw(raw_pointer: id) -> Result<Self, $crate::FromRawError> {
                use $crate::internal::conforms_to_protocol;
                use cocoa::base::nil;
                if raw_pointer == nil {
                    Err($crate::FromRawError::NilPointer)
                } else if !conforms_to_protocol(raw_pointer, $protocol) {
                    Err($crate::FromRawError::WrongPointerType)
                } else {
                    Ok($wrapper_type(From::from(raw_pointer)))
                }
            }
        }

        impl $crate::AsRaw for $wrapper_type {
            fn as_raw(&self) -> &id {
                &self.0
            }

            fn as_raw_mut(&mut self) -> &mut id {
                &mut self.0
            }
        }

        impl $crate::IntoRaw for $wrapper_type {
            fn into_raw(self) -> id {
                self.0.into()
            }
        }
    );

    ($wrapper_type:ident, of class $class:expr) => (
        impl $crate::FromRaw for $wrapper_type {
            fn from_raw(raw_pointer: id) -> Result<Self, $crate::FromRawError> {
                use $crate::internal::is_kind_of_class;
                use cocoa::base::nil;
                if raw_pointer == nil {
                    Err($crate::FromRawError::NilPointer)
                } else if !is_kind_of_class(raw_pointer, $class) {
                    Err($crate::FromRawError::WrongPointerType)
                } else {
                    Ok($wrapper_type(From::from(raw_pointer)))
                }
            }
        }

        impl $crate::AsRaw for $wrapper_type {
            fn as_raw(&self) -> &id {
                &self.0
            }

            fn as_raw_mut(&mut self) -> &mut id {
                &mut self.0
            }
        }

        impl $crate::IntoRaw for $wrapper_type {
            fn into_raw(self) -> id {
                self.0.into()
            }
        }
    )
}

impl fmt::Display for FromRawError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let descr = match *self {
            FromRawError::NilPointer => "FromRawError::NilPointer",
            FromRawError::WrongPointerType => "FromRawError::WrongPointerType",
        };
        write!(f, "{}", descr)
    }
}

impl Error for FromRawError {
    fn description(&self) -> &str {
        match *self {
            FromRawError::NilPointer => "Attempted to create an object from nil",
            FromRawError::WrongPointerType => "The object pointer is not of the correct class",
        }
    }
}
<commit_msg>Some reordering of impl blocks for StrongPtr, and impl FromRaw for StrongPtr<commit_after>use cocoa::base::id;
use std::convert::{From, Into};
use std::error::Error;
use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut};

/// A type which can be constructed from an Objective-C pointer.
pub trait FromRaw: Sized {
    /// Creates the object from the pointer. If there is a problem with the pointer,
    /// this function will return a FromRawError.
    fn from_raw(raw_pointer: id) -> Result<Self, FromRawError>;
}

/// A type which can be borrowed as an Objective-C pointer.
pub trait AsRaw {
    /// Get an immutable reference to the pointer.
    fn as_raw(&self) -> &id;

    /// Get a mutable reference to the pointer.
    fn as_raw_mut(&mut self) -> &mut id;
}

/// A type which can be converted into an Objective-C pointer.
pub trait IntoRaw {
    /// Get the underlying pointer to the object. Releases ownership.
    fn into_raw(self) -> id;
}

impl FromRaw for id {
    fn from_raw(ptr: id) -> Result<Self, FromRawError> {
        Ok(ptr)
    }
}

impl AsRaw for id {
    fn as_raw(&self) -> &id {
        self
    }

    fn as_raw_mut(&mut self) -> &mut id {
        self
    }
}

impl IntoRaw for id {
    fn into_raw(self) -> id {
        self
    }
}

/// An Objective-C pointer which sends the `release` message to its object on drop
#[derive(Eq, PartialEq)]
pub struct StrongPtr(id);

impl fmt::Debug for StrongPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "StrongPtr({:p})", self.0)
    }
}

impl fmt::Display for StrongPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(self, f)
    }
}

impl fmt::Pointer for StrongPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:p}", self.0)
    }
}

impl Deref for StrongPtr {
    type Target = id;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for StrongPtr {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.0
    }
}

impl FromRaw for StrongPtr {
    fn from_raw(ptr: id) -> Result<Self, FromRawError> {
        Ok(From::from(ptr))
    }
}

impl AsRaw for StrongPtr {
    fn as_raw(&self) -> &id {
        self.deref()
    }

    fn as_raw_mut(&mut self) -> &mut id {
        self.deref_mut()
    }
}

impl IntoRaw for StrongPtr {
    fn into_raw(self) -> id {
        self.into()
    }
}

impl Drop for StrongPtr {
    fn drop(&mut self) {
        unsafe { msg_send![self.0, release] }
    }
}

impl From<id> for StrongPtr {
    fn from(ptr: id) -> Self {
        StrongPtr(ptr)
    }
}

impl Into<id> for StrongPtr {
    /// Get the underlying pointer from `Self`. The pointer will no longer be released on drop.
    fn into(self) -> id {
        let self_ptr = self.0;
        mem::forget(self);
        self_ptr
    }
}

/// Represents errors which may occur when constructing an object from a pointer.
#[derive(Clone, Debug)]
pub enum FromRawError {
    /// The pointer was nil.
    NilPointer,

    /// The pointer does not point to either:
    ///
    /// * an object of the correct type,
    /// * an object which does not have a certain base class,
    /// * an object which does not implement a particular protocol.
    WrongPointerType
}

macro_rules! impl_from_into_raw {
    ($wrapper_type:ident, of protocol $protocol:expr) => (
        impl $crate::FromRaw for $wrapper_type {
            fn from_raw(raw_pointer: id) -> Result<Self, $crate::FromRawError> {
                use $crate::internal::conforms_to_protocol;
                use cocoa::base::nil;
                if raw_pointer == nil {
                    Err($crate::FromRawError::NilPointer)
                } else if !conforms_to_protocol(raw_pointer, $protocol) {
                    Err($crate::FromRawError::WrongPointerType)
                } else {
                    Ok($wrapper_type(From::from(raw_pointer)))
                }
            }
        }

        impl $crate::AsRaw for $wrapper_type {
            fn as_raw(&self) -> &id {
                &self.0
            }

            fn as_raw_mut(&mut self) -> &mut id {
                &mut self.0
            }
        }

        impl $crate::IntoRaw for $wrapper_type {
            fn into_raw(self) -> id {
                self.0.into()
            }
        }
    );

    ($wrapper_type:ident, of class $class:expr) => (
        impl $crate::FromRaw for $wrapper_type {
            fn from_raw(raw_pointer: id) -> Result<Self, $crate::FromRawError> {
                use $crate::internal::is_kind_of_class;
                use cocoa::base::nil;
                if raw_pointer == nil {
                    Err($crate::FromRawError::NilPointer)
                } else if !is_kind_of_class(raw_pointer, $class) {
                    Err($crate::FromRawError::WrongPointerType)
                } else {
                    Ok($wrapper_type(From::from(raw_pointer)))
                }
            }
        }

        impl $crate::AsRaw for $wrapper_type {
            fn as_raw(&self) -> &id {
                &self.0
            }

            fn as_raw_mut(&mut self) -> &mut id {
                &mut self.0
            }
        }

        impl $crate::IntoRaw for $wrapper_type {
            fn into_raw(self) -> id {
                self.0.into()
            }
        }
    )
}

impl fmt::Display for FromRawError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let descr = match *self {
            FromRawError::NilPointer => "FromRawError::NilPointer",
            FromRawError::WrongPointerType => "FromRawError::WrongPointerType",
        };
        write!(f, "{}", descr)
    }
}

impl Error for FromRawError {
    fn description(&self) -> &str {
        match *self {
            FromRawError::NilPointer => "Attempted to create an object from nil",
            FromRawError::WrongPointerType => "The object pointer is not of the correct class",
        }
    }
}
<|endoftext|>


<commit_before>//! Exonum global variables which stored in blockchain as utf8 encoded json.

use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

/// Public keys of a validator.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

/// Exonum blockchain global configuration.
/// This configuration must be same for any exonum node in the certain network on given height.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    /// Link to the previous configuration.
    /// For configuration in genesis block `hash` is just an array of zeroes.
    pub previous_cfg_hash: Hash,
    /// The height, starting from which this configuration becomes actual.
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    /// Consensus algorithm parameters.
    pub consensus: ConsensusConfig,
    /// Services specific variables.
    /// Keys are `service_name` from `Service` trait and values are the serialized json.
    pub services: BTreeMap<String, serde_json::Value>,
}

/// Consensus algorithm parameters.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    /// Interval between rounds.
    pub round_timeout: Milliseconds,
    /// Period of sending a Status message.
    pub status_timeout: Milliseconds,
    /// Peer exchange timeout.
    pub peers_timeout: Milliseconds,
    /// Proposal timeout after committing a block.
    pub propose_timeout: Milliseconds,
    /// Maximum number of transactions per block.
    pub txs_block_limit: u32,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
        }
    }
}

impl StoredConfiguration {
    /// Tries to serialize given configuration into the utf8 encoded json.
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    /// Tries to deserialize `StorageConfiguration` from the given utf8 encoded json.
    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in &config.validator_keys {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom(
                    "Duplicated keys are found: each consensus and service key must be unique"));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn into_bytes(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn from_bytes(v: ::std::borrow::Cow<[u8]>) -> Self {
        StoredConfiguration::try_deserialize(v.as_ref()).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated validator keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4).map(|i| ValidatorKeys {
                consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
            }).collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<commit_msg>Fix test<commit_after>//! Exonum global variables which stored in blockchain as utf8 encoded json.

use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

/// Public keys of a validator.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

/// Exonum blockchain global configuration.
/// This configuration must be same for any exonum node in the certain network on given height.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    /// Link to the previous configuration.
    /// For configuration in genesis block `hash` is just an array of zeroes.
    pub previous_cfg_hash: Hash,
    /// The height, starting from which this configuration becomes actual.
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    /// Consensus algorithm parameters.
    pub consensus: ConsensusConfig,
    /// Services specific variables.
    /// Keys are `service_name` from `Service` trait and values are the serialized json.
    pub services: BTreeMap<String, serde_json::Value>,
}

/// Consensus algorithm parameters.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    /// Interval between rounds.
    pub round_timeout: Milliseconds,
    /// Period of sending a Status message.
    pub status_timeout: Milliseconds,
    /// Peer exchange timeout.
    pub peers_timeout: Milliseconds,
    /// Proposal timeout after committing a block.
    pub propose_timeout: Milliseconds,
    /// Maximum number of transactions per block.
    pub txs_block_limit: u32,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
        }
    }
}

impl StoredConfiguration {
    /// Tries to serialize given configuration into the utf8 encoded json.
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    /// Tries to deserialize `StorageConfiguration` from the given utf8 encoded json.
    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in &config.validator_keys {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom(
                    "Duplicated keys are found: each consensus and service key must be unique"));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn into_bytes(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn from_bytes(v: ::std::borrow::Cow<[u8]>) -> Self {
        StoredConfiguration::try_deserialize(v.as_ref()).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4).map(|i| ValidatorKeys {
                consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
            }).collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate cfg_if;
extern crate gcc;

use std::cmp::Ordering;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::iter;
use std::path::{Path, PathBuf};
use std::process::{self, Child, Command, Stdio};
use std::str;

cfg_if! {
    if #[cfg(feature = "v1_8_0")] {
        const TARGET_VERSION: &'static str = "1.8.0";
    } else if #[cfg(feature = "v1_7_1")] {
        const TARGET_VERSION: &'static str = "1.7.1";
    } else if #[cfg(feature = "v1_7_0")] {
        const TARGET_VERSION: &'static str = "1.7.0";
    } else if #[cfg(feature = "v1_6_0")] {
        const TARGET_VERSION: &'static str = "1.6.0";
    } else if #[cfg(feature = "v1_5_1")] {
        const TARGET_VERSION: &'static str = "1.5.1";
    } else if #[cfg(feature = "v1_5_0")] {
        const TARGET_VERSION: &'static str = "1.5.0";
    } else if #[cfg(feature = "v1_4_3")] {
        const TARGET_VERSION: &'static str = "1.4.3";
    } else if #[cfg(feature = "v1_4_2")] {
        const TARGET_VERSION: &'static str = "1.4.2";
    } else if #[cfg(feature = "v1_4_0")] {
        const TARGET_VERSION: &'static str = "1.4.0";
    } else if #[cfg(feature = "v1_3_1")] {
        const TARGET_VERSION: &'static str = "1.3.1";
    } else if #[cfg(feature = "v1_3_0")] {
        const TARGET_VERSION: &'static str = "1.3.0";
    } else {
        const TARGET_VERSION: &'static str = "1.2.0";
    }
}

fn main() {
    let path = env::var_os("GPGME_LIB_PATH");
    let libs = env::var_os("GPGME_LIBS");
    if path.is_some() || libs.is_some() {
        let mode = match env::var_os("GPGME_STATIC") {
            Some(_) => "static",
            _ => "dylib",
        };

        for path in path.iter().flat_map(env::split_paths) {
            println!("cargo:rustc-link-search=native={}", path.display());
        }
        match libs {
            Some(libs) => {
                for lib in env::split_paths(&libs) {
                    println!("cargo:rustc-link-lib={0}={1}", mode, lib.display());
                }
            }
            None => {
                println!("cargo:rustc-link-lib={0}={1}", mode, "gpgme");
            }
        }
        return;
    } else if let Some(path) = env::var_os("GPGME_CONFIG") {
        if !try_config(path) {
            process::exit(1);
        }
        return;
    }

    if !Path::new("libassuan/.git").exists() || !Path::new("gpgme/.git").exists() {
        run(Command::new("git").args(&["submodule", "update", "--init"]));
    }
    run(Command::new("git")
        .current_dir("libassuan")
        .args(&["apply", "../libassuan-remove-doc.patch"]));
    run(Command::new("git").current_dir("gpgme").args(&["apply", "../gpgme-remove-doc.patch"]));

    if try_build() || try_config("gpgme-config") {
        return;
    }
    process::exit(1);
}

fn try_config<S: AsRef<OsStr>>(path: S) -> bool {
    let path = path.as_ref();

    let mut cmd = path.to_owned();
    cmd.push(" --version");
    if let Some(output) = output(Command::new("sh").arg("-c").arg(cmd)) {
        test_version(&output);
    } else {
        return false;
    }

    let mut cmd = path.to_owned();
    cmd.push(" --prefix");
    if let Some(output) = output(Command::new("sh").arg("-c").arg(cmd)) {
        println!("cargo:root={}", output);
    }

    let mut cmd = path.to_owned();
    if cfg!(unix) {
        cmd.push(" --thread=pthread");
    }
    cmd.push(" --libs");
    if let Some(output) = output(Command::new("sh").arg("-c").arg(cmd)) {
        parse_config_output(&output);
        return true;
    }
    false
}

fn parse_config_output(output: &str) {
    let parts = output.split(|c: char| c.is_whitespace()).filter_map(|p| if p.len() > 2 {
        Some(p.split_at(2))
    } else {
        None
    });

    for (flag, val) in parts {
        match flag {
            "-L" => {
                println!("cargo:rustc-link-search=native={}", val);
            }
            "-F" => {
                println!("cargo:rustc-link-search=framework={}", val);
            }
            "-l" => {
                println!("cargo:rustc-link-lib={}", val);
            }
            _ => {}
        }
    }
}

fn try_build() -> bool {
    let src = PathBuf::from(env::current_dir().unwrap()).join("libassuan");
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dst.clone().join("build/assuan");
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let gpgerror_root = env::var("DEP_GPG_ERROR_ROOT").unwrap();
    let compiler = gcc::Config::new().get_compiler();
    let cflags = compiler.args().iter().fold(OsString::new(), |mut c, a| {
        c.push(a);
        c.push(" ");
        c
    });

    let _ = fs::create_dir_all(&build);

    if !run(Command::new("sh").current_dir(&src).arg("autogen.sh")) {
        return false;
    }
    if !run(Command::new("sh")
        .current_dir(&build)
        .env("CC", compiler.path())
        .env("CFLAGS", &cflags)
        .arg(msys_compatible(src.join("configure")))
        .args(&["--build", gnu_target(&host),
                "--host", gnu_target(&target),
                "--enable-static",
                "--disable-shared",
                &format!("--with-libgpg-error-prefix={}",
                         msys_compatible(&gpgerror_root)),
                &format!("--prefix={}", msys_compatible(&dst))])) {
        return false;
    }
    if !run(Command::new("make")
        .current_dir(&build)
        .arg("-j")
        .arg(env::var("NUM_JOBS").unwrap())) {
        return false;
    }
    if !run(Command::new("make")
        .current_dir(&build)
        .arg("install")) {
        return false;
    }

    let src = PathBuf::from(env::current_dir().unwrap()).join("gpgme");
    let build = dst.clone().join("build/gpgme");
    let _ = fs::create_dir_all(&build);

    if !run(Command::new("sh").current_dir(&src).arg("autogen.sh")) {
        return false;
    }

    let mut configure = Command::new("sh");
    configure.current_dir(&build)
        .env("CC", compiler.path())
        .env("CFLAGS", &cflags)
        .arg(msys_compatible(src.join("configure")))
        .args(&["--build", gnu_target(&host),
                "--host", gnu_target(&target),
                "--enable-static",
                "--disable-shared",
                "--disable-languages",
                &format!("--with-libgpg-error-prefix={}",
                         msys_compatible(&gpgerror_root)),
                &format!("--with-libassuan-prefix={}", msys_compatible(&dst)),
                &format!("--prefix={}", msys_compatible(&dst))]);
    if target.contains("windows") {
        configure.args(&["--disable-gpgsm-test", "--disable-gpgconf-test", "--disable-g13-test"]);
    }
    if !run(&mut configure) {
        return false;
    }
    if !run(Command::new("make")
        .current_dir(&build)
        .arg("-j")
        .arg(env::var("NUM_JOBS").unwrap())) {
        return false;
    }
    if !run(Command::new("make").current_dir(&build).arg("install")) {
        return false;
    }

    println!("cargo:rustc-link-search=native={}", dst.clone().join("lib").display());
    println!("cargo:rustc-link-lib=static=assuan");
    println!("cargo:rustc-link-lib=static=gpgme");
    println!("cargo:root={}", dst.display());
    true
}

fn test_version(version: &str) {
    let version = version.trim();
    for (x, y) in TARGET_VERSION.split('.').zip(version.split('.').chain(iter::repeat("0"))) {
        let (x, y): (u8, u8) = (x.parse().unwrap(), y.parse().unwrap());
        match x.cmp(&y) {
            Ordering::Less => break,
            Ordering::Greater => {
                panic!("GPGME version `{}` is less than requested `{}`",
                       version, TARGET_VERSION)
            }
            _ => (),
        }
    }
}

fn spawn(cmd: &mut Command) -> Option<Child> {
    println!("running: {:?}", cmd);
    match cmd.stdin(Stdio::null()).spawn() {
        Ok(child) => Some(child),
        Err(e) => {
            println!("failed to execute command: {:?}\nerror: {}", cmd, e);
            None
        }
    }
}

fn run(cmd: &mut Command) -> bool {
    if let Some(mut child) = spawn(cmd) {
        match child.wait() {
            Ok(status) => {
                if !status.success() {
                    println!("command did not execute successfully: {:?}\n\
                       expected success, got: {}", cmd, status);
                } else {
                    return true;
                }
            }
            Err(e) => {
                println!("failed to execute command: {:?}\nerror: {}", cmd, e);
            }
        }
    }
    false
}

fn output(cmd: &mut Command) -> Option<String> {
    if let Some(child) = spawn(cmd.stdout(Stdio::piped())) {
        match child.wait_with_output() {
            Ok(output) => {
                if !output.status.success() {
                    println!("command did not execute successfully: {:?}\n\
                       expected success, got: {}", cmd, output.status);
                } else {
                    return String::from_utf8(output.stdout).ok();
                }
            }
            Err(e) => {
                println!("failed to execute command: {:?}\nerror: {}", cmd, e);
            }
        }
    }
    None
}

fn msys_compatible<P: AsRef<Path>>(path: P) -> String {
    use std::ascii::AsciiExt;

    let mut path = path.as_ref().to_string_lossy().into_owned();
    if !cfg!(windows) || Path::new(&path).is_relative() {
        return path;
    }

    if let Some(b'a'...b'z') = path.as_bytes().first().map(u8::to_ascii_lowercase) {
        if path.split_at(1).1.starts_with(":\\") {
            (&mut path[..1]).make_ascii_lowercase();
            path.remove(1);
            path.insert(0, '/');
        }
    }
    path.replace("\\", "/")
}

fn gnu_target(target: &str) -> &str {
    match target {
        "i686-pc-windows-gnu" => "i686-w64-mingw32",
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
        s => s,
    }
}
<commit_msg>Change target for git submodule check<commit_after>#[macro_use]
extern crate cfg_if;
extern crate gcc;

use std::cmp::Ordering;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::iter;
use std::path::{Path, PathBuf};
use std::process::{self, Child, Command, Stdio};
use std::str;

cfg_if! {
    if #[cfg(feature = "v1_8_0")] {
        const TARGET_VERSION: &'static str = "1.8.0";
    } else if #[cfg(feature = "v1_7_1")] {
        const TARGET_VERSION: &'static str = "1.7.1";
    } else if #[cfg(feature = "v1_7_0")] {
        const TARGET_VERSION: &'static str = "1.7.0";
    } else if #[cfg(feature = "v1_6_0")] {
        const TARGET_VERSION: &'static str = "1.6.0";
    } else if #[cfg(feature = "v1_5_1")] {
        const TARGET_VERSION: &'static str = "1.5.1";
    } else if #[cfg(feature = "v1_5_0")] {
        const TARGET_VERSION: &'static str = "1.5.0";
    } else if #[cfg(feature = "v1_4_3")] {
        const TARGET_VERSION: &'static str = "1.4.3";
    } else if #[cfg(feature = "v1_4_2")] {
        const TARGET_VERSION: &'static str = "1.4.2";
    } else if #[cfg(feature = "v1_4_0")] {
        const TARGET_VERSION: &'static str = "1.4.0";
    } else if #[cfg(feature = "v1_3_1")] {
        const TARGET_VERSION: &'static str = "1.3.1";
    } else if #[cfg(feature = "v1_3_0")] {
        const TARGET_VERSION: &'static str = "1.3.0";
    } else {
        const TARGET_VERSION: &'static str = "1.2.0";
    }
}

fn main() {
    let path = env::var_os("GPGME_LIB_PATH");
    let libs = env::var_os("GPGME_LIBS");
    if path.is_some() || libs.is_some() {
        let mode = match env::var_os("GPGME_STATIC") {
            Some(_) => "static",
            _ => "dylib",
        };

        for path in path.iter().flat_map(env::split_paths) {
            println!("cargo:rustc-link-search=native={}", path.display());
        }
        match libs {
            Some(libs) => {
                for lib in env::split_paths(&libs) {
                    println!("cargo:rustc-link-lib={0}={1}", mode, lib.display());
                }
            }
            None => {
                println!("cargo:rustc-link-lib={0}={1}", mode, "gpgme");
            }
        }
        return;
    } else if let Some(path) = env::var_os("GPGME_CONFIG") {
        if !try_config(path) {
            process::exit(1);
        }
        return;
    }

    if !Path::new("libassuan/autogen.sh").exists() || !Path::new("gpgme/autogen.sh").exists() {
        run(Command::new("git").args(&["submodule", "update", "--init"]));
    }
    run(Command::new("git")
        .current_dir("libassuan")
        .args(&["apply", "../libassuan-remove-doc.patch"]));
    run(Command::new("git").current_dir("gpgme").args(&["apply", "../gpgme-remove-doc.patch"]));

    if try_build() || try_config("gpgme-config") {
        return;
    }
    process::exit(1);
}

fn try_config<S: AsRef<OsStr>>(path: S) -> bool {
    let path = path.as_ref();

    let mut cmd = path.to_owned();
    cmd.push(" --version");
    if let Some(output) = output(Command::new("sh").arg("-c").arg(cmd)) {
        test_version(&output);
    } else {
        return false;
    }

    let mut cmd = path.to_owned();
    cmd.push(" --prefix");
    if let Some(output) = output(Command::new("sh").arg("-c").arg(cmd)) {
        println!("cargo:root={}", output);
    }

    let mut cmd = path.to_owned();
    if cfg!(unix) {
        cmd.push(" --thread=pthread");
    }
    cmd.push(" --libs");
    if let Some(output) = output(Command::new("sh").arg("-c").arg(cmd)) {
        parse_config_output(&output);
        return true;
    }
    false
}

fn parse_config_output(output: &str) {
    let parts = output.split(|c: char| c.is_whitespace()).filter_map(|p| if p.len() > 2 {
        Some(p.split_at(2))
    } else {
        None
    });

    for (flag, val) in parts {
        match flag {
            "-L" => {
                println!("cargo:rustc-link-search=native={}", val);
            }
            "-F" => {
                println!("cargo:rustc-link-search=framework={}", val);
            }
            "-l" => {
                println!("cargo:rustc-link-lib={}", val);
            }
            _ => {}
        }
    }
}

fn try_build() -> bool {
    let src = PathBuf::from(env::current_dir().unwrap()).join("libassuan");
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dst.clone().join("build/assuan");
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let gpgerror_root = env::var("DEP_GPG_ERROR_ROOT").unwrap();
    let compiler = gcc::Config::new().get_compiler();
    let cflags = compiler.args().iter().fold(OsString::new(), |mut c, a| {
        c.push(a);
        c.push(" ");
        c
    });

    let _ = fs::create_dir_all(&build);

    if !run(Command::new("sh").current_dir(&src).arg("autogen.sh")) {
        return false;
    }
    if !run(Command::new("sh")
        .current_dir(&build)
        .env("CC", compiler.path())
        .env("CFLAGS", &cflags)
        .arg(msys_compatible(src.join("configure")))
        .args(&["--build", gnu_target(&host),
                "--host", gnu_target(&target),
                "--enable-static",
                "--disable-shared",
                &format!("--with-libgpg-error-prefix={}",
                         msys_compatible(&gpgerror_root)),
                &format!("--prefix={}", msys_compatible(&dst))])) {
        return false;
    }
    if !run(Command::new("make")
        .current_dir(&build)
        .arg("-j")
        .arg(env::var("NUM_JOBS").unwrap())) {
        return false;
    }
    if !run(Command::new("make")
        .current_dir(&build)
        .arg("install")) {
        return false;
    }

    let src = PathBuf::from(env::current_dir().unwrap()).join("gpgme");
    let build = dst.clone().join("build/gpgme");
    let _ = fs::create_dir_all(&build);

    if !run(Command::new("sh").current_dir(&src).arg("autogen.sh")) {
        return false;
    }

    let mut configure = Command::new("sh");
    configure.current_dir(&build)
        .env("CC", compiler.path())
        .env("CFLAGS", &cflags)
        .arg(msys_compatible(src.join("configure")))
        .args(&["--build", gnu_target(&host),
                "--host", gnu_target(&target),
                "--enable-static",
                "--disable-shared",
                "--disable-languages",
                &format!("--with-libgpg-error-prefix={}",
                         msys_compatible(&gpgerror_root)),
                &format!("--with-libassuan-prefix={}", msys_compatible(&dst)),
                &format!("--prefix={}", msys_compatible(&dst))]);
    if target.contains("windows") {
        configure.args(&["--disable-gpgsm-test", "--disable-gpgconf-test", "--disable-g13-test"]);
    }
    if !run(&mut configure) {
        return false;
    }
    if !run(Command::new("make")
        .current_dir(&build)
        .arg("-j")
        .arg(env::var("NUM_JOBS").unwrap())) {
        return false;
    }
    if !run(Command::new("make").current_dir(&build).arg("install")) {
        return false;
    }

    println!("cargo:rustc-link-search=native={}", dst.clone().join("lib").display());
    println!("cargo:rustc-link-lib=static=assuan");
    println!("cargo:rustc-link-lib=static=gpgme");
    println!("cargo:root={}", dst.display());
    true
}

fn test_version(version: &str) {
    let version = version.trim();
    for (x, y) in TARGET_VERSION.split('.').zip(version.split('.').chain(iter::repeat("0"))) {
        let (x, y): (u8, u8) = (x.parse().unwrap(), y.parse().unwrap());
        match x.cmp(&y) {
            Ordering::Less => break,
            Ordering::Greater => {
                panic!("GPGME version `{}` is less than requested `{}`",
                       version, TARGET_VERSION)
            }
            _ => (),
        }
    }
}

fn spawn(cmd: &mut Command) -> Option<Child> {
    println!("running: {:?}", cmd);
    match cmd.stdin(Stdio::null()).spawn() {
        Ok(child) => Some(child),
        Err(e) => {
            println!("failed to execute command: {:?}\nerror: {}", cmd, e);
            None
        }
    }
}

fn run(cmd: &mut Command) -> bool {
    if let Some(mut child) = spawn(cmd) {
        match child.wait() {
            Ok(status) => {
                if !status.success() {
                    println!("command did not execute successfully: {:?}\n\
                       expected success, got: {}", cmd, status);
                } else {
                    return true;
                }
            }
            Err(e) => {
                println!("failed to execute command: {:?}\nerror: {}", cmd, e);
            }
        }
    }
    false
}

fn output(cmd: &mut Command) -> Option<String> {
    if let Some(child) = spawn(cmd.stdout(Stdio::piped())) {
        match child.wait_with_output() {
            Ok(output) => {
                if !output.status.success() {
                    println!("command did not execute successfully: {:?}\n\
                       expected success, got: {}", cmd, output.status);
                } else {
                    return String::from_utf8(output.stdout).ok();
                }
            }
            Err(e) => {
                println!("failed to execute command: {:?}\nerror: {}", cmd, e);
            }
        }
    }
    None
}

fn msys_compatible<P: AsRef<Path>>(path: P) -> String {
    use std::ascii::AsciiExt;

    let mut path = path.as_ref().to_string_lossy().into_owned();
    if !cfg!(windows) || Path::new(&path).is_relative() {
        return path;
    }

    if let Some(b'a'...b'z') = path.as_bytes().first().map(u8::to_ascii_lowercase) {
        if path.split_at(1).1.starts_with(":\\") {
            (&mut path[..1]).make_ascii_lowercase();
            path.remove(1);
            path.insert(0, '/');
        }
    }
    path.replace("\\", "/")
}

fn gnu_target(target: &str) -> &str {
    match target {
        "i686-pc-windows-gnu" => "i686-w64-mingw32",
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
        s => s,
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[link(name = "sax",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/sax-rs")];

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_type = "lib"];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::hashmap::HashMap;
use std::libc::{c_char, c_int};
use std::str;

pub mod error;
pub mod ffi;
mod extfn;

#[deriving(Eq, Clone)]
pub enum ParseMsg {
    StartDocument,
    EndDocument,
    StartElement(~str, Attributes),
    EndElement(~str),
    Characters(~str),
    IgnorableWhitespace(~str),
    Comment(~str),
    CdataBlock(~str),
}

impl ToStr for ParseMsg {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => fmt!("<%s%s>", *name, atts.to_str()),
            EndElement(ref name) => fmt!("</%s>", *name),
            Characters(ref ch) => ch.clone(),
            IgnorableWhitespace(_) => ~"",
            Comment(ref value) => fmt!("", *value),
            CdataBlock(ref value) => fmt!("<![CDATA[%s]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attributes(HashMap<~str, ~str>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut map = Attributes(HashMap::new());
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            map.insert(str::raw::from_c_str(*ptr),
                       str::raw::from_c_str(*(ptr + 1)));
            ptr = ptr + 2;
        }
        map
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        do self.iter().map |(k, v)| {
            fmt!(" %s=\"%s\"", *k, *v)
        }.to_owned_vec().concat()
    }
}

pub type ParseResult = Result<ParseMsg, error::ErrorData>;

pub fn parse(src: &str) -> Port<ParseResult> {
    let (port, chan) = stream();
    unsafe {
        do src.to_c_str().with_ref |c_str| {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       cast::transmute(&chan),
                                       c_str,
                                       src.len() as c_int);
            ffi::xmlCleanupParser();
        }
    }
    port
}

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

    static TEST_XML: &'static str =
"<hello>
    <this />
    test
</hello>";

    #[test]
    fn test() {
        let port = parse(TEST_XML);
        loop {
            match port.recv() {
                Ok(ref msg) => println(msg.to_str()),
                Err(ref err) => println(err.to_str()),
            }
        }
    }
}
<commit_msg>Wrap port in an iterable struct<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[link(name = "sax",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/sax-rs")];

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_type = "lib"];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::hashmap::HashMap;
use std::libc::{c_char, c_int};
use std::str;

pub mod error;
pub mod ffi;
mod extfn;

#[deriving(Eq, Clone)]
pub enum ParseMsg {
    StartDocument,
    EndDocument,
    StartElement(~str, Attributes),
    EndElement(~str),
    Characters(~str),
    IgnorableWhitespace(~str),
    Comment(~str),
    CdataBlock(~str),
}

impl ToStr for ParseMsg {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => fmt!("<%s%s>", *name, atts.to_str()),
            EndElement(ref name) => fmt!("</%s>", *name),
            Characters(ref ch) => ch.clone(),
            IgnorableWhitespace(_) => ~"",
            Comment(ref value) => fmt!("", *value),
            CdataBlock(ref value) => fmt!("<![CDATA[%s]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attributes(HashMap<~str, ~str>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut map = Attributes(HashMap::new());
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            map.insert(str::raw::from_c_str(*ptr),
                       str::raw::from_c_str(*(ptr + 1)));
            ptr = ptr + 2;
        }
        map
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        do self.iter().map |(k, v)| {
            fmt!(" %s=\"%s\"", *k, *v)
        }.to_owned_vec().concat()
    }
}

pub type ParseResult = Result<ParseMsg, error::ErrorData>;

pub struct Parser {
    priv port: Port<ParseResult>,
    priv is_last: bool,
}

impl Parser {
    /// Recives a new parse result. Fails if the parser has finished.
    pub fn recv(&self) -> ParseResult {
        self.port.try_recv().expect(
            "Could not get a new parse result, the parser has already finished!"
        )
    }

    pub fn try_recv(&self) -> Option<ParseResult> {
        self.port.try_recv()
    }
}

impl Iterator<ParseResult> for Parser {
    #[inline]
    fn next(&mut self) -> Option<ParseResult> {
        if self.is_last { return None };

        let msg = self.try_recv();
        if msg == Some(Ok(EndDocument)) {
            self.is_last = true;
        }
        msg
    }
}

pub fn parse(src: &str) -> Parser {
    let (port, chan) = stream();
    unsafe {
        do src.to_c_str().with_ref |c_str| {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       cast::transmute(&chan),
                                       c_str,
                                       src.len() as c_int);
            ffi::xmlCleanupParser();
        }
    }
    Parser { port: port, is_last: false }
}

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

    static TEST_XML: &'static str = "<hello><this />test</hello>";

    #[test]
    fn test() {
        for r in parse(TEST_XML) {
            match r {
                Ok(IgnorableWhitespace(_)) => (),
                Ok(ref msg) => println(msg.to_str()),
                Err(ref err) => println(err.to_str()),
            }
        }
    }
}
<|endoftext|>


<commit_before>/// The Toml Set extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use tokenizer::Token;
use error::*;

pub trait TomlValueSetExt<'doc> {

    /// Extension function for setting a value in the current toml::Value document
    /// using a custom seperator
    ///
    /// # Semantics
    ///
    /// The function _never_ creates intermediate data structures (Tables or Arrays) in the
    /// document.
    ///
    /// # Return value
    ///
    /// * If the set operation worked correctly, `Ok(None)` is returned.
    /// * If the set operation replaced an existing value `Ok(Some(old_value))` is returned
    /// * On failure, `Err(e)` is returned:
    ///     * If the query is `"a.b.c"` but there is no table `"b"`: error
    ///     * If the query is `"a.b.[0]"` but "`b"` is not an array: error
    ///     * If the query is `"a.b.[3]"` but the array at "`b"` has no index `3`: error
    ///     * etc.
    ///
    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for setting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueSetExt::set_with_seperator`
    fn set(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.set_with_seperator(query, '.', value)
    }

}

impl<'doc> TomlValueSetExt<'doc> for Value {

    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        let mut tokens = try!(tokenize_with_seperator(query, sep));
        let last = tokens.pop_last();
        let last = last.unwrap();

        let mut val = try!(resolve(self, &tokens));

        match *last {
            Token::Identifier { ident, .. } => {
                match val {
                    &mut Value::Table(ref mut t) => {
                        Ok(t.insert(ident, value))
                    }
                    _ => unimplemented!()
                }
            }

            Token::Index { idx, .. } => {
                match val {
                    &mut Value::Array(ref mut a) => {
                        if a.len() > idx {
                            let result = a.swap_remove(idx);
                            a.insert(idx, value);
                            Ok(Some(result))
                        } else {
                            a.push(value);
                            Ok(None)
                        }
                    }
                    _ => unimplemented!()
                }
            }

        }
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_set_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        a = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = [ 0 ]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nested_table() {
        let mut toml : Value = toml_from_str(r#"
        [a.b.c]
        d = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let a = t.get("a");
                assert!(a.is_some());

                let a = a.unwrap();
                assert!(is_match!(a, &Value::Table(_)));
                match a {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    },
                                    _ => panic!("What just happenend?"),
                                }
                            },
                            _ => panic!("What just happenend?"),
                        }
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

}

<commit_msg>Add more tests<commit_after>/// The Toml Set extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use tokenizer::Token;
use error::*;

pub trait TomlValueSetExt<'doc> {

    /// Extension function for setting a value in the current toml::Value document
    /// using a custom seperator
    ///
    /// # Semantics
    ///
    /// The function _never_ creates intermediate data structures (Tables or Arrays) in the
    /// document.
    ///
    /// # Return value
    ///
    /// * If the set operation worked correctly, `Ok(None)` is returned.
    /// * If the set operation replaced an existing value `Ok(Some(old_value))` is returned
    /// * On failure, `Err(e)` is returned:
    ///     * If the query is `"a.b.c"` but there is no table `"b"`: error
    ///     * If the query is `"a.b.[0]"` but "`b"` is not an array: error
    ///     * If the query is `"a.b.[3]"` but the array at "`b"` has no index `3`: error
    ///     * etc.
    ///
    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for setting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueSetExt::set_with_seperator`
    fn set(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.set_with_seperator(query, '.', value)
    }

}

impl<'doc> TomlValueSetExt<'doc> for Value {

    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        let mut tokens = try!(tokenize_with_seperator(query, sep));
        let last = tokens.pop_last();
        let last = last.unwrap();

        let mut val = try!(resolve(self, &tokens));

        match *last {
            Token::Identifier { ident, .. } => {
                match val {
                    &mut Value::Table(ref mut t) => {
                        Ok(t.insert(ident, value))
                    }
                    _ => unimplemented!()
                }
            }

            Token::Index { idx, .. } => {
                match val {
                    &mut Value::Array(ref mut a) => {
                        if a.len() > idx {
                            let result = a.swap_remove(idx);
                            a.insert(idx, value);
                            Ok(Some(result))
                        } else {
                            a.push(value);
                            Ok(None)
                        }
                    }
                    _ => unimplemented!()
                }
            }

        }
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_set_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        a = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_table_key_nonexistent() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());
        let res = res.unwrap();

        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = [ 0 ]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_table_index_nonexistent() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nested_table() {
        let mut toml : Value = toml_from_str(r#"
        [a.b.c]
        d = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let a = t.get("a");
                assert!(a.is_some());

                let a = a.unwrap();
                assert!(is_match!(a, &Value::Table(_)));
                match a {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    },
                                    _ => panic!("What just happenend?"),
                                }
                            },
                            _ => panic!("What just happenend?"),
                        }
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nonexistent_table() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::IdentifierNotFoundInDocument(_)));
    }

    #[test]
    fn test_set_with_seperator_into_nonexistent_array() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.set_with_seperator(&String::from("[0]"), '.', Value::Integer(1));

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::NoIndexInTable(0)));
    }

}

<|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 std::net::url;
use std::net::url::Url;
use core::hashmap::HashMap;

/**
Create a URL object from a string. Does various helpful browsery things like

* If there's no current url and the path looks like a file then it will
  create a file url based of the current working directory
* If there's a current url and the new path is relative then the new url
  is based off the current url

*/
#[allow(non_implicitly_copyable_typarams)]
pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
    let mut schm = url::get_scheme(str_url);
    let str_url = if result::is_err(&schm) {
        if current_url.is_none() {
            // Assume we've been given a file path. If it's absolute just return
            // it, otherwise make it absolute with the cwd.
            if str_url[0] == "/"[0] {
                ~"file://" + str_url
            } else {
                ~"file://" + os::getcwd().push(str_url).to_str()
            }
        } else {
            let current_url = current_url.get();
            debug!("make_url: current_url: %?", current_url);
            if current_url.path.is_empty() || current_url.path.ends_with("/") {
                current_url.scheme + "://" + current_url.host + "/" + str_url
            } else {
                let mut path = ~[];
                for str::each_split_char(current_url.path, '/') |p| {
                    path.push(p.to_str());
                }
                let path = path; // FIXME: borrow checker workaround
                let path = path.init();
                let path = str::connect(path.map(|x| copy *x) + ~[str_url], "/");

                current_url.scheme + "://" + current_url.host + path
            }
        }
    } else {
        str_url
    };

    // FIXME: Need to handle errors
    url::from_str(str_url).get()
}

mod make_url_tests {

    #[test]
    fn should_create_absolute_file_url_if_current_url_is_none_and_str_url_looks_filey() {
        let file = ~"local.html";
        let url = make_url(file, None);
        debug!("url: %?", url);
        fail_unless!(url.scheme == ~"file");
        fail_unless!(url.path.contains(os::getcwd().to_str()));
    }

    #[test]
    fn should_create_url_based_on_old_url_1() {
        let old_str = ~"http://example.com";
        let old_url = make_url(old_str, None);
        let new_str = ~"index.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/index.html");
    }

    #[test]
    fn should_create_url_based_on_old_url_2() {
        let old_str = ~"http://example.com/";
        let old_url = make_url(old_str, None);
        let new_str = ~"index.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/index.html");
    }

    #[test]
    fn should_create_url_based_on_old_url_3() {
        let old_str = ~"http://example.com/index.html";
        let old_url = make_url(old_str, None);
        let new_str = ~"crumpet.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/crumpet.html");
    }

    #[test]
    fn should_create_url_based_on_old_url_4() {
        let old_str = ~"http://example.com/snarf/index.html";
        let old_url = make_url(old_str, None);
        let new_str = ~"crumpet.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/snarf/crumpet.html");
    }

}

pub type UrlMap<T> = @mut HashMap<Url, T>;

pub fn url_map<T: Copy>() -> UrlMap<T> {
    @mut HashMap::new()
}
<commit_msg>Fix 'make_url' to handle absolute paths properly, allows servo command line to handle absolute paths.<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 std::net::url;
use std::net::url::Url;
use core::hashmap::HashMap;

/**
Create a URL object from a string. Does various helpful browsery things like

* If there's no current url and the path looks like a file then it will
  create a file url based of the current working directory
* If there's a current url and the new path is relative then the new url
  is based off the current url

*/
#[allow(non_implicitly_copyable_typarams)]
pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
    let mut schm = url::get_scheme(str_url);
    let str_url = if result::is_err(&schm) {
        if current_url.is_none() {
            // Assume we've been given a file path. If it's absolute just return
            // it, otherwise make it absolute with the cwd.
            if str_url.starts_with("/") {
                ~"file://" + str_url
            } else {
                ~"file://" + os::getcwd().push(str_url).to_str()
            }
        } else {
            let current_url = current_url.get();
            debug!("make_url: current_url: %?", current_url);
            if current_url.path.is_empty() || current_url.path.ends_with("/") {
                current_url.scheme + "://" + current_url.host + "/" + str_url
            } else {
                let mut path = ~[];
                for str::each_split_char(current_url.path, '/') |p| {
                    path.push(p.to_str());
                }
                let path = path; // FIXME: borrow checker workaround
                let path = path.init();
                let path = str::connect(path.map(|x| copy *x) + ~[str_url], "/");

                current_url.scheme + "://" + current_url.host + path
            }
        }
    } else {
        str_url
    };

    // FIXME: Need to handle errors
    url::from_str(str_url).get()
}

mod make_url_tests {

    #[test]
    fn should_create_absolute_file_url_if_current_url_is_none_and_str_url_looks_filey() {
        let file = ~"local.html";
        let url = make_url(file, None);
        debug!("url: %?", url);
        fail_unless!(url.scheme == ~"file");
        fail_unless!(url.path.contains(os::getcwd().to_str()));
    }

    #[test]
    fn should_create_url_based_on_old_url_1() {
        let old_str = ~"http://example.com";
        let old_url = make_url(old_str, None);
        let new_str = ~"index.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/index.html");
    }

    #[test]
    fn should_create_url_based_on_old_url_2() {
        let old_str = ~"http://example.com/";
        let old_url = make_url(old_str, None);
        let new_str = ~"index.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/index.html");
    }

    #[test]
    fn should_create_url_based_on_old_url_3() {
        let old_str = ~"http://example.com/index.html";
        let old_url = make_url(old_str, None);
        let new_str = ~"crumpet.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/crumpet.html");
    }

    #[test]
    fn should_create_url_based_on_old_url_4() {
        let old_str = ~"http://example.com/snarf/index.html";
        let old_url = make_url(old_str, None);
        let new_str = ~"crumpet.html";
        let new_url = make_url(new_str, Some(old_url));
        fail_unless!(new_url.scheme == ~"http");
        fail_unless!(new_url.host == ~"example.com");
        fail_unless!(new_url.path == ~"/snarf/crumpet.html");
    }

}

pub type UrlMap<T> = @mut HashMap<Url, T>;

pub fn url_map<T: Copy>() -> UrlMap<T> {
    @mut HashMap::new()
}
<|endoftext|>


<commit_before>//! Module containing a few common error wrappers which allows more information to be saved for
//! later display to the user

use std::any::Any;
use std::error::Error as StdError;
use std::fmt;
use std::iter::{Extend, FromIterator};
use std::slice;
use std::vec;

use pos::{BytePos, Location, Span, Spanned, spanned2};
use source::Source;

/// An error type which can represent multiple errors.
#[derive(Debug, PartialEq)]
pub struct Errors<T> {
    errors: Vec<T>,
}

impl<T> Errors<T> {
    /// Creates a new, empty `Errors` instance.
    pub fn new() -> Errors<T> {
        Errors::from(Vec::new())
    }

    /// Returns true if `self` contains any errors
    pub fn has_errors(&self) -> bool {
        !self.is_empty()
    }

    /// The number of errors in the error list
    pub fn len(&self) -> usize {
        self.errors.len()
    }

    pub fn is_empty(&self) -> bool {
        self.errors.is_empty()
    }

    /// Adds an error to `self`
    pub fn push(&mut self, t: T) {
        self.errors.push(t);
    }

    /// Pops and error off the error list
    pub fn pop(&mut self) -> Option<T> {
        self.errors.pop()
    }
}

impl<T> Extend<T> for Errors<T> {
    fn extend<Iter: IntoIterator<Item = T>>(&mut self, iter: Iter) {
        self.errors.extend(iter);
    }
}

impl<T> From<Vec<T>> for Errors<T> {
    fn from(errors: Vec<T>) -> Errors<T> {
        Errors { errors: errors }
    }
}

impl<T> FromIterator<T> for Errors<T> {
    fn from_iter<Iter: IntoIterator<Item = T>>(iter: Iter) -> Errors<T> {
        Errors { errors: iter.into_iter().collect() }
    }
}

impl<T> Into<Vec<T>> for Errors<T> {
    fn into(self) -> Vec<T> {
        self.errors
    }
}

impl<T> IntoIterator for Errors<T> {
    type Item = T;

    type IntoIter = vec::IntoIter<T>;

    fn into_iter(self) -> vec::IntoIter<T> {
        self.errors.into_iter()
    }
}

impl<'a, T> IntoIterator for &'a Errors<T> {
    type Item = &'a T;

    type IntoIter = slice::Iter<'a, T>;

    fn into_iter(self) -> slice::Iter<'a, T> {
        self.errors.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Errors<T> {
    type Item = &'a mut T;

    type IntoIter = slice::IterMut<'a, T>;

    fn into_iter(self) -> slice::IterMut<'a, T> {
        self.errors.iter_mut()
    }
}

impl<T: fmt::Display> fmt::Display for Errors<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.errors {
            write!(f, "{}\n", error)?;
        }
        Ok(())
    }
}

impl<T: fmt::Display + fmt::Debug + Any> StdError for Errors<T> {
    fn description(&self) -> &str {
        "Errors"
    }
}

#[derive(Debug, PartialEq)]
struct SourceContext<E> {
    line: String,
    error: Spanned<E, Location>,
}

impl<E> SourceContext<E> {
    fn new(source: &Source, error: Spanned<E, BytePos>) -> SourceContext<E> {
        let start = source.location(error.span.start).unwrap();
        let end = source.location(error.span.end).unwrap();
        let (_, line) = source.line_at_byte(error.span.start).unwrap();

        SourceContext {
            line: line.to_string(),
            error: spanned2(start, end, error.value),
        }
    }
}

/// Error type which contains information of which file and where in the file the error occured
#[derive(Debug, PartialEq)]
pub struct InFile<E> {
    pub source_name: String,
    error: Errors<SourceContext<E>>,
}

impl<E: fmt::Display> InFile<E> {
    /// Creates a new `InFile` error which states that the error occured in `file` using the file
    /// contents in `source` to provide a context to the span.
    pub fn new(source_name: &str, source: &str, error: Errors<Spanned<E, BytePos>>) -> InFile<E> {
        let source = Source::new(source);

        InFile {
            source_name: source_name.to_string(),
            error: Errors {
                errors: error
                    .errors
                    .into_iter()
                    .map(|error| SourceContext::new(&source, error))
                    .collect(),
            },
        }
    }

    pub fn errors(self) -> Errors<Spanned<E, Location>> {
        Errors { errors: self.error.errors.into_iter().map(|err| err.error).collect() }
    }
}

impl<E: fmt::Display> fmt::Display for InFile<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.error.errors {
            let Span { start, end, .. } = error.error.span;

            write!(f, "{}:{}\n{}\n", self.source_name, error.error, error.line)?;

            for _ in 0..start.column.to_usize() {
                write!(f, " ")?;
            }

            write!(f, "^")?;
            for _ in (start.column.to_usize() + 1)..end.column.to_usize() {
                write!(f, "~")?;
            }

            writeln!(f, "")?;
        }
        Ok(())
    }
}

impl<E: fmt::Display + fmt::Debug + Any> StdError for InFile<E> {
    fn description(&self) -> &str {
        "Error in file"
    }
}
<commit_msg>fix: Separate all errors with a newline<commit_after>//! Module containing a few common error wrappers which allows more information to be saved for
//! later display to the user

use std::any::Any;
use std::error::Error as StdError;
use std::fmt;
use std::iter::{Extend, FromIterator};
use std::slice;
use std::vec;

use pos::{BytePos, Location, Span, Spanned, spanned2};
use source::Source;

/// An error type which can represent multiple errors.
#[derive(Debug, PartialEq)]
pub struct Errors<T> {
    errors: Vec<T>,
}

impl<T> Errors<T> {
    /// Creates a new, empty `Errors` instance.
    pub fn new() -> Errors<T> {
        Errors::from(Vec::new())
    }

    /// Returns true if `self` contains any errors
    pub fn has_errors(&self) -> bool {
        !self.is_empty()
    }

    /// The number of errors in the error list
    pub fn len(&self) -> usize {
        self.errors.len()
    }

    pub fn is_empty(&self) -> bool {
        self.errors.is_empty()
    }

    /// Adds an error to `self`
    pub fn push(&mut self, t: T) {
        self.errors.push(t);
    }

    /// Pops and error off the error list
    pub fn pop(&mut self) -> Option<T> {
        self.errors.pop()
    }
}

impl<T> Extend<T> for Errors<T> {
    fn extend<Iter: IntoIterator<Item = T>>(&mut self, iter: Iter) {
        self.errors.extend(iter);
    }
}

impl<T> From<Vec<T>> for Errors<T> {
    fn from(errors: Vec<T>) -> Errors<T> {
        Errors { errors: errors }
    }
}

impl<T> FromIterator<T> for Errors<T> {
    fn from_iter<Iter: IntoIterator<Item = T>>(iter: Iter) -> Errors<T> {
        Errors { errors: iter.into_iter().collect() }
    }
}

impl<T> Into<Vec<T>> for Errors<T> {
    fn into(self) -> Vec<T> {
        self.errors
    }
}

impl<T> IntoIterator for Errors<T> {
    type Item = T;

    type IntoIter = vec::IntoIter<T>;

    fn into_iter(self) -> vec::IntoIter<T> {
        self.errors.into_iter()
    }
}

impl<'a, T> IntoIterator for &'a Errors<T> {
    type Item = &'a T;

    type IntoIter = slice::Iter<'a, T>;

    fn into_iter(self) -> slice::Iter<'a, T> {
        self.errors.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Errors<T> {
    type Item = &'a mut T;

    type IntoIter = slice::IterMut<'a, T>;

    fn into_iter(self) -> slice::IterMut<'a, T> {
        self.errors.iter_mut()
    }
}

impl<T: fmt::Display> fmt::Display for Errors<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, error) in self.errors.iter().enumerate() {
            write!(f, "{}", error)?;
            // Errors are assumed to not have a newline at the end so we add one to keep errors on
            // separate lines and one to space them out
            if i + 1 != self.errors.len() {
                writeln!(f)?;
                writeln!(f)?;
            }
        }
        Ok(())
    }
}

impl<T: fmt::Display + fmt::Debug + Any> StdError for Errors<T> {
    fn description(&self) -> &str {
        "Errors"
    }
}

#[derive(Debug, PartialEq)]
struct SourceContext<E> {
    line: String,
    error: Spanned<E, Location>,
}

impl<E> SourceContext<E> {
    fn new(source: &Source, error: Spanned<E, BytePos>) -> SourceContext<E> {
        let start = source.location(error.span.start).unwrap();
        let end = source.location(error.span.end).unwrap();
        let (_, line) = source.line_at_byte(error.span.start).unwrap();

        SourceContext {
            line: line.to_string(),
            error: spanned2(start, end, error.value),
        }
    }
}

/// Error type which contains information of which file and where in the file the error occured
#[derive(Debug, PartialEq)]
pub struct InFile<E> {
    pub source_name: String,
    error: Errors<SourceContext<E>>,
}

impl<E: fmt::Display> InFile<E> {
    /// Creates a new `InFile` error which states that the error occured in `file` using the file
    /// contents in `source` to provide a context to the span.
    pub fn new(source_name: &str, source: &str, error: Errors<Spanned<E, BytePos>>) -> InFile<E> {
        let source = Source::new(source);

        InFile {
            source_name: source_name.to_string(),
            error: Errors {
                errors: error
                    .errors
                    .into_iter()
                    .map(|error| SourceContext::new(&source, error))
                    .collect(),
            },
        }
    }

    pub fn errors(self) -> Errors<Spanned<E, Location>> {
        Errors { errors: self.error.errors.into_iter().map(|err| err.error).collect() }
    }
}

impl<E: fmt::Display> fmt::Display for InFile<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.error.errors {
            let Span { start, end, .. } = error.error.span;

            write!(f, "{}:{}\n{}\n", self.source_name, error.error, error.line)?;

            for _ in 0..start.column.to_usize() {
                write!(f, " ")?;
            }

            write!(f, "^")?;
            for _ in (start.column.to_usize() + 1)..end.column.to_usize() {
                write!(f, "~")?;
            }

            writeln!(f, "")?;
        }
        Ok(())
    }
}

impl<E: fmt::Display + fmt::Debug + Any> StdError for InFile<E> {
    fn description(&self) -> &str {
        "Error in file"
    }
}
<|endoftext|>


<commit_before>//! `StructureExtension` data description.
use crate::data::RoomName;

with_structure_fields_and_update_struct! {
    /// An extension structure - a structure that can be filled with extra energy spawns can use.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureExtension {
        /// The user ID of the owner of this structure.
        pub user: String,
        /// Whether or not this structure is non-functional due to a degraded controller.
        #[serde(default, rename = "off")]
        pub disabled: bool,
        /// The current amount of energy held in this structure.
        pub energy: i32,
        /// The maximum amount of energy that can be held in this structure.
        pub energy_capacity: i32,
        /// Whether or not an attack on this structure will send an email to the owner automatically.
        pub notify_when_attacked: bool,
    }

    /// The update structure for an extension structure.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureExtensionUpdate {
        - user: String,
        #[serde(rename = "off")]
        - disabled: bool,
        - energy: i32,
        - energy_capacity: i32,
        - notify_when_attacked: bool,
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;
    use serde_json;

    use crate::data::RoomName;

    use super::StructureExtension;

    #[test]
    fn parse_extension_and_update() {
        let json = json!({
            "_id": "594cac66e1dd5c8d2eb7df9d",
            "energy": 200,
            "energyCapacity": 200,
            "hits": 1000,
            "hitsMax": 1000,
            "notifyWhenAttacked": true,
            "off": false,
            "room": "E4S61",
            "type": "extension",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 27,
            "y": 3,
        });

        let mut obj = StructureExtension::deserialize(json).unwrap();

        assert_eq!(
            obj,
            StructureExtension {
                room: RoomName::new("E4S61").unwrap(),
                x: 27,
                y: 3,
                id: "594cac66e1dd5c8d2eb7df9d".to_owned(),
                energy: 200,
                energy_capacity: 200,
                hits: 1000,
                hits_max: 1000,
                notify_when_attacked: true,
                disabled: false,
                user: "57874d42d0ae911e3bd15bbc".to_owned(),
            }
        );

        obj.update(
            serde_json::from_value(json!({
                "energy": 0,
                "notifyWhenAttacked": false,
            }))
            .unwrap(),
        );

        assert_eq!(
            obj,
            StructureExtension {
                room: RoomName::new("E4S61").unwrap(),
                x: 27,
                y: 3,
                id: "594cac66e1dd5c8d2eb7df9d".to_owned(),
                energy: 0,
                energy_capacity: 200,
                hits: 1000,
                hits_max: 1000,
                notify_when_attacked: false,
                disabled: false,
                user: "57874d42d0ae911e3bd15bbc".to_owned(),
            }
        );
    }
}
<commit_msg>Updated StructureExtension<commit_after>//! `StructureExtension` data description.
use crate::data::RoomName;
use super::super::resources::Store;

with_structure_fields_and_update_struct! {
    /// An extension structure - a structure that can be filled with extra energy spawns can use.
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureExtension {
        /// The user ID of the owner of this structure.
        pub user: String,
        /// Whether or not this structure is non-functional due to a degraded controller.
        #[serde(default, rename = "off")]
        pub disabled: bool,
        /// The current amount of energy held in this structure.
        pub store: Store,
        /// The maximum amount of energy that can be held in this structure.
        #[serde(rename = "storeCapacityResource")]
        pub store_capacity: Store,
        /// Whether or not an attack on this structure will send an email to the owner automatically.
        pub notify_when_attacked: bool,
    }

    /// The update structure for an extension structure.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct StructureExtensionUpdate {
        - user: String,
        #[serde(rename = "off")]
        - disabled: bool,
        - store: Store,
        - store_capacity: Store,
        - notify_when_attacked: bool,
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;
    use serde_json;

    use crate::data::RoomName;

    use super::StructureExtension;

    #[test]
    fn parse_extension_and_update() {
        let json = json!({
          "_id": "5bef67919e7eaa3015aadfe2",
          "type": "extension",
          "x": 21,
          "y": 24,
          "room": "E9S32",
          "notifyWhenAttacked": true,
          "user": "589f5265d25357e8253e3ee8",
          "hits": 1000,
          "hitsMax": 1000,
          "off": false,
          "store": {
            "energy": 200
          },
          "storeCapacityResource": {
            "energy": 200
          }
        });

        let mut obj = StructureExtension::deserialize(json).unwrap();

        assert_eq!(
            obj,
            StructureExtension {
                room: RoomName::new("E9S32").unwrap(),
                x: 21,
                y: 24,
                id: "5bef67919e7eaa3015aadfe2".to_owned(),
                store: store! { Energy: 200 },
                store_capacity: store! { Energy: 200 },
                hits: 1000,
                hits_max: 1000,
                notify_when_attacked: true,
                disabled: false,
                user: "589f5265d25357e8253e3ee8".to_owned(),
            }
        );

        obj.update(
            serde_json::from_value(json!({
                "store": {
                    "energy": 0,
                },
                "notifyWhenAttacked": false,
            }))
            .unwrap(),
        );

        assert_eq!(
            obj,
            StructureExtension {
                room: RoomName::new("E9S32").unwrap(),
                x: 21,
                y: 24,
                id: "5bef67919e7eaa3015aadfe2".to_owned(),
                store: store! { Energy: 200 },
                store_capacity: store! { Energy: 200 },
                hits: 1000,
                hits_max: 1000,
                notify_when_attacked: false,
                disabled: false,
                user: "589f5265d25357e8253e3ee8".to_owned(),
            }
        );
    }
}
<|endoftext|>