<commit_before>use fnv::FnvHashMap;
use {UndoCmd, UndoStack};

#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Id(u64);

pub struct UndoGroup<'a, T: UndoCmd + 'a> {
    group: FnvHashMap<Id, UndoStack<'a, T>>,
    active: Option<&'a mut UndoStack<'a, T>>,
    id: u64,
}

impl<'a, T: UndoCmd> UndoGroup<'a, T> {
    pub fn new() -> Self {
        UndoGroup {
            group: FnvHashMap::default(),
            active: None,
            id: 0,
        }
    }

    pub fn with_capacity(capacity: usize) -> Self {
        UndoGroup {
            group: FnvHashMap::with_capacity_and_hasher(capacity, Default::default()),
            active: None,
            id: 0,
        }
    }

    pub fn add_stack(&mut self, stack: UndoStack<'a, T>) -> Id {
        let id = Id(self.id);
        self.id += 1;
        self.group.insert(Id(id.0), stack);
        id
    }

    pub fn remove_stack(&mut self, id: Id) -> UndoStack<'a, T> {
        let stack = self.group.remove(&id).unwrap();
        // Check if it was the active stack that was removed.
        let is_active = match self.active {
            Some(ref active) => {
                *active as *const _ == &stack as *const _
            },
            None => return stack,
        };
        // If it was, we remove it from the active stack.
        if is_active {
            self.active = None;
        }
        stack
    }

    pub fn set_active_stack(&'a mut self, id: &Id) {
        self.active = self.group.get_mut(id);
    }

    pub fn clear_active_stack(&mut self) {
        self.active = None;
    }

    pub fn is_clean(&self) -> Option<bool> {
        self.active.as_ref().map(|t| t.is_clean())
    }

    pub fn is_dirty(&self) -> Option<bool> {
        self.is_clean().map(|t| !t)
    }

    pub fn push(&mut self, cmd: T) {
        if let Some(ref mut stack) = self.active {
            stack.push(cmd);
        }
    }

    pub fn redo(&mut self) {
        if let Some(ref mut stack) = self.active {
            stack.redo();
        }
    }

    pub fn undo(&mut self) {
        if let Some(ref mut stack) = self.active {
            stack.undo();
        }
    }
}
<commit_msg>Use u64 as key instead of Id<commit_after>use fnv::FnvHashMap;
use {UndoCmd, UndoStack};

pub struct Id(u64);

pub struct UndoGroup<'a, T: UndoCmd + 'a> {
    group: FnvHashMap<u64, UndoStack<'a, T>>,
    active: Option<&'a mut UndoStack<'a, T>>,
    id: u64,
}

impl<'a, T: UndoCmd> UndoGroup<'a, T> {
    pub fn new() -> Self {
        UndoGroup {
            group: FnvHashMap::default(),
            active: None,
            id: 0,
        }
    }

    pub fn with_capacity(capacity: usize) -> Self {
        UndoGroup {
            group: FnvHashMap::with_capacity_and_hasher(capacity, Default::default()),
            active: None,
            id: 0,
        }
    }

    pub fn add_stack(&mut self, stack: UndoStack<'a, T>) -> Id {
        let id = self.id;
        self.id += 1;
        self.group.insert(id, stack);
        Id(id)
    }

    pub fn remove_stack(&mut self, Id(id): Id) -> UndoStack<'a, T> {
        let stack = self.group.remove(&id).unwrap();
        // Check if it was the active stack that was removed.
        let is_active = match self.active {
            Some(ref active) => {
                *active as *const _ == &stack as *const _
            },
            None => return stack,
        };
        // If it was, we remove it from the active stack.
        if is_active {
            self.active = None;
        }
        stack
    }

    pub fn set_active_stack(&'a mut self, &Id(ref id): &Id) {
        self.active = self.group.get_mut(id);
    }

    pub fn clear_active_stack(&mut self) {
        self.active = None;
    }

    pub fn is_clean(&self) -> Option<bool> {
        self.active.as_ref().map(|t| t.is_clean())
    }

    pub fn is_dirty(&self) -> Option<bool> {
        self.is_clean().map(|t| !t)
    }

    pub fn push(&mut self, cmd: T) {
        if let Some(ref mut stack) = self.active {
            stack.push(cmd);
        }
    }

    pub fn redo(&mut self) {
        if let Some(ref mut stack) = self.active {
            stack.redo();
        }
    }

    pub fn undo(&mut self) {
        if let Some(ref mut stack) = self.active {
            stack.undo();
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Set all listen addresses to 0.0.0.0 for testnets<commit_after><|endoftext|>


<commit_before><commit_msg>Refactor arg parsing<commit_after><|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use ring::digest::Algorithm;

use hashutils::HashUtils;
use tree::Tree;

/// An inclusion proof represent the fact that a `value` is a member
/// of a `MerkleTree` with root hash `root_hash`, and hash function `algorithm`.
#[cfg_attr(
    feature = "serialization-serde",
    derive(Serialize, Deserialize)
)]
#[derive(Clone, Debug)]
pub struct Proof<T> {
    /// The hashing algorithm used in the original `MerkleTree`
    #[cfg_attr(
        feature = "serialization-serde",
        serde(with = "algorithm_serde")
    )]
    pub algorithm: &'static Algorithm,

    /// The hash of the root of the original `MerkleTree`
    pub root_hash: Vec<u8>,

    /// The first `Lemma` of the `Proof`
    pub lemma: Lemma,

    /// The value concerned by this `Proof`
    pub value: T,
}

#[cfg(feature = "serialization-serde")]
mod algorithm_serde {
    use ring::digest::{self, Algorithm};
    use serde::de::Error;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    pub fn serialize<S: Serializer>(
        algorithm: &'static Algorithm,
        se: S,
    ) -> Result<S::Ok, S::Error> {
        // The `Debug` implementation of `Algorithm` prints its ID.
        format!("{:?}", algorithm).serialize(se)
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<&'static Algorithm, D::Error> {
        let alg_str: String = Deserialize::deserialize(de)?;
        match &*alg_str {
            "SHA1" => Ok(&digest::SHA1),
            "SHA256" => Ok(&digest::SHA256),
            "SHA384" => Ok(&digest::SHA384),
            "SHA512" => Ok(&digest::SHA512),
            "SHA512_256" => Ok(&digest::SHA512_256),
            _ => Err(D::Error::custom("unknown hash algorithm")),
        }
    }

    #[cfg(test)]
    mod test {
        use super::*;
        use ring::digest::{
            SHA1 as sha1, SHA256 as sha256, SHA384 as sha384, SHA512 as sha512,
            SHA512_256 as sha512_256,
        };

        static SHA1: &Algorithm = &sha1;
        static SHA256: &Algorithm = &sha256;
        static SHA384: &Algorithm = &sha384;
        static SHA512: &Algorithm = &sha512;
        static SHA512_256: &Algorithm = &sha512_256;

        #[test]
        fn test_serialize_known_algorithms() {
            extern crate serde_json;

            for alg in &[SHA1, SHA256, SHA384, SHA512, SHA512_256] {
                let mut serializer = serde_json::Serializer::with_formatter(
                    vec![],
                    serde_json::ser::PrettyFormatter::new(),
                );

                serialize(alg, &mut serializer).expect(&format!("{:?}", alg));
                let alg_ = deserialize(&mut serde_json::Deserializer::from_slice(
                    &serializer.into_inner()[..],
                )).expect(&format!("{:?}", alg));

                assert_eq!(*alg, alg_);
            }
        }

        #[test]
        #[should_panic(expected = "unknown hash algorithm")]
        fn test_serialize_unknown_algorithm() {
            extern crate serde_json;
            {
                let alg_str = "\"BLAKE2b\"";
                let mut deserializer = serde_json::Deserializer::from_str(alg_str);
                let _ = deserialize(&mut deserializer).expect(&format!("{:?}", alg_str));
            }
        }
    }
}

impl<T: PartialEq> PartialEq for Proof<T> {
    fn eq(&self, other: &Proof<T>) -> bool {
        self.root_hash == other.root_hash && self.lemma == other.lemma && self.value == other.value
    }
}

impl<T: Eq> Eq for Proof<T> {}

impl<T: Ord> PartialOrd for Proof<T> {
    fn partial_cmp(&self, other: &Proof<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: Ord> Ord for Proof<T> {
    fn cmp(&self, other: &Proof<T>) -> Ordering {
        self.root_hash
            .cmp(&other.root_hash)
            .then(self.value.cmp(&other.value))
            .then_with(|| self.lemma.cmp(&other.lemma))
    }
}

impl<T: Hash> Hash for Proof<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.root_hash.hash(state);
        self.lemma.hash(state);
        self.value.hash(state);
    }
}

impl<T> Proof<T> {
    /// Constructs a new `Proof`
    pub fn new(algorithm: &'static Algorithm, root_hash: Vec<u8>, lemma: Lemma, value: T) -> Self {
        Proof {
            algorithm,
            root_hash,
            lemma,
            value,
        }
    }

    /// Checks whether this inclusion proof is well-formed,
    /// and whether its root hash matches the given `root_hash`.
    pub fn validate(&self, root_hash: &[u8]) -> bool {
        if self.root_hash != root_hash || self.lemma.node_hash != root_hash {
            return false;
        }

        self.lemma.validate(self.algorithm)
    }

    /// Returns the index of this proof's value, given the total number of items in the tree.
    pub fn index(&self, count: usize) -> usize {
        self.lemma.index(count)
    }
}

/// A `Lemma` holds the hash of a node, the hash of its sibling node,
/// and a sub lemma, whose `node_hash`, when combined with this `sibling_hash`
/// must be equal to this `node_hash`.
#[cfg_attr(
    feature = "serialization-serde",
    derive(Serialize, Deserialize)
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Lemma {
    pub node_hash: Vec<u8>,
    pub sibling_hash: Option<Positioned<Vec<u8>>>,
    pub sub_lemma: Option<Box<Lemma>>,
}

impl Lemma {
    /// Attempts to generate a proof that the a value with hash `needle` is a
    /// member of the given `tree`.
    pub fn new<T>(tree: &Tree<T>, needle: &[u8]) -> Option<Lemma> {
        match *tree {
            Tree::Empty { .. } => None,

            Tree::Leaf { ref hash, .. } => Lemma::new_leaf_proof(hash, needle),

            Tree::Node {
                ref hash,
                ref left,
                ref right,
            } => Lemma::new_tree_proof(hash, needle, left, right),
        }
    }

    /// Attempts to generate a proof that the `idx`-th leaf is a member of
    /// the given tree. The `count` must equal the number of leaves in the
    /// `tree`. If `idx >= count`, `None` is returned. Otherwise it returns
    /// the new `Lemma` and the `idx`-th value.
    pub fn new_by_index<T>(tree: &Tree<T>, idx: usize, count: usize) -> Option<(Lemma, &T)> {
        if idx >= count {
            return None;
        }
        match *tree {
            Tree::Empty { .. } => None,

            Tree::Leaf {
                ref hash,
                ref value,
                ..
            } => {
                if count != 1 {
                    return None;
                }
                let lemma = Lemma {
                    node_hash: hash.clone(),
                    sibling_hash: None,
                    sub_lemma: None,
                };
                Some((lemma, value))
            }

            Tree::Node {
                ref hash,
                ref left,
                ref right,
            } => {
                let left_count = count.next_power_of_two() / 2;
                let (sub_lem_val, sibling_hash);
                if idx < left_count {
                    sub_lem_val = Lemma::new_by_index(left, idx, left_count);
                    sibling_hash = Positioned::Right(right.hash().clone());
                } else {
                    sub_lem_val = Lemma::new_by_index(right, idx - left_count, count - left_count);
                    sibling_hash = Positioned::Left(left.hash().clone());
                }
                sub_lem_val.map(|(sub_lemma, value)| {
                    let lemma = Lemma {
                        node_hash: hash.clone(),
                        sibling_hash: Some(sibling_hash),
                        sub_lemma: Some(Box::new(sub_lemma)),
                    };
                    (lemma, value)
                })
            }
        }
    }

    /// Returns the index of this lemma's value, given the total number of items in the tree.
    pub fn index(&self, count: usize) -> usize {
        let left_count = count.next_power_of_two() / 2;
        match (self.sub_lemma.as_ref(), self.sibling_hash.as_ref()) {
            (None, Some(&Positioned::Right(_))) | (None, None) => 0,
            (None, Some(&Positioned::Left(_))) => 1,
            (Some(l), None) => l.index(count),
            (Some(l), Some(&Positioned::Left(_))) => left_count + l.index(count - left_count),
            (Some(l), Some(&Positioned::Right(_))) => l.index(left_count),
        }
    }

    fn new_leaf_proof(hash: &[u8], needle: &[u8]) -> Option<Lemma> {
        if *hash == *needle {
            Some(Lemma {
                node_hash: hash.into(),
                sibling_hash: None,
                sub_lemma: None,
            })
        } else {
            None
        }
    }

    fn new_tree_proof<T>(
        hash: &[u8],
        needle: &[u8],
        left: &Tree<T>,
        right: &Tree<T>,
    ) -> Option<Lemma> {
        Lemma::new(left, needle)
            .map(|lemma| {
                let right_hash = right.hash().clone();
                let sub_lemma = Some(Positioned::Right(right_hash));
                (lemma, sub_lemma)
            })
            .or_else(|| {
                let sub_lemma = Lemma::new(right, needle);
                sub_lemma.map(|lemma| {
                    let left_hash = left.hash().clone();
                    let sub_lemma = Some(Positioned::Left(left_hash));
                    (lemma, sub_lemma)
                })
            })
            .map(|(sub_lemma, sibling_hash)| Lemma {
                node_hash: hash.into(),
                sibling_hash,
                sub_lemma: Some(Box::new(sub_lemma)),
            })
    }

    fn validate(&self, algorithm: &'static Algorithm) -> bool {
        match self.sub_lemma {
            None => self.sibling_hash.is_none(),

            Some(ref sub) => match self.sibling_hash {
                None => false,

                Some(Positioned::Left(ref hash)) => {
                    let combined = algorithm.hash_nodes(hash, &sub.node_hash);
                    let hashes_match = combined.as_ref() == self.node_hash.as_slice();
                    hashes_match && sub.validate(algorithm)
                }

                Some(Positioned::Right(ref hash)) => {
                    let combined = algorithm.hash_nodes(&sub.node_hash, hash);
                    let hashes_match = combined.as_ref() == self.node_hash.as_slice();
                    hashes_match && sub.validate(algorithm)
                }
            },
        }
    }
}

/// Tags a value so that we know from which branch of a `Tree` (if any) it was found.
#[cfg_attr(
    feature = "serialization-serde",
    derive(Serialize, Deserialize)
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Positioned<T> {
    /// The value was found in the left branch
    Left(T),

    /// The value was found in the right branch
    Right(T),
}
<commit_msg>Make index panic on malformed lemma.<commit_after>use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use ring::digest::Algorithm;

use hashutils::HashUtils;
use tree::Tree;

/// An inclusion proof represent the fact that a `value` is a member
/// of a `MerkleTree` with root hash `root_hash`, and hash function `algorithm`.
#[cfg_attr(
    feature = "serialization-serde",
    derive(Serialize, Deserialize)
)]
#[derive(Clone, Debug)]
pub struct Proof<T> {
    /// The hashing algorithm used in the original `MerkleTree`
    #[cfg_attr(
        feature = "serialization-serde",
        serde(with = "algorithm_serde")
    )]
    pub algorithm: &'static Algorithm,

    /// The hash of the root of the original `MerkleTree`
    pub root_hash: Vec<u8>,

    /// The first `Lemma` of the `Proof`
    pub lemma: Lemma,

    /// The value concerned by this `Proof`
    pub value: T,
}

#[cfg(feature = "serialization-serde")]
mod algorithm_serde {
    use ring::digest::{self, Algorithm};
    use serde::de::Error;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    pub fn serialize<S: Serializer>(
        algorithm: &'static Algorithm,
        se: S,
    ) -> Result<S::Ok, S::Error> {
        // The `Debug` implementation of `Algorithm` prints its ID.
        format!("{:?}", algorithm).serialize(se)
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<&'static Algorithm, D::Error> {
        let alg_str: String = Deserialize::deserialize(de)?;
        match &*alg_str {
            "SHA1" => Ok(&digest::SHA1),
            "SHA256" => Ok(&digest::SHA256),
            "SHA384" => Ok(&digest::SHA384),
            "SHA512" => Ok(&digest::SHA512),
            "SHA512_256" => Ok(&digest::SHA512_256),
            _ => Err(D::Error::custom("unknown hash algorithm")),
        }
    }

    #[cfg(test)]
    mod test {
        use super::*;
        use ring::digest::{
            SHA1 as sha1, SHA256 as sha256, SHA384 as sha384, SHA512 as sha512,
            SHA512_256 as sha512_256,
        };

        static SHA1: &Algorithm = &sha1;
        static SHA256: &Algorithm = &sha256;
        static SHA384: &Algorithm = &sha384;
        static SHA512: &Algorithm = &sha512;
        static SHA512_256: &Algorithm = &sha512_256;

        #[test]
        fn test_serialize_known_algorithms() {
            extern crate serde_json;

            for alg in &[SHA1, SHA256, SHA384, SHA512, SHA512_256] {
                let mut serializer = serde_json::Serializer::with_formatter(
                    vec![],
                    serde_json::ser::PrettyFormatter::new(),
                );

                serialize(alg, &mut serializer).expect(&format!("{:?}", alg));
                let alg_ = deserialize(&mut serde_json::Deserializer::from_slice(
                    &serializer.into_inner()[..],
                )).expect(&format!("{:?}", alg));

                assert_eq!(*alg, alg_);
            }
        }

        #[test]
        #[should_panic(expected = "unknown hash algorithm")]
        fn test_serialize_unknown_algorithm() {
            extern crate serde_json;
            {
                let alg_str = "\"BLAKE2b\"";
                let mut deserializer = serde_json::Deserializer::from_str(alg_str);
                let _ = deserialize(&mut deserializer).expect(&format!("{:?}", alg_str));
            }
        }
    }
}

impl<T: PartialEq> PartialEq for Proof<T> {
    fn eq(&self, other: &Proof<T>) -> bool {
        self.root_hash == other.root_hash && self.lemma == other.lemma && self.value == other.value
    }
}

impl<T: Eq> Eq for Proof<T> {}

impl<T: Ord> PartialOrd for Proof<T> {
    fn partial_cmp(&self, other: &Proof<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: Ord> Ord for Proof<T> {
    fn cmp(&self, other: &Proof<T>) -> Ordering {
        self.root_hash
            .cmp(&other.root_hash)
            .then(self.value.cmp(&other.value))
            .then_with(|| self.lemma.cmp(&other.lemma))
    }
}

impl<T: Hash> Hash for Proof<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.root_hash.hash(state);
        self.lemma.hash(state);
        self.value.hash(state);
    }
}

impl<T> Proof<T> {
    /// Constructs a new `Proof`
    pub fn new(algorithm: &'static Algorithm, root_hash: Vec<u8>, lemma: Lemma, value: T) -> Self {
        Proof {
            algorithm,
            root_hash,
            lemma,
            value,
        }
    }

    /// Checks whether this inclusion proof is well-formed,
    /// and whether its root hash matches the given `root_hash`.
    pub fn validate(&self, root_hash: &[u8]) -> bool {
        if self.root_hash != root_hash || self.lemma.node_hash != root_hash {
            return false;
        }

        self.lemma.validate(self.algorithm)
    }

    /// Returns the index of this proof's value, given the total number of items in the tree.
    ///
    /// # Panics
    ///
    /// Panics if the proof is malformed. Call `validate` first.
    pub fn index(&self, count: usize) -> usize {
        self.lemma.index(count)
    }
}

/// A `Lemma` holds the hash of a node, the hash of its sibling node,
/// and a sub lemma, whose `node_hash`, when combined with this `sibling_hash`
/// must be equal to this `node_hash`.
#[cfg_attr(
    feature = "serialization-serde",
    derive(Serialize, Deserialize)
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Lemma {
    pub node_hash: Vec<u8>,
    pub sibling_hash: Option<Positioned<Vec<u8>>>,
    pub sub_lemma: Option<Box<Lemma>>,
}

impl Lemma {
    /// Attempts to generate a proof that the a value with hash `needle` is a
    /// member of the given `tree`.
    pub fn new<T>(tree: &Tree<T>, needle: &[u8]) -> Option<Lemma> {
        match *tree {
            Tree::Empty { .. } => None,

            Tree::Leaf { ref hash, .. } => Lemma::new_leaf_proof(hash, needle),

            Tree::Node {
                ref hash,
                ref left,
                ref right,
            } => Lemma::new_tree_proof(hash, needle, left, right),
        }
    }

    /// Attempts to generate a proof that the `idx`-th leaf is a member of
    /// the given tree. The `count` must equal the number of leaves in the
    /// `tree`. If `idx >= count`, `None` is returned. Otherwise it returns
    /// the new `Lemma` and the `idx`-th value.
    pub fn new_by_index<T>(tree: &Tree<T>, idx: usize, count: usize) -> Option<(Lemma, &T)> {
        if idx >= count {
            return None;
        }
        match *tree {
            Tree::Empty { .. } => None,

            Tree::Leaf {
                ref hash,
                ref value,
                ..
            } => {
                if count != 1 {
                    return None;
                }
                let lemma = Lemma {
                    node_hash: hash.clone(),
                    sibling_hash: None,
                    sub_lemma: None,
                };
                Some((lemma, value))
            }

            Tree::Node {
                ref hash,
                ref left,
                ref right,
            } => {
                let left_count = count.next_power_of_two() / 2;
                let (sub_lem_val, sibling_hash);
                if idx < left_count {
                    sub_lem_val = Lemma::new_by_index(left, idx, left_count);
                    sibling_hash = Positioned::Right(right.hash().clone());
                } else {
                    sub_lem_val = Lemma::new_by_index(right, idx - left_count, count - left_count);
                    sibling_hash = Positioned::Left(left.hash().clone());
                }
                sub_lem_val.map(|(sub_lemma, value)| {
                    let lemma = Lemma {
                        node_hash: hash.clone(),
                        sibling_hash: Some(sibling_hash),
                        sub_lemma: Some(Box::new(sub_lemma)),
                    };
                    (lemma, value)
                })
            }
        }
    }

    /// Returns the index of this lemma's value, given the total number of items in the tree.
    ///
    /// # Panics
    ///
    /// Panics if the lemma is malformed. Call `validate_lemma` first.
    pub fn index(&self, count: usize) -> usize {
        let left_count = count.next_power_of_two() / 2;
        match (self.sub_lemma.as_ref(), self.sibling_hash.as_ref()) {
            (None, None) => 0,
            (Some(l), Some(&Positioned::Left(_))) => left_count + l.index(count - left_count),
            (Some(l), Some(&Positioned::Right(_))) => l.index(left_count),
            (None, Some(_)) | (Some(_), None) => panic!("malformed lemma"),
        }
    }

    fn new_leaf_proof(hash: &[u8], needle: &[u8]) -> Option<Lemma> {
        if *hash == *needle {
            Some(Lemma {
                node_hash: hash.into(),
                sibling_hash: None,
                sub_lemma: None,
            })
        } else {
            None
        }
    }

    fn new_tree_proof<T>(
        hash: &[u8],
        needle: &[u8],
        left: &Tree<T>,
        right: &Tree<T>,
    ) -> Option<Lemma> {
        Lemma::new(left, needle)
            .map(|lemma| {
                let right_hash = right.hash().clone();
                let sub_lemma = Some(Positioned::Right(right_hash));
                (lemma, sub_lemma)
            })
            .or_else(|| {
                let sub_lemma = Lemma::new(right, needle);
                sub_lemma.map(|lemma| {
                    let left_hash = left.hash().clone();
                    let sub_lemma = Some(Positioned::Left(left_hash));
                    (lemma, sub_lemma)
                })
            })
            .map(|(sub_lemma, sibling_hash)| Lemma {
                node_hash: hash.into(),
                sibling_hash,
                sub_lemma: Some(Box::new(sub_lemma)),
            })
    }

    fn validate(&self, algorithm: &'static Algorithm) -> bool {
        match self.sub_lemma {
            None => self.sibling_hash.is_none(),

            Some(ref sub) => match self.sibling_hash {
                None => false,

                Some(Positioned::Left(ref hash)) => {
                    let combined = algorithm.hash_nodes(hash, &sub.node_hash);
                    let hashes_match = combined.as_ref() == self.node_hash.as_slice();
                    hashes_match && sub.validate(algorithm)
                }

                Some(Positioned::Right(ref hash)) => {
                    let combined = algorithm.hash_nodes(&sub.node_hash, hash);
                    let hashes_match = combined.as_ref() == self.node_hash.as_slice();
                    hashes_match && sub.validate(algorithm)
                }
            },
        }
    }
}

/// Tags a value so that we know from which branch of a `Tree` (if any) it was found.
#[cfg_attr(
    feature = "serialization-serde",
    derive(Serialize, Deserialize)
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Positioned<T> {
    /// The value was found in the left branch
    Left(T),

    /// The value was found in the right branch
    Right(T),
}
<|endoftext|>


<commit_before>use crate::{buffer, Document, Error, Result};

#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
use image_crate::DynamicImage;

/// Format of image pixel data.
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Format {
    /// Red only.
    R8,

    /// Red, green.
    R8G8,

    /// Red, green, blue.
    R8G8B8,

    /// Red, green, blue, alpha.
    R8G8B8A8,

    /// Red only (16 bits).
    R16,

    /// Red, green (16 bits).
    R16G16,

    /// Red, green, blue (16 bits).
    R16G16B16,

    /// Red, green, blue, alpha (16 bits).
    R16G16B16A16,

    /// Red, green, blue (32 bits float)
    R32G32B32FLOAT,

    /// Red, green, blue, alpha (32 bits float)
    R32G32B32A32FLOAT,
}

/// Describes an image data source.
#[derive(Clone, Debug)]
pub enum Source<'a> {
    /// Image data is contained in a buffer view.
    View {
        /// The buffer view containing the encoded image data.
        view: buffer::View<'a>,

        /// The image data MIME type.
        mime_type: &'a str,
    },

    /// Image data is contained in an external data source.
    Uri {
        /// The URI of the external data source.
        uri: &'a str,

        /// The image data MIME type, if provided.
        mime_type: Option<&'a str>,
    },
}

/// Image data used to create a texture.
#[derive(Clone, Debug)]
pub struct Image<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::image::Image,
}

/// Image data belonging to an imported glTF asset.
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
#[derive(Clone, Debug)]
pub struct Data {
    /// The image pixel data (8 bits per channel).
    pub pixels: Vec<u8>,

    /// The image pixel data format.
    pub format: Format,

    /// The image height in pixels.
    pub width: u32,

    /// The image width in pixels.
    pub height: u32,
}

impl<'a> Image<'a> {
    /// Constructs an `Image` from owned data.
    pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::image::Image) -> Self {
        Self {
            document,
            index,
            json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
    pub fn name(&self) -> Option<&'a str> {
        self.json.name.as_deref()
    }

    /// Returns the image data source.
    pub fn source(&self) -> Source<'a> {
        if let Some(index) = self.json.buffer_view.as_ref() {
            let view = self.document.views().nth(index.value()).unwrap();
            let mime_type = self.json.mime_type.as_ref().map(|x| x.0.as_str()).unwrap();
            Source::View { view, mime_type }
        } else {
            let uri = self.json.uri.as_ref().unwrap();
            let mime_type = self.json.mime_type.as_ref().map(|x| x.0.as_str());
            Source::Uri { uri, mime_type }
        }
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &'a json::Extras {
        &self.json.extras
    }
}

#[cfg(feature = "import")]
impl Data {
    /// Note: We don't implement `From<DynamicImage>` since we don't want
    /// to expose such functionality to the user.
    pub(crate) fn new(image: DynamicImage) -> Result<Self> {
        use image_crate::GenericImageView;
        let format = match image {
            DynamicImage::ImageLuma8(_) => Format::R8,
            DynamicImage::ImageLumaA8(_) => Format::R8G8,
            DynamicImage::ImageRgb8(_) => Format::R8G8B8,
            DynamicImage::ImageRgba8(_) => Format::R8G8B8A8,
            DynamicImage::ImageLuma16(_) => Format::R16,
            DynamicImage::ImageLumaA16(_) => Format::R16G16,
            DynamicImage::ImageRgb16(_) => Format::R16G16B16,
            DynamicImage::ImageRgba16(_) => Format::R16G16B16A16,
            DynamicImage::ImageRgb32F(_) => Format::R32G32B32FLOAT,
            DynamicImage::ImageRgba32F(_) => Format::R32G32B32A32FLOAT,
            image => return Err(Error::UnsupportedImageFormat(image)),
        };
        let (width, height) = image.dimensions();
        let pixels = image.into_bytes();
        Ok(Data {
            format,
            width,
            height,
            pixels,
        })
    }
}
<commit_msg>fix image::Data width and height docstrings<commit_after>use crate::{buffer, Document, Error, Result};

#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
use image_crate::DynamicImage;

/// Format of image pixel data.
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Format {
    /// Red only.
    R8,

    /// Red, green.
    R8G8,

    /// Red, green, blue.
    R8G8B8,

    /// Red, green, blue, alpha.
    R8G8B8A8,

    /// Red only (16 bits).
    R16,

    /// Red, green (16 bits).
    R16G16,

    /// Red, green, blue (16 bits).
    R16G16B16,

    /// Red, green, blue, alpha (16 bits).
    R16G16B16A16,

    /// Red, green, blue (32 bits float)
    R32G32B32FLOAT,

    /// Red, green, blue, alpha (32 bits float)
    R32G32B32A32FLOAT,
}

/// Describes an image data source.
#[derive(Clone, Debug)]
pub enum Source<'a> {
    /// Image data is contained in a buffer view.
    View {
        /// The buffer view containing the encoded image data.
        view: buffer::View<'a>,

        /// The image data MIME type.
        mime_type: &'a str,
    },

    /// Image data is contained in an external data source.
    Uri {
        /// The URI of the external data source.
        uri: &'a str,

        /// The image data MIME type, if provided.
        mime_type: Option<&'a str>,
    },
}

/// Image data used to create a texture.
#[derive(Clone, Debug)]
pub struct Image<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::image::Image,
}

/// Image data belonging to an imported glTF asset.
#[cfg(feature = "import")]
#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
#[derive(Clone, Debug)]
pub struct Data {
    /// The image pixel data (8 bits per channel).
    pub pixels: Vec<u8>,

    /// The image pixel data format.
    pub format: Format,

    /// The image width in pixels.
    pub width: u32,

    /// The image height in pixels.
    pub height: u32,
}

impl<'a> Image<'a> {
    /// Constructs an `Image` from owned data.
    pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::image::Image) -> Self {
        Self {
            document,
            index,
            json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
    pub fn name(&self) -> Option<&'a str> {
        self.json.name.as_deref()
    }

    /// Returns the image data source.
    pub fn source(&self) -> Source<'a> {
        if let Some(index) = self.json.buffer_view.as_ref() {
            let view = self.document.views().nth(index.value()).unwrap();
            let mime_type = self.json.mime_type.as_ref().map(|x| x.0.as_str()).unwrap();
            Source::View { view, mime_type }
        } else {
            let uri = self.json.uri.as_ref().unwrap();
            let mime_type = self.json.mime_type.as_ref().map(|x| x.0.as_str());
            Source::Uri { uri, mime_type }
        }
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &'a json::Extras {
        &self.json.extras
    }
}

#[cfg(feature = "import")]
impl Data {
    /// Note: We don't implement `From<DynamicImage>` since we don't want
    /// to expose such functionality to the user.
    pub(crate) fn new(image: DynamicImage) -> Result<Self> {
        use image_crate::GenericImageView;
        let format = match image {
            DynamicImage::ImageLuma8(_) => Format::R8,
            DynamicImage::ImageLumaA8(_) => Format::R8G8,
            DynamicImage::ImageRgb8(_) => Format::R8G8B8,
            DynamicImage::ImageRgba8(_) => Format::R8G8B8A8,
            DynamicImage::ImageLuma16(_) => Format::R16,
            DynamicImage::ImageLumaA16(_) => Format::R16G16,
            DynamicImage::ImageRgb16(_) => Format::R16G16B16,
            DynamicImage::ImageRgba16(_) => Format::R16G16B16A16,
            DynamicImage::ImageRgb32F(_) => Format::R32G32B32FLOAT,
            DynamicImage::ImageRgba32F(_) => Format::R32G32B32A32FLOAT,
            image => return Err(Error::UnsupportedImageFormat(image)),
        };
        let (width, height) = image.dimensions();
        let pixels = image.into_bytes();
        Ok(Data {
            format,
            width,
            height,
            pixels,
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Dario Domizioli
//
// 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.

use rustc_serialize::json;

use std::collections::HashMap;
use regex;

use structure;

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub enum StorageAction {
    StoreSingle,
    StoreVector,
    StoreMapSingle,
    StoreMapVector,
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct StorageSpec {
    action: StorageAction,
    replace: String,
    variable: String,
    key: String
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct RuleSpec {
    name: String,
    regex: String,
    replace: String,
    storage: Vec<StorageSpec>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct RuleSpecContainer {
    rules: Vec<RuleSpec>
}

impl RuleSpecContainer {
    fn validate_rules(rsc: &RuleSpecContainer) -> Result<(), String> {
        let valid_names = regex::Regex::new("^[_0-9a-zA-Z]+$").unwrap();
        for r in rsc.rules.iter() {
            match regex::Regex::new(&r.regex) {
                Ok(_) => (),
                Err(_) => {
                    return Err("Regular expression '".to_string() + &r.regex +
                               "' in rule '" + &r.name + "' is invalid.");
                }
            }
            for s in r.storage.iter() {
                if !valid_names.is_match(&s.variable) {
                    return Err("Variable name '".to_string() + &s.variable +
                               "' in rule '" + &r.name + "'is invalid. " +
                               "Please only use underscores, digits and " +
                               "ASCII letters.");
                }
            }
        }
        Ok(())
    }

    pub fn from_json(js: &str) -> Result<RuleSpecContainer, String> {
        let rsc = match json::decode::<RuleSpecContainer>(js) {
            Ok(x) => x,
            Err(e) => {
                return Err(
                    (format!("Error parsing rules JSON: {}", e)).to_string());
            }
        };
        match RuleSpecContainer::validate_rules(&rsc) {
            Ok(_) => (),
            Err(e) => { return Err(e); }
        }
        Ok(rsc)
    }
}

struct VarVariant {
    single:     String,
    vector:     Vec<String>,
    map_single: HashMap<String, String>,
    map_vector: HashMap<String, Vec<String>>,
}

pub struct RulesEngine {
    variables: HashMap<String, VarVariant>
}

impl RulesEngine {
    pub fn new() -> RulesEngine {
        RulesEngine {
            variables: HashMap::new()
        }
    }

    pub fn apply_rule(&mut self, rule: &RuleSpec,
                      content: &mut structure::Content) -> Result<(), String> {
        // We have validated regexps before, so this must work.
        let re = regex::Regex::new(&rule.regex).unwrap();
        // Match and perform operations.
        for mut chunk in content.chunks.iter_mut() {
            // Process each match for storage
            for cap in re.captures_iter(&chunk) {
                for s in rule.storage.iter() {
                    let processed_key = cap.expand(s.key.as_str());
                    let valid_key = regex::Regex::new(
                        "^[_0-9a-zA-Z]+$").unwrap();
                    if !valid_key.is_match(&processed_key) {
                        return Err("Captured key '".to_string() +
                                   &processed_key +
                                   "' obtained from text when applying rule '" +
                                   &rule.name +
                                   "' is invalid. Please only use " +
                                   "underscores, digits, and ASCII letters.");
                    }
                    let processed_value = cap.expand(s.replace.as_str());
                    if !self.variables.contains_key(&s.variable) {
                        self.variables.insert(s.variable.clone(), VarVariant {
                            single: String::new(),
                            vector: Vec::new(),
                            map_single: HashMap::new(),
                            map_vector: HashMap::new()
                        });
                    }
                    match s.action {
                        StorageAction::StoreSingle => {
                            self.variables.get_mut(&s.variable).unwrap(
                                ).single = processed_value;
                        },
                        StorageAction::StoreVector => {
                            self.variables.get_mut(&s.variable).unwrap(
                                ).vector.push(processed_value);
                        },
                        StorageAction::StoreMapSingle => {
                            self.variables.get_mut(&s.variable).unwrap(
                                ).map_single.insert(processed_key,
                                                    processed_value);
                        },
                        StorageAction::StoreMapVector => {
                            let must_init = !self.variables.get(&s.variable)
                                            .unwrap().map_vector
                                            .contains_key(&processed_key);
                            if must_init {
                                self.variables.get_mut(&s.variable).unwrap()
                                    .map_vector.insert(
                                        processed_key.clone(), Vec::new());
                            }
                            self.variables.get_mut(&s.variable).unwrap(
                                ).map_vector.get_mut(&processed_key).unwrap(
                                    ).push(processed_value);
                        },
                    }
                }
            }
            // Finally replace all matches
            let new_chunk = re.replace_all(&chunk, rule.replace.as_str());
            // Surely there's an easier way of doing this...
            // Why isn't there a String.swap()?
            chunk.clear();
            chunk.push_str(&new_chunk);
        }
        Ok(())
    }

    pub fn apply_rules(&mut self, rules: &RuleSpecContainer,
                       content: &mut structure::Content) -> Result<(), String> {
        for rule in rules.rules.iter() {
            match self.apply_rule(rule, content) {
                Ok(_) => (),
                Err(e) => { return Err(e); }
            }
        }
        Ok(())
    }

    pub fn substitute_vars(&self, content: &mut structure::Content)
    -> Result<(), String>  {
        let re_map_var = regex::Regex::new(
            r"\{\{\s*([_0-9a-zA-Z]+)\.([_0-9a-zA-Z]+)\s*\}\}").unwrap();
        let re_single_var = regex::Regex::new(
            r"\{\{\s*([_0-9a-zA-Z]+)\s*\}\}").unwrap();
        for mut chunk in content.chunks.iter_mut() {
            // Try the map variables first.
            while let Some(m) = re_map_var.captures(&chunk.clone()) {
                let var_name = m.at(1).unwrap();
                let var_key = m.at(2).unwrap();
                match self.variables.get(var_name) {
                    Some(var) => {
                        match var.map_single.get(var_key) {
                            Some(value) => {
                                let new_chunk = re_map_var.replace(
                                    &chunk, regex::NoExpand(value));
                                // Why isn't there a String.swap()?
                                chunk.clear();
                                chunk.push_str(&new_chunk);
                                continue;
                            },
                            None => ()
                        }
                        match var.map_vector.get(var_key) {
                            Some(vector) => {
                                let new_chunk = re_map_var.replace(
                                    &chunk, regex::NoExpand(&vector.join("\n")));
                                // Why isn't there a String.swap()?
                                chunk.clear();
                                chunk.push_str(&new_chunk);
                                continue;
                            },
                            None => ()
                        }
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' does not contain key '" +
                                   &var_key + "' at the point of " +
                                   "variable substitution.");
                    },
                    None => {
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' is not defined at the point of " +
                                   "variable substitution.");
                    }
                }
            }
            // Then try the non-map variables.
            while let Some(m) = re_single_var.captures(&chunk.clone()) {
                let var_name = m.at(1).unwrap();
                match self.variables.get(var_name) {
                    Some(var) => {
                        if !var.single.is_empty() {
                            let new_chunk = re_map_var.replace(
                                &chunk, regex::NoExpand(&var.single));
                            // Why isn't there a String.swap()?
                            chunk.clear();
                            chunk.push_str(&new_chunk);
                            continue;
                        }
                        if !var.vector.is_empty() {
                            let new_chunk = re_map_var.replace(
                                &chunk, regex::NoExpand(&var.vector.join("\n")));
                            // Why isn't there a String.swap()?
                            chunk.clear();
                            chunk.push_str(&new_chunk);
                            continue;
                        }
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' is not a single value nor a vector " +
                                   "at the point of " +
                                   "variable substitution.");
                    },
                    None => {
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' is not defined at the point of " +
                                   "variable substitution.");
                    }
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Fixed bugs in variables substitution engine, added first implementation of map formatting when substituting variables<commit_after>// Copyright 2016 Dario Domizioli
//
// 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.

use rustc_serialize::json;

use std::collections::HashMap;
use regex;

use structure;

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub enum StorageAction {
    StoreSingle,
    StoreVector,
    StoreMapSingle,
    StoreMapVector,
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct StorageSpec {
    action: StorageAction,
    replace: String,
    variable: String,
    key: String
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct RuleSpec {
    name: String,
    regex: String,
    replace: String,
    storage: Vec<StorageSpec>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct RuleSpecContainer {
    rules: Vec<RuleSpec>
}

impl RuleSpecContainer {
    fn validate_rules(rsc: &RuleSpecContainer) -> Result<(), String> {
        let valid_names = regex::Regex::new("^[_0-9a-zA-Z]+$").unwrap();
        for r in rsc.rules.iter() {
            match regex::Regex::new(&r.regex) {
                Ok(_) => (),
                Err(_) => {
                    return Err("Regular expression '".to_string() + &r.regex +
                               "' in rule '" + &r.name + "' is invalid.");
                }
            }
            for s in r.storage.iter() {
                if !valid_names.is_match(&s.variable) {
                    return Err("Variable name '".to_string() + &s.variable +
                               "' in rule '" + &r.name + "'is invalid. " +
                               "Please only use underscores, digits and " +
                               "ASCII letters.");
                }
            }
        }
        Ok(())
    }

    pub fn from_json(js: &str) -> Result<RuleSpecContainer, String> {
        let rsc = match json::decode::<RuleSpecContainer>(js) {
            Ok(x) => x,
            Err(e) => {
                return Err(
                    (format!("Error parsing rules JSON: {}", e)).to_string());
            }
        };
        match RuleSpecContainer::validate_rules(&rsc) {
            Ok(_) => (),
            Err(e) => { return Err(e); }
        }
        Ok(rsc)
    }
}

struct VarVariant {
    single:     String,
    vector:     Vec<String>,
    map_single: HashMap<String, String>,
    map_vector: HashMap<String, Vec<String>>,
}

pub struct RulesEngine {
    variables: HashMap<String, VarVariant>
}

impl RulesEngine {
    pub fn new() -> RulesEngine {
        RulesEngine {
            variables: HashMap::new()
        }
    }

    pub fn apply_rule(&mut self, rule: &RuleSpec,
                      content: &mut structure::Content) -> Result<(), String> {
        // We have validated regexps before, so this must work.
        let re = regex::Regex::new(&rule.regex).unwrap();
        // Match and perform operations.
        for mut chunk in content.chunks.iter_mut() {
            // Process each match for storage
            for cap in re.captures_iter(&chunk) {
                for s in rule.storage.iter() {
                    let processed_key = cap.expand(s.key.as_str());
                    let valid_key = regex::Regex::new(
                        "^[_0-9a-zA-Z]+$").unwrap();
                    if !valid_key.is_match(&processed_key) {
                        return Err("Captured key '".to_string() +
                                   &processed_key +
                                   "' obtained from text when applying rule '" +
                                   &rule.name +
                                   "' is invalid. Please only use " +
                                   "underscores, digits, and ASCII letters.");
                    }
                    let processed_value = cap.expand(s.replace.as_str());
                    if !self.variables.contains_key(&s.variable) {
                        self.variables.insert(s.variable.clone(), VarVariant {
                            single: String::new(),
                            vector: Vec::new(),
                            map_single: HashMap::new(),
                            map_vector: HashMap::new()
                        });
                    }
                    match s.action {
                        StorageAction::StoreSingle => {
                            self.variables.get_mut(&s.variable).unwrap(
                                ).single = processed_value;
                        },
                        StorageAction::StoreVector => {
                            self.variables.get_mut(&s.variable).unwrap(
                                ).vector.push(processed_value);
                        },
                        StorageAction::StoreMapSingle => {
                            self.variables.get_mut(&s.variable).unwrap(
                                ).map_single.insert(processed_key,
                                                    processed_value);
                        },
                        StorageAction::StoreMapVector => {
                            let must_init = !self.variables.get(&s.variable)
                                            .unwrap().map_vector
                                            .contains_key(&processed_key);
                            if must_init {
                                self.variables.get_mut(&s.variable).unwrap()
                                    .map_vector.insert(
                                        processed_key.clone(), Vec::new());
                            }
                            self.variables.get_mut(&s.variable).unwrap(
                                ).map_vector.get_mut(&processed_key).unwrap(
                                    ).push(processed_value);
                        },
                    }
                }
            }
            // Finally replace all matches
            let new_chunk = re.replace_all(&chunk, rule.replace.as_str());
            // Surely there's an easier way of doing this...
            // Why isn't there a String.swap()?
            chunk.clear();
            chunk.push_str(&new_chunk);
        }
        Ok(())
    }

    pub fn apply_rules(&mut self, rules: &RuleSpecContainer,
                       content: &mut structure::Content) -> Result<(), String> {
        for rule in rules.rules.iter() {
            match self.apply_rule(rule, content) {
                Ok(_) => (),
                Err(e) => { return Err(e); }
            }
        }
        Ok(())
    }

    fn construct_map_content(&self, m: &HashMap<String, String>) -> String {
        m.iter().map(|(k, v)| {
            format!("{}: {}", k, v)
        }).fold(String::new(), |acc, x| {
            acc + "\n\n" + &x
        })
    }

    fn construct_mapv_content(&self, m: &HashMap<String, Vec<String>>) -> String {
        m.iter().map(|(k, v)| {
            format!("{}: {}", k, v.iter().fold(String::new(), |acc, x| {
                acc + " " + &x
            }))
        }).fold(String::new(), |acc, x| {
            acc + "\n\n" + &x
        })
    }

    pub fn substitute_vars(&self, content: &mut structure::Content)
    -> Result<(), String>  {
        let re_keyed_var = regex::Regex::new(
            r"\{\{\s*([_0-9a-zA-Z]+)\.([_0-9a-zA-Z]+)\s*\}\}").unwrap();
        let re_plain_var = regex::Regex::new(
            r"\{\{\s*([_0-9a-zA-Z]+)\s*\}\}").unwrap();
        for mut chunk in content.chunks.iter_mut() {
            // Loop until there isn't anything to substitute anymore.
            while let Some(m) = re_keyed_var.captures(&chunk.clone()) {
                let var_name = m.at(1).unwrap();
                let var_key = m.at(2).unwrap();
                match self.variables.get(var_name) {
                    Some(var) => {
                        match var.map_single.get(var_key) {
                            Some(value) => {
                                let new_chunk = re_keyed_var.replace(
                                    &chunk, regex::NoExpand(value));
                                // Why isn't there a String.swap()?
                                chunk.clear();
                                chunk.push_str(&new_chunk);
                                continue;
                            },
                            None => ()
                        }
                        match var.map_vector.get(var_key) {
                            Some(vector) => {
                                let new_chunk = re_keyed_var.replace(
                                    &chunk, regex::NoExpand(
                                        &vector.join("\n\n")));
                                // Why isn't there a String.swap()?
                                chunk.clear();
                                chunk.push_str(&new_chunk);
                                continue;
                            },
                            None => ()
                        }
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' does not contain key '" +
                                   &var_key + "' at the point of " +
                                   "variable substitution.");
                    },
                    None => {
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' is not defined at the point of " +
                                   "variable substitution.");
                    }
                }
            }
            while let Some(m) = re_plain_var.captures(&chunk.clone()) {
                let var_name = m.at(1).unwrap();
                match self.variables.get(var_name) {
                    Some(var) => {
                        if !var.single.is_empty() {
                            let new_chunk = re_plain_var.replace(
                                &chunk, regex::NoExpand(&var.single));
                            // Why isn't there a String.swap()?
                            chunk.clear();
                            chunk.push_str(&new_chunk);
                            continue;
                        }
                        if !var.vector.is_empty() {
                            let new_chunk = re_plain_var.replace(
                                &chunk, regex::NoExpand(
                                    &var.vector.join("\n\n")));
                            // Why isn't there a String.swap()?
                            chunk.clear();
                            chunk.push_str(&new_chunk);
                            continue;
                        }
                        if !var.map_single.is_empty() {
                            let new_chunk = re_plain_var.replace(
                                &chunk, regex::NoExpand(
                                    &self.construct_map_content(
                                        &var.map_single)));
                            // Why isn't there a String.swap()?
                            chunk.clear();
                            chunk.push_str(&new_chunk);
                            continue;
                        }
                        if !var.map_vector.is_empty() {
                            let new_chunk = re_plain_var.replace(
                                &chunk, regex::NoExpand(
                                    &self.construct_mapv_content(
                                        &var.map_vector)));
                            // Why isn't there a String.swap()?
                            chunk.clear();
                            chunk.push_str(&new_chunk);
                            continue;
                        }
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' does not contain content " +
                                   "at the point of " +
                                   "variable substitution.");
                    },
                    None => {
                        return Err("Variable '".to_string() +
                                   &var_name +
                                   "' is not defined at the point of " +
                                   "variable substitution.");
                    }
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::{Read};

use getopts;

use hyper::{Client};
use hyper::status::{StatusCode};

use rustc_serialize::{json};

use super::{CreateServiceResult, Service, ServiceFactory, ServiceResult, User};

#[derive(RustcDecodable)]
struct SlackUserListResponse {
    ok: bool,
    members: Vec<SlackUser>,
}

#[derive(RustcDecodable)]
struct SlackUser {
    name: String,
    deleted: bool,
    is_bot: bool,
    has_2fa: Option<bool>,
    profile: SlackProfile,
    is_owner: Option<bool>,
    is_admin: Option<bool>,
}

#[derive(RustcDecodable)]
struct SlackProfile {
    email: Option<String>,
}

pub struct SlackServiceFactory;

impl ServiceFactory for SlackServiceFactory {
    fn add_options(&self, opts: &mut getopts::Options) {
        opts.optopt(
            "", "slack-token", "Slack token (https://api.slack.com/web#authentication)", "token"
        );
    }

    fn create_service(&self, matches: &getopts::Matches) -> CreateServiceResult {
        match matches.opt_str("slack-token") {
            Some(token) => CreateServiceResult::Service(Box::new(SlackService{
                token: token
            })),
            None => CreateServiceResult::None,
        }
    }
}

struct SlackService {
    token: String,
}

impl Service for SlackService {
    fn get_users(&self) -> ServiceResult {
        let client = Client::new();

        let mut response = client.get(
            &format!("https://slack.com/api/users.list?token={}", self.token)
        ).send().unwrap();
        assert_eq!(response.status, StatusCode::Ok);
        let mut body = String::new();
        response.read_to_string(&mut body).unwrap();

        let result = json::decode::<SlackUserListResponse>(&body).unwrap();
        assert!(result.ok);
        let users = result.members.iter().filter(|user| {
            match (user.deleted, user.is_bot, user.has_2fa) {
                (true, _, _) => false,
                (false, true, _) => false,
                (false, false, None) => true,
                (false, false, Some(true)) => false,
                (false, false, Some(false)) => true,
            }
        }).map(|user|
            User{
                name: user.name.to_string(),
                email: match user.profile.email {
                    Some(ref m) => Some(m.to_string()),
                    None => None
                },
                details: match (user.is_owner.unwrap(), user.is_admin.unwrap()) {
                    (true, true) => Some("Owner/Admin".to_string()),
                    (true, false) => Some("Owner".to_string()),
                    (false, true) => Some("Admin".to_string()),
                    (false, false) => None
                }
            }
        ).collect();

        return ServiceResult{
            service_name: "Slack".to_string(),
            users: users,
        }
    }
}
<commit_msg>alternative to match<commit_after>use std::io::{Read};

use getopts;

use hyper::{Client};
use hyper::status::{StatusCode};

use rustc_serialize::{json};

use super::{CreateServiceResult, Service, ServiceFactory, ServiceResult, User};

#[derive(RustcDecodable)]
struct SlackUserListResponse {
    ok: bool,
    members: Vec<SlackUser>,
}

#[derive(RustcDecodable)]
struct SlackUser {
    name: String,
    deleted: bool,
    is_bot: bool,
    has_2fa: Option<bool>,
    profile: SlackProfile,
    is_owner: Option<bool>,
    is_admin: Option<bool>,
}

#[derive(RustcDecodable)]
struct SlackProfile {
    email: Option<String>,
}

pub struct SlackServiceFactory;

impl ServiceFactory for SlackServiceFactory {
    fn add_options(&self, opts: &mut getopts::Options) {
        opts.optopt(
            "", "slack-token", "Slack token (https://api.slack.com/web#authentication)", "token"
        );
    }

    fn create_service(&self, matches: &getopts::Matches) -> CreateServiceResult {
        match matches.opt_str("slack-token") {
            Some(token) => CreateServiceResult::Service(Box::new(SlackService{
                token: token
            })),
            None => CreateServiceResult::None,
        }
    }
}

struct SlackService {
    token: String,
}

impl Service for SlackService {
    fn get_users(&self) -> ServiceResult {
        let client = Client::new();

        let mut response = client.get(
            &format!("https://slack.com/api/users.list?token={}", self.token)
        ).send().unwrap();
        assert_eq!(response.status, StatusCode::Ok);
        let mut body = String::new();
        response.read_to_string(&mut body).unwrap();

        let result = json::decode::<SlackUserListResponse>(&body).unwrap();
        assert!(result.ok);
        let users = result.members.iter().filter(|user| {
            match (user.deleted, user.is_bot, user.has_2fa) {
                (true, _, _) => false,
                (false, true, _) => false,
                (false, false, None) => true,
                (false, false, Some(true)) => false,
                (false, false, Some(false)) => true,
            }
        }).map(|user|
            User{
                name: user.name.to_string(),
                email: Some(user.profile.email.clone().unwrap()),
                details: match (user.is_owner.unwrap(), user.is_admin.unwrap()) {
                    (true, true) => Some("Owner/Admin".to_string()),
                    (true, false) => Some("Owner".to_string()),
                    (false, true) => Some("Admin".to_string()),
                    (false, false) => None
                }
            }
        ).collect();

        return ServiceResult{
            service_name: "Slack".to_string(),
            users: users,
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Result as IoResult;
use std::io::Error as IoError;
use std::io::ErrorKind as IoErrorKind;
use {MemReader, ReadsMemory};

pub struct MemorySlice<'a> {
  pub start: usize,
  pub end: usize,
  reader: &'a MemReader,
  mark: Option<usize>
}

impl<'a> MemorySlice<'a> {
  pub fn new(reader: &'a MemReader, start: usize, end: usize) -> Self {
    MemorySlice {
      start: start,
      end: end,
      reader: reader,
      mark: None
    }
  }
}

impl<'a> Read for MemorySlice<'a> {
  fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
    let start = match self.mark {
      Some(m) => m,
      None => self.start
    };
    let buf_len = buf.len();
    if start + buf_len > self.end {
      return Ok(0);
    }
    let bytes = self.reader.read_bytes(start, buf_len).map_err(|e| IoError::new(IoErrorKind::Other, e))?;
    let bytes_len = bytes.len();
    self.mark = Some(start + buf_len);
    for (i, byte) in bytes.into_iter().enumerate() {
      buf[i] = byte;
    }
    Ok(bytes_len)
  }
}
<commit_msg>refactor: make start and end fields private<commit_after>use std::io::Read;
use std::io::Result as IoResult;
use std::io::Error as IoError;
use std::io::ErrorKind as IoErrorKind;
use {MemReader, ReadsMemory};

pub struct MemorySlice<'a> {
  start: usize,
  end: usize,
  reader: &'a MemReader,
  mark: Option<usize>
}

impl<'a> MemorySlice<'a> {
  pub fn new(reader: &'a MemReader, start: usize, end: usize) -> Self {
    MemorySlice {
      start: start,
      end: end,
      reader: reader,
      mark: None
    }
  }

  /// The start address of this slice.
  pub fn start(&self) -> usize {
    self.start
  }

  /// The end address of this slice.
  pub fn end(&self) -> usize {
    self.end
  }
}

impl<'a> Read for MemorySlice<'a> {
  fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
    let start = match self.mark {
      Some(m) => m,
      None => self.start
    };
    let buf_len = buf.len();
    if start + buf_len > self.end {
      return Ok(0);
    }
    let bytes = self.reader.read_bytes(start, buf_len).map_err(|e| IoError::new(IoErrorKind::Other, e))?;
    let bytes_len = bytes.len();
    self.mark = Some(start + buf_len);
    for (i, byte) in bytes.into_iter().enumerate() {
      buf[i] = byte;
    }
    Ok(bytes_len)
  }
}
<|endoftext|>