<commit_before>use num::{Integer, range, ToPrimitive};

use std::marker::PhantomData;
use std::cell::Cell;

use super::{Map, Error, StorageValue};

use ::crypto::{hash, Hash};

/// Merkle tree over list.
/// Данные в таблице хранятся в строчках,
/// высота определяется количеством записаных значений H = len / 2 +1
/// H  | Элементы
/// 0  | Записанные данные
/// 1  | Хэши от исходных данных
/// 2..| Дерево хешей, где каждая новая высота считает Hash(Hash(h - 1, i), Hash(h - 1, i + 1))
pub struct MerkleTable<T: Map<[u8], Vec<u8>>, K, V> {
    map: T,
    count: Cell<Option<K>>,
    _v: PhantomData<V>,
}

impl<'a, T, K, V> MerkleTable<T, K, V>
    where T: Map<[u8], Vec<u8>>,
          K: Integer + Copy + Clone + ToPrimitive + StorageValue,
          V: StorageValue
{
    pub fn new(map: T) -> Self {
        MerkleTable {
            map: map,
            count: Cell::new(None),
            _v: PhantomData,
        }
    }

    pub fn append(&mut self, value: V) -> Result<(), Error> {
        let len = self.len()?;
        let bytes = value.serialize();
        self.rebuild_hash(len, &bytes)?;

        self.map.put(&Self::db_key(K::zero(), len), bytes)?;
        self.set_len(len + K::one())?;
        Ok(())
    }

    pub fn extend<I>(&mut self, iter: I) -> Result<(), Error>
        where I: IntoIterator<Item = V>
    {
        for value in iter {
            self.append(value)?;
        }
        Ok(())
    }

    pub fn get(&self, index: K) -> Result<Option<V>, Error> {
        let value = self.map.get(&Self::db_key(K::zero(), index))?;
        Ok(value.map(StorageValue::deserialize))
    }

    pub fn last(&self) -> Result<Option<V>, Error> {
        let len = self.len()?;
        if len == K::zero() {
            Ok(None)
        } else {
            self.get(len - K::one())
        }
    }

    // TODO: implement iterator for List
    pub fn iter(&self) -> Result<Option<Vec<V>>, Error> {
        Ok(if self.is_empty()? {
            None
        } else {
            Some(range(K::zero(), self.len()?).map(|i| self.get(i).unwrap().unwrap()).collect())
        })
    }

    pub fn is_empty(&self) -> Result<bool, Error> {
        Ok(self.len()? == K::zero())
    }

    pub fn len(&self) -> Result<K, Error> {
        if let Some(count) = self.count.get() {
            return Ok(count);
        }

        let v = self.map.get(&[])?;
        let c = v.map(K::deserialize).unwrap_or(K::zero());
        self.count.set(Some(c));
        Ok(c)
    }

    pub fn root_hash(&self) -> Result<Option<Hash>, Error> {
        self.get_hash(self.height()?, K::zero())
    }

    fn height(&self) -> Result<K, Error> {
        let len = self.len()?;
        let h = Self::upper_power_of_two(len) + K::one();
        Ok(h)
    }

    // TODO replace by library method
    fn upper_power_of_two(v: K) -> K {
        let mut p = K::one();
        let mut i = K::zero();
        while p < v {
            p = p * (K::one() + K::one());
            i = i + K::one();
        }
        i
    }

    fn set_len(&mut self, len: K) -> Result<(), Error> {
        self.count.set(Some(len));
        self.map.put(&[], len.serialize())
    }

    fn db_key(h: K, i: K) -> Vec<u8> {
        [h.serialize(), i.serialize()].concat()
    }

    fn get_hash(&self, height: K, index: K) -> Result<Option<Hash>, Error> {
        debug_assert!(height > K::zero());

        let v = self.map.get(&Self::db_key(height, index))?;
        let hash = v.map(|x| {
            debug_assert_eq!(x.len(), 32);
            Hash::from_slice(&x).unwrap()
        });
        Ok(hash)
    }

    fn rebuild_hash(&mut self, mut index: K, bytes: &Vec<u8>) -> Result<(), Error> {
        //FIXME avoid reallocation
        self.map.put(&Self::db_key(K::one(), index), hash(bytes).serialize())?;
        let mut current_height = K::one();
        while index != K::zero() {
            // Left leaf, Right leaf is empty
            let new_hash = if index.is_even() {
                let h1 = self.get_hash(current_height, index)?.unwrap(); //TODO replace by error
                h1
            } else {
            // Right leaf
                let h1 = self.get_hash(current_height, index - K::one())?.unwrap();
                let h2 = self.get_hash(current_height, index)?.unwrap();
                hash(&[h1.as_ref(), h2.as_ref()].concat())
            };
            current_height = current_height + K::one();
            index = index / (K::one() + K::one());
            self.map.put(&Self::db_key(current_height, index), new_hash.serialize())?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;

    use ::crypto::{hash};
    use ::storage::{MemoryDB, MapExt};

    #[test]
    fn height() {
        let mut storage = MemoryDB::new();
        let mut table = storage.merkle_list(vec![255]);

        table.append(vec![1]).unwrap();
        assert_eq!(table.height().unwrap(), 1);

        table.append(vec![2]).unwrap();
        assert_eq!(table.height().unwrap(), 2);

        table.append(vec![3]).unwrap();
        assert_eq!(table.height().unwrap(), 3);

        table.append(vec![4]).unwrap();
        assert_eq!(table.height().unwrap(), 3);

        assert_eq!(table.len().unwrap(), 4);
        assert_eq!(table.get(0u32).unwrap(), Some(vec![1]));
        assert_eq!(table.get(1).unwrap(), Some(vec![2]));
        assert_eq!(table.get(2).unwrap(), Some(vec![3]));
        assert_eq!(table.get(3).unwrap(), Some(vec![4]));
    }

    #[test]
    fn hashes() {
        let mut storage = MemoryDB::new();
        let mut table = storage.merkle_list(vec![255]);

        let h1 = hash(&vec![1]);
        let h2 = hash(&vec![2]);
        let h3 = hash(&vec![3]);
        let h4 = hash(&vec![4]);
        let h12 = hash(&[h1.as_ref(), h2.as_ref()].concat());
        let h34 = hash(&[h3.as_ref(), h4.as_ref()].concat());
        let h123 = hash(&[h12.as_ref(), h3.as_ref()].concat());
        let h1234 = hash(&[h12.as_ref(), h34.as_ref()].concat());

        table.append(vec![1]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h1));

        table.append(vec![2]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h12));

        table.append(vec![3]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h123));

        table.append(vec![4]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h1234));

        assert_eq!(table.get(0u32).unwrap(), Some(vec![1]));
    }
}
<commit_msg>Add a more complete test<commit_after>use num::{Integer, range, ToPrimitive};

use std::marker::PhantomData;
use std::cell::Cell;

use super::{Map, Error, StorageValue};

use ::crypto::{hash, Hash};

/// Merkle tree over list.
/// Данные в таблице хранятся в строчках,
/// высота определяется количеством записаных значений H = len / 2 +1
/// H  | Элементы
/// 0  | Записанные данные
/// 1  | Хэши от исходных данных
/// 2..| Дерево хешей, где каждая новая высота считает Hash(Hash(h - 1, i), Hash(h - 1, i + 1))
pub struct MerkleTable<T: Map<[u8], Vec<u8>>, K, V> {
    map: T,
    count: Cell<Option<K>>,
    _v: PhantomData<V>,
}

impl<'a, T, K, V> MerkleTable<T, K, V>
    where T: Map<[u8], Vec<u8>>,
          K: Integer + Copy + Clone + ToPrimitive + StorageValue,
          V: StorageValue
{
    pub fn new(map: T) -> Self {
        MerkleTable {
            map: map,
            count: Cell::new(None),
            _v: PhantomData,
        }
    }

    pub fn append(&mut self, value: V) -> Result<(), Error> {
        let len = self.len()?;
        let bytes = value.serialize();
        self.rebuild_hash(len, &bytes)?;

        self.map.put(&Self::db_key(K::zero(), len), bytes)?;
        self.set_len(len + K::one())?;
        Ok(())
    }

    pub fn extend<I>(&mut self, iter: I) -> Result<(), Error>
        where I: IntoIterator<Item = V>
    {
        for value in iter {
            self.append(value)?;
        }
        Ok(())
    }

    pub fn get(&self, index: K) -> Result<Option<V>, Error> {
        let value = self.map.get(&Self::db_key(K::zero(), index))?;
        Ok(value.map(StorageValue::deserialize))
    }

    pub fn last(&self) -> Result<Option<V>, Error> {
        let len = self.len()?;
        if len == K::zero() {
            Ok(None)
        } else {
            self.get(len - K::one())
        }
    }

    // TODO: implement iterator for List
    pub fn iter(&self) -> Result<Option<Vec<V>>, Error> {
        Ok(if self.is_empty()? {
            None
        } else {
            Some(range(K::zero(), self.len()?).map(|i| self.get(i).unwrap().unwrap()).collect())
        })
    }

    pub fn is_empty(&self) -> Result<bool, Error> {
        Ok(self.len()? == K::zero())
    }

    pub fn len(&self) -> Result<K, Error> {
        if let Some(count) = self.count.get() {
            return Ok(count);
        }

        let v = self.map.get(&[])?;
        let c = v.map(K::deserialize).unwrap_or(K::zero());
        self.count.set(Some(c));
        Ok(c)
    }

    pub fn root_hash(&self) -> Result<Option<Hash>, Error> {
        self.get_hash(self.height()?, K::zero())
    }

    fn height(&self) -> Result<K, Error> {
        let len = self.len()?;
        let h = Self::upper_power_of_two(len) + K::one();
        Ok(h)
    }

    // TODO replace by library method
    fn upper_power_of_two(v: K) -> K {
        let mut p = K::one();
        let mut i = K::zero();
        while p < v {
            p = p * (K::one() + K::one());
            i = i + K::one();
        }
        i
    }

    fn set_len(&mut self, len: K) -> Result<(), Error> {
        self.count.set(Some(len));
        self.map.put(&[], len.serialize())
    }

    fn db_key(h: K, i: K) -> Vec<u8> {
        [h.serialize(), i.serialize()].concat()
    }

    fn get_hash(&self, height: K, index: K) -> Result<Option<Hash>, Error> {
        debug_assert!(height > K::zero());

        let v = self.map.get(&Self::db_key(height, index))?;
        let hash = v.map(|x| {
            debug_assert_eq!(x.len(), 32);
            Hash::from_slice(&x).unwrap()
        });
        Ok(hash)
    }

    fn rebuild_hash(&mut self, mut index: K, bytes: &Vec<u8>) -> Result<(), Error> {
        //FIXME avoid reallocation
        self.map.put(&Self::db_key(K::one(), index), hash(bytes).serialize())?;
        let mut current_height = K::one();
        while index != K::zero() {
            // Left leaf, Right leaf is empty
            let new_hash = if index.is_even() {
                let h1 = self.get_hash(current_height, index)?.unwrap(); //TODO replace by error
                h1
            } else {
            // Right leaf
                let h1 = self.get_hash(current_height, index - K::one())?.unwrap();
                let h2 = self.get_hash(current_height, index)?.unwrap();
                hash(&[h1.as_ref(), h2.as_ref()].concat())
            };
            current_height = current_height + K::one();
            index = index / (K::one() + K::one());
            self.map.put(&Self::db_key(current_height, index), new_hash.serialize())?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;

    use ::crypto::{hash};
    use ::storage::{MemoryDB, MapExt};

    #[test]
    fn height() {
        let mut storage = MemoryDB::new();
        let mut table = storage.merkle_list(vec![255]);

        table.append(vec![1]).unwrap();
        assert_eq!(table.height().unwrap(), 1);

        table.append(vec![2]).unwrap();
        assert_eq!(table.height().unwrap(), 2);

        table.append(vec![3]).unwrap();
        assert_eq!(table.height().unwrap(), 3);

        table.append(vec![4]).unwrap();
        assert_eq!(table.height().unwrap(), 3);

        assert_eq!(table.len().unwrap(), 4);
        assert_eq!(table.get(0u32).unwrap(), Some(vec![1]));
        assert_eq!(table.get(1).unwrap(), Some(vec![2]));
        assert_eq!(table.get(2).unwrap(), Some(vec![3]));
        assert_eq!(table.get(3).unwrap(), Some(vec![4]));
    }

    #[test]
    fn hashes() {
        let mut storage = MemoryDB::new();
        let mut table = storage.merkle_list(vec![255]);

        let h1 = hash(&vec![1]);
        let h2 = hash(&vec![2]);
        let h3 = hash(&vec![3]);
        let h4 = hash(&vec![4]);
        let h5 = hash(&vec![5]);
        let h6 = hash(&vec![6]);
        let h7 = hash(&vec![7]);
        let h8 = hash(&vec![8]);
        let h12 = hash(&[h1.as_ref(), h2.as_ref()].concat());
        let h123 = hash(&[h12.as_ref(), h3.as_ref()].concat());
        let h34 = hash(&[h3.as_ref(), h4.as_ref()].concat());
        let h1234 = hash(&[h12.as_ref(), h34.as_ref()].concat());
        let h12345 = hash(&[h1234.as_ref(), h5.as_ref()].concat());
        let h56 = hash(&[h5.as_ref(), h6.as_ref()].concat());
        let h123456 = hash(&[h1234.as_ref(), h56.as_ref()].concat());
        let h78 = hash(&[h7.as_ref(), h8.as_ref()].concat());
        let h567 = hash(&[h56.as_ref(), h7.as_ref()].concat());
        let h1234567 = hash(&[h1234.as_ref(), h567.as_ref()].concat());
        let h5678 = hash(&[h56.as_ref(), h78.as_ref()].concat());
        let h12345678 = hash(&[h1234.as_ref(), h5678.as_ref()].concat());

        table.append(vec![1]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h1));

        table.append(vec![2]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h12));

        table.append(vec![3]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h123));

        table.append(vec![4]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h1234));

        table.append(vec![5]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h12345));

        table.append(vec![6]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h123456));

        table.append(vec![7]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h1234567));

        table.append(vec![8]).unwrap();
        assert_eq!(table.root_hash().unwrap(), Some(h12345678));

        assert_eq!(table.get(0u32).unwrap(), Some(vec![1]));
    }
}
<|endoftext|>


<commit_before>use std::io::Write;

use bit_set::BitSet;
use docopt::Docopt;
use fst::raw as fst;

use util;
use Error;

const USAGE: &'static str = "
Emit this transducer in the \"dot\" format.

If <output> is not set, then the \"dot\" description is emitted to stdout.

Generally, usage of this command should look like this:

    $ fst dot your-transducer.fst | dot -Tpng > your-transducer.png
    $ $YOUR_FAVORITE_IMAGE_VIEWER your-transducer.png

Note that `dot` is a command line utility that is part of graphviz.

If your transducer contains output values, then they are shown as labels on
transitions. Zero output values are omitted.

Usage:
    fst dot [options] <input> [<output>]
    fst dot --help

Options:
    -h, --help       Show this help message.
    --state-names    When set, states will be labeled with arbitrary number.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_input: String,
    arg_output: Option<String>,
    flag_state_names: bool,
}

impl Args {
    fn dot_state(
        &self,
        node: &fst::Node,
        i: usize,
        addr: fst::CompiledAddr,
    ) -> String {
        let label = if self.flag_state_names {
            i.to_string()
        } else {
            "".to_owned()
        };
        if node.is_final() {
            format!("    {} [label=\"{}\",peripheries=2];", addr, label)
        } else {
            format!("    {} [label=\"{}\"];", addr, label)
        }
    }
}

pub fn run(argv: Vec<String>) -> Result<(), Error> {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.argv(&argv).decode())
                            .unwrap_or_else(|e| e.exit());

    let mut wtr = try!(util::get_buf_writer(args.arg_output.as_ref()));
    let fst = try!(fst::Fst::from_path(&args.arg_input));
    let mut set = BitSet::with_capacity(fst.len());

    let mut stack = vec![fst.root().addr()];

    writeln!(wtr, r#"
digraph automaton {{
    labelloc="l";
    labeljust="l";
    rankdir="LR";
"#).unwrap();
    let mut state_num = 0;
    while let Some(addr) = stack.pop() {
        if set.contains(&addr) {
            continue;
        }
        set.insert(addr);

        let node = fst.node(addr);
        writeln!(wtr, "{}", args.dot_state(&node, state_num, addr)).unwrap();
        for t in node.transitions() {
            stack.push(t.addr);
            let inp = (t.inp as char).to_string();
            let out = if t.out.value() == 0 { "".to_owned() } else {
                format!("/{}", t.out.value().to_string())
            };
            writeln!(wtr, "    {} -> {} [label=\"{}{}\"];",
                     addr, t.addr, inp, out).unwrap();
        }
        state_num += 1;
    }
    writeln!(wtr, "}}").unwrap();
    try!(wtr.flush());
    Ok(())
}
<commit_msg>Escape inputs so we produce valid dot in all cases.<commit_after>use std::ascii;
use std::io::Write;

use bit_set::BitSet;
use docopt::Docopt;
use fst::raw as fst;

use util;
use Error;

const USAGE: &'static str = "
Emit this transducer in the \"dot\" format.

If <output> is not set, then the \"dot\" description is emitted to stdout.

Generally, usage of this command should look like this:

    $ fst dot your-transducer.fst | dot -Tpng > your-transducer.png
    $ $YOUR_FAVORITE_IMAGE_VIEWER your-transducer.png

Note that `dot` is a command line utility that is part of graphviz.

If your transducer contains output values, then they are shown as labels on
transitions. Zero output values are omitted.

Usage:
    fst dot [options] <input> [<output>]
    fst dot --help

Options:
    -h, --help       Show this help message.
    --state-names    When set, states will be labeled with arbitrary number.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_input: String,
    arg_output: Option<String>,
    flag_state_names: bool,
}

impl Args {
    fn dot_state(
        &self,
        node: &fst::Node,
        i: usize,
        addr: fst::CompiledAddr,
    ) -> String {
        let label = if self.flag_state_names {
            i.to_string()
        } else {
            "".to_owned()
        };
        if node.is_final() {
            format!("    {} [label=\"{}\",peripheries=2];", addr, label)
        } else {
            format!("    {} [label=\"{}\"];", addr, label)
        }
    }
}

pub fn run(argv: Vec<String>) -> Result<(), Error> {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.argv(&argv).decode())
                            .unwrap_or_else(|e| e.exit());

    let mut wtr = try!(util::get_buf_writer(args.arg_output.as_ref()));
    let fst = try!(fst::Fst::from_path(&args.arg_input));
    let mut set = BitSet::with_capacity(fst.len());

    let mut stack = vec![fst.root().addr()];

    writeln!(wtr, r#"
digraph automaton {{
    labelloc="l";
    labeljust="l";
    rankdir="LR";
"#).unwrap();
    let mut state_num = 0;
    while let Some(addr) = stack.pop() {
        if set.contains(&addr) {
            continue;
        }
        set.insert(addr);

        let node = fst.node(addr);
        writeln!(wtr, "{}", args.dot_state(&node, state_num, addr)).unwrap();
        for t in node.transitions() {
            stack.push(t.addr);
            let out = if t.out.value() == 0 { "".to_owned() } else {
                format!("/{}", t.out.value().to_string())
            };
            writeln!(wtr, "    {} -> {} [label=\"{}{}\"];",
                     addr, t.addr, escape_input(t.inp), out).unwrap();
        }
        state_num += 1;
    }
    writeln!(wtr, "}}").unwrap();
    try!(wtr.flush());
    Ok(())
}

fn escape_input(b: u8) -> String {
    String::from_utf8(ascii::escape_default(b).collect::<Vec<_>>()).unwrap()
}
<|endoftext|>


<commit_before>//! # Trace Context Propagator
//!
//! The `traceparent` header represents the incoming request in a
//! tracing system in a common format, understood by all vendors.
//! Here’s an example of a `traceparent` header.
//!
//! `traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01`
//!
//! The `traceparent` HTTP header field identifies the incoming request in a
//! tracing system. It has four fields:
//!
//!    - version
//!    - trace-id
//!    - parent-id
//!    - trace-flags
//!
//! See the [w3c trace-context docs] for more details.
//!
//! [w3c trace-context docs]: https://w3c.github.io/trace-context/

use crate::api;

static SUPPORTED_VERSION: u8 = 0;
static MAX_VERSION: u8 = 254;
static TRACEPARENT_HEADER: &str = "Traceparent";

/// Extracts and injects `SpanContext`s into `Carrier`s using the
/// trace-context format.
#[derive(Debug, Default)]
pub struct TraceContextPropagator {}

impl TraceContextPropagator {
    /// Create a new `TraceContextPropagator`.
    pub fn new() -> Self {
        TraceContextPropagator {}
    }

    /// Extract span context from w3c trace-context header.
    fn extract_span_context(&self, carrier: &dyn api::Carrier) -> Result<api::SpanContext, ()> {
        let header_value = carrier.get(TRACEPARENT_HEADER).unwrap_or("").trim();
        let parts = header_value.split_terminator('-').collect::<Vec<&str>>();
        // Ensure parts are not out of range.
        if parts.len() < 4 {
            return Err(());
        }

        // Ensure version is within range, for version 0 there must be 4 parts.
        let version = u8::from_str_radix(parts[0], 16).map_err(|_| ())?;
        if version > MAX_VERSION || version == 0 && parts.len() != 4 {
            return Err(());
        }

        // Parse trace id section
        let trace_id = u128::from_str_radix(parts[1], 16)
            .map_err(|_| ())
            .map(api::TraceId::from_u128)?;

        // Parse span id section
        let span_id = u64::from_str_radix(parts[2], 16)
            .map_err(|_| ())
            .map(api::SpanId::from_u64)?;

        // Parse trace flags section
        let opts = u8::from_str_radix(parts[3], 16).map_err(|_| ())?;

        // Ensure opts are valid for version 0
        if version == 0 && opts > 2 {
            return Err(());
        }
        // Build trace flags
        let trace_flags = opts & !api::TRACE_FLAGS_UNUSED;

        // create context
        let span_context = api::SpanContext::new(trace_id, span_id, trace_flags, true);

        // Ensure span is valid
        if !span_context.is_valid() {
            return Err(());
        }

        Ok(span_context)
    }
}

impl api::HttpTextFormat for TraceContextPropagator {
    /// Properly encodes the values of the `SpanContext` and injects them
    /// into the `Carrier`.
    fn inject(&self, context: api::SpanContext, carrier: &mut dyn api::Carrier) {
        if context.is_valid() {
            let header_value = format!(
                "{:02x}-{:032x}-{:016x}-{:02x}",
                SUPPORTED_VERSION,
                context.trace_id().to_u128(),
                context.span_id().to_u64(),
                context.trace_flags() & api::TRACE_FLAG_SAMPLED
            );
            carrier.set(TRACEPARENT_HEADER, header_value)
        }
    }

    /// Retrieves encoded `SpanContext`s using the `Carrier`. It decodes
    /// the `SpanContext` and returns it. If no `SpanContext` was retrieved
    /// OR if the retrieved SpanContext is invalid then an empty `SpanContext`
    /// is returned.
    fn extract(&self, carrier: &dyn api::Carrier) -> api::SpanContext {
        self.extract_span_context(carrier)
            .unwrap_or_else(|_| api::SpanContext::empty_context())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::api::{Carrier, HttpTextFormat};
    use std::collections::HashMap;

    #[rustfmt::skip]
    fn extract_data() -> Vec<(&'static str, api::SpanContext)> {
        vec![
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01-", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("01-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
        ]
    }
    #[rustfmt::skip]
    fn inject_data() -> Vec<(&'static str, api::SpanContext)> {
        vec![
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0xff, true)),
            ("", api::SpanContext::empty_context()),
        ]
    }

    #[test]
    fn extract_w3c() {
        let propagator = TraceContextPropagator::new();

        for (header, expected_context) in extract_data() {
            let mut carrier: HashMap<&'static str, String> = HashMap::new();
            carrier.insert(TRACEPARENT_HEADER, header.to_owned());
            assert_eq!(propagator.extract(&carrier), expected_context)
        }
    }

    #[test]
    fn inject_w3c() {
        let propagator = TraceContextPropagator::new();

        for (expected_header, context) in inject_data() {
            let mut carrier = HashMap::new();
            propagator.inject(context, &mut carrier);

            assert_eq!(
                Carrier::get(&carrier, TRACEPARENT_HEADER).unwrap_or(""),
                expected_header
            )
        }
    }
}
<commit_msg>Fix traceparent header (#104)<commit_after>//! # Trace Context Propagator
//!
//! The `traceparent` header represents the incoming request in a
//! tracing system in a common format, understood by all vendors.
//! Here’s an example of a `traceparent` header.
//!
//! `traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01`
//!
//! The `traceparent` HTTP header field identifies the incoming request in a
//! tracing system. It has four fields:
//!
//!    - version
//!    - trace-id
//!    - parent-id
//!    - trace-flags
//!
//! See the [w3c trace-context docs] for more details.
//!
//! [w3c trace-context docs]: https://w3c.github.io/trace-context/

use crate::api;

static SUPPORTED_VERSION: u8 = 0;
static MAX_VERSION: u8 = 254;
static TRACEPARENT_HEADER: &str = "traceparent";

/// Extracts and injects `SpanContext`s into `Carrier`s using the
/// trace-context format.
#[derive(Debug, Default)]
pub struct TraceContextPropagator {}

impl TraceContextPropagator {
    /// Create a new `TraceContextPropagator`.
    pub fn new() -> Self {
        TraceContextPropagator {}
    }

    /// Extract span context from w3c trace-context header.
    fn extract_span_context(&self, carrier: &dyn api::Carrier) -> Result<api::SpanContext, ()> {
        let header_value = carrier.get(TRACEPARENT_HEADER).unwrap_or("").trim();
        let parts = header_value.split_terminator('-').collect::<Vec<&str>>();
        // Ensure parts are not out of range.
        if parts.len() < 4 {
            return Err(());
        }

        // Ensure version is within range, for version 0 there must be 4 parts.
        let version = u8::from_str_radix(parts[0], 16).map_err(|_| ())?;
        if version > MAX_VERSION || version == 0 && parts.len() != 4 {
            return Err(());
        }

        // Parse trace id section
        let trace_id = u128::from_str_radix(parts[1], 16)
            .map_err(|_| ())
            .map(api::TraceId::from_u128)?;

        // Parse span id section
        let span_id = u64::from_str_radix(parts[2], 16)
            .map_err(|_| ())
            .map(api::SpanId::from_u64)?;

        // Parse trace flags section
        let opts = u8::from_str_radix(parts[3], 16).map_err(|_| ())?;

        // Ensure opts are valid for version 0
        if version == 0 && opts > 2 {
            return Err(());
        }
        // Build trace flags
        let trace_flags = opts & !api::TRACE_FLAGS_UNUSED;

        // create context
        let span_context = api::SpanContext::new(trace_id, span_id, trace_flags, true);

        // Ensure span is valid
        if !span_context.is_valid() {
            return Err(());
        }

        Ok(span_context)
    }
}

impl api::HttpTextFormat for TraceContextPropagator {
    /// Properly encodes the values of the `SpanContext` and injects them
    /// into the `Carrier`.
    fn inject(&self, context: api::SpanContext, carrier: &mut dyn api::Carrier) {
        if context.is_valid() {
            let header_value = format!(
                "{:02x}-{:032x}-{:016x}-{:02x}",
                SUPPORTED_VERSION,
                context.trace_id().to_u128(),
                context.span_id().to_u64(),
                context.trace_flags() & api::TRACE_FLAG_SAMPLED
            );
            carrier.set(TRACEPARENT_HEADER, header_value)
        }
    }

    /// Retrieves encoded `SpanContext`s using the `Carrier`. It decodes
    /// the `SpanContext` and returns it. If no `SpanContext` was retrieved
    /// OR if the retrieved SpanContext is invalid then an empty `SpanContext`
    /// is returned.
    fn extract(&self, carrier: &dyn api::Carrier) -> api::SpanContext {
        self.extract_span_context(carrier)
            .unwrap_or_else(|_| api::SpanContext::empty_context())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::api::{Carrier, HttpTextFormat};
    use std::collections::HashMap;

    #[rustfmt::skip]
    fn extract_data() -> Vec<(&'static str, api::SpanContext)> {
        vec![
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)),
            ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01-", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("01-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
        ]
    }
    #[rustfmt::skip]
    fn inject_data() -> Vec<(&'static str, api::SpanContext)> {
        vec![
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)),
            ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0xff, true)),
            ("", api::SpanContext::empty_context()),
        ]
    }

    #[test]
    fn extract_w3c() {
        let propagator = TraceContextPropagator::new();

        for (header, expected_context) in extract_data() {
            let mut carrier: HashMap<&'static str, String> = HashMap::new();
            carrier.insert(TRACEPARENT_HEADER, header.to_owned());
            assert_eq!(propagator.extract(&carrier), expected_context)
        }
    }

    #[test]
    fn inject_w3c() {
        let propagator = TraceContextPropagator::new();

        for (expected_header, context) in inject_data() {
            let mut carrier = HashMap::new();
            propagator.inject(context, &mut carrier);

            assert_eq!(
                Carrier::get(&carrier, TRACEPARENT_HEADER).unwrap_or(""),
                expected_header
            )
        }
    }
}
<|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/. */

///
/// Implementation of the callbacks that the CSS selector engine uses to query the DOM.
///

use core::str::eq_slice;
use newcss::select::SelectHandler;
use script::dom::node::{AbstractNode, LayoutView};

pub struct NodeSelectHandler {
    node: AbstractNode<LayoutView>,
}

fn with_node_name<R>(node: AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
    if !node.is_element() {
        fail!(~"attempting to style non-element node");
    }
    do node.with_imm_element |element_n| {
        f(element_n.tag_name)
    }
}

impl SelectHandler<AbstractNode<LayoutView>> for NodeSelectHandler {
    fn with_node_name<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
        with_node_name(*node, f)
    }

    fn named_parent_node(&self, node: &AbstractNode<LayoutView>, name: &str)
                         -> Option<AbstractNode<LayoutView>> {
        match node.parent_node() {
            Some(parent) => {
                do with_node_name(parent) |node_name| {
                    if eq_slice(name, node_name) {
                        Some(parent)
                    } else {
                        None
                    }
                }
            }
            None => None
        }
    }

    fn parent_node(&self, node: &AbstractNode<LayoutView>) -> Option<AbstractNode<LayoutView>> {
        node.parent_node()
    }

    // TODO: Use a Bloom filter.
    fn named_ancestor_node(&self, node: &AbstractNode<LayoutView>, name: &str)
                           -> Option<AbstractNode<LayoutView>> {
        let mut node = *node;
        loop {
            let parent = node.parent_node();
            match parent {
                Some(parent) => {
                    let mut found = false;
                    do with_node_name(parent) |node_name| {
                        if eq_slice(name, node_name) {
                            found = true;
                        }
                    }
                    if found {
                        return Some(parent);
                    }
                    node = parent;
                }
                None => return None
            }
        }
    }

    fn node_is_root(&self, node: &AbstractNode<LayoutView>) -> bool {
        self.parent_node(node).is_none()
    }

    fn node_is_link(&self, node: &AbstractNode<LayoutView>) -> bool {
        if node.is_element() {
            do node.with_imm_element |element| {
                "a" == element.tag_name
            }
        } else {
            false
        }
    }

    fn with_node_classes<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(Option<&str>) -> R) -> R {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element() |element_n| {
            f(element_n.get_attr("class"))
        }
    }

    fn with_node_id<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(Option<&str>) -> R) -> R {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element() |element_n| {
            f(element_n.get_attr("id"))
        }
    }

    fn node_has_id(&self, node: &AbstractNode<LayoutView>, id: &str) -> bool {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element |element_n| {
            match element_n.get_attr("id") {
                None => false,
                Some(existing_id) => id == existing_id
            }
        }
    }
}
<commit_msg>Support css class selection (2)<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/. */

///
/// Implementation of the callbacks that the CSS selector engine uses to query the DOM.
///

use core::str::eq_slice;
use newcss::select::SelectHandler;
use script::dom::node::{AbstractNode, LayoutView};

pub struct NodeSelectHandler {
    node: AbstractNode<LayoutView>,
}

fn with_node_name<R>(node: AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
    if !node.is_element() {
        fail!(~"attempting to style non-element node");
    }
    do node.with_imm_element |element_n| {
        f(element_n.tag_name)
    }
}

impl SelectHandler<AbstractNode<LayoutView>> for NodeSelectHandler {
    fn with_node_name<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
        with_node_name(*node, f)
    }

    fn named_parent_node(&self, node: &AbstractNode<LayoutView>, name: &str)
                         -> Option<AbstractNode<LayoutView>> {
        match node.parent_node() {
            Some(parent) => {
                do with_node_name(parent) |node_name| {
                    if eq_slice(name, node_name) {
                        Some(parent)
                    } else {
                        None
                    }
                }
            }
            None => None
        }
    }

    fn parent_node(&self, node: &AbstractNode<LayoutView>) -> Option<AbstractNode<LayoutView>> {
        node.parent_node()
    }

    // TODO: Use a Bloom filter.
    fn named_ancestor_node(&self, node: &AbstractNode<LayoutView>, name: &str)
                           -> Option<AbstractNode<LayoutView>> {
        let mut node = *node;
        loop {
            let parent = node.parent_node();
            match parent {
                Some(parent) => {
                    let mut found = false;
                    do with_node_name(parent) |node_name| {
                        if eq_slice(name, node_name) {
                            found = true;
                        }
                    }
                    if found {
                        return Some(parent);
                    }
                    node = parent;
                }
                None => return None
            }
        }
    }

    fn node_is_root(&self, node: &AbstractNode<LayoutView>) -> bool {
        self.parent_node(node).is_none()
    }

    fn node_is_link(&self, node: &AbstractNode<LayoutView>) -> bool {
        if node.is_element() {
            do node.with_imm_element |element| {
                "a" == element.tag_name
            }
        } else {
            false
        }
    }

    fn with_node_classes<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(Option<&str>) -> R) -> R {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element() |element_n| {
            f(element_n.get_attr("class"))
        }
    }

    fn node_has_class(&self, node: &AbstractNode<LayoutView>, class: &str) -> bool {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element |element_n| {
            match element_n.get_attr("class") {
                None => false,
                Some(existing_classes) => {
                    let mut ret = false;
                    for str::each_split_char(existing_classes, ' ') |s| {
                        if s == class {
                            ret = true;
                            break;
                        }
                    }
                    ret
                }
            }
        }
    }

    fn with_node_id<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(Option<&str>) -> R) -> R {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element() |element_n| {
            f(element_n.get_attr("id"))
        }
    }

    fn node_has_id(&self, node: &AbstractNode<LayoutView>, id: &str) -> bool {
        if !node.is_element() {
            fail!(~"attempting to style non-element node");
        }
        do node.with_imm_element |element_n| {
            match element_n.get_attr("id") {
                None => false,
                Some(existing_id) => id == existing_id
            }
        }
    }
}
<|endoftext|>


<commit_before>use parser;
use test_util;

fn check_err(expected_err: &str, grammar: &str, span: &str) {
    let parsed_grammar = parser::parse_grammar(&grammar).unwrap();
    let err = super::validate(&parsed_grammar).unwrap_err();
    test_util::check_norm_err(expected_err, span, err);
}

#[test]
fn named_symbols() {
    check_err(
        r#"named symbols \(like `"Num"`\) require a custom action"#,
        r#"grammar; Term = { <n:"Num"> };"#,
        r#"                     ~~~~~    "#);
}

#[test]
fn bad_assoc_type() {
    check_err(
        r#"associated type `Foo` not recognized"#,
        r#"grammar; extern { type Foo = i32; enum Tok { } }"#,
        r#"                       ~~~                      "#);
}

#[test]
fn dup_assoc_type() {
    check_err(
        r#"associated type `Location` already specified"#,
        r#"grammar; extern { type Location = i32; type Location = u32; enum Tok { } }"#,
        r#"                                            ~~~~~~~~                      "#);
}

#[test]
fn lookahead_without_loc_type() {
    check_err(
        r#"lookahead/lookbehind require you to declare the type of a location"#,
        r#"grammar; extern { enum Tok { } } Foo = @L;"#,
        r#"                                       ~~ "#);
}

#[test]
fn multiple_extern_token() {
    check_err(
        r#"multiple extern definitions are not permitted"#,
        r#"grammar; extern { enum Tok { } } extern { enum Tok { } }"#,
        r#"                                 ~~~~~~                 "#);
}

#[test]
fn unrecognized_annotation() {
    check_err(
        r#"unrecognized annotation `foo`"#,
        r#"grammar; #[foo] Term = ();"#,
        r#"           ~~~            "#);
}

#[test]
fn duplicate_annotation() {
    check_err(
        r#"duplicate annotation `inline`"#,
        r#"grammar; #[inline] #[inline] Term = ();"#,
        r#"                     ~~~~~~            "#);
}

#[test]
fn pub_inline_annotation() {
    check_err(
        r#"public items cannot be marked #\[inline\]"#,
        r#"grammar; #[inline] pub Term = ();"#,
        r#"           ~~~~~~            "#);
}

#[test]
fn multiple_match_token() {
    check_err(
        r#"multiple match definitions are not permitted"#,
        r#"grammar; match { _ } match { _ }"#,
        r#"                     ~~~~~      "#);
}

#[test]
fn match_after_extern_token() {
    check_err(
        r#"match and extern definitions are mutually exclusive"#,
        r#"grammar; extern { enum Tok { } } match { _ }"#,
        r#"                                 ~~~~~      "#);
}

#[test]
fn extern_after_match_token() {
    check_err(
        r#"extern and match definitions are mutually exclusive"#,
        r#"grammar; match { _ } extern { enum Tok { } }"#,
        r#"                     ~~~~~~                 "#);
}

#[test]
fn match_catch_all_first_of_last() {
    check_err(
        r#"Catch all must be final item"#,
        r#"grammar; match { _, "abc" }"#,
        r#"                 ~         "#);
}

#[test]
fn match_catch_all_last_of_first() {
    check_err(
        r#"Catch all must be final item"#,
        r#"grammar; match { "abc", _ } else { "foo" }"#,
        r#"                        ~                 "#);
}
<commit_msg>Added missing tests<commit_after>use parser;
use test_util;

fn check_err(expected_err: &str, grammar: &str, span: &str) {
    let parsed_grammar = parser::parse_grammar(&grammar).unwrap();
    let err = super::validate(&parsed_grammar).unwrap_err();
    test_util::check_norm_err(expected_err, span, err);
}

#[test]
fn named_symbols() {
    check_err(
        r#"named symbols \(like `"Num"`\) require a custom action"#,
        r#"grammar; Term = { <n:"Num"> };"#,
        r#"                     ~~~~~    "#);
}

#[test]
fn bad_assoc_type() {
    check_err(
        r#"associated type `Foo` not recognized"#,
        r#"grammar; extern { type Foo = i32; enum Tok { } }"#,
        r#"                       ~~~                      "#);
}

#[test]
fn dup_assoc_type() {
    check_err(
        r#"associated type `Location` already specified"#,
        r#"grammar; extern { type Location = i32; type Location = u32; enum Tok { } }"#,
        r#"                                            ~~~~~~~~                      "#);
}

#[test]
fn lookahead_without_loc_type() {
    check_err(
        r#"lookahead/lookbehind require you to declare the type of a location"#,
        r#"grammar; extern { enum Tok { } } Foo = @L;"#,
        r#"                                       ~~ "#);
}

#[test]
fn multiple_extern_token() {
    check_err(
        r#"multiple extern definitions are not permitted"#,
        r#"grammar; extern { enum Tok { } } extern { enum Tok { } }"#,
        r#"                                 ~~~~~~                 "#);
}

#[test]
fn unrecognized_annotation() {
    check_err(
        r#"unrecognized annotation `foo`"#,
        r#"grammar; #[foo] Term = ();"#,
        r#"           ~~~            "#);
}

#[test]
fn duplicate_annotation() {
    check_err(
        r#"duplicate annotation `inline`"#,
        r#"grammar; #[inline] #[inline] Term = ();"#,
        r#"                     ~~~~~~            "#);
}

#[test]
fn pub_inline_annotation() {
    check_err(
        r#"public items cannot be marked #\[inline\]"#,
        r#"grammar; #[inline] pub Term = ();"#,
        r#"           ~~~~~~            "#);
}

#[test]
fn multiple_match_token() {
    check_err(
        r#"multiple match definitions are not permitted"#,
        r#"grammar; match { _ } match { _ }"#,
        r#"                     ~~~~~      "#);
}

#[test]
fn match_after_extern_token() {
    check_err(
        r#"match and extern definitions are mutually exclusive"#,
        r#"grammar; extern { enum Tok { } } match { _ }"#,
        r#"                                 ~~~~~      "#);
}

#[test]
fn extern_after_match_token() {
    check_err(
        r#"extern and match definitions are mutually exclusive"#,
        r#"grammar; match { _ } extern { enum Tok { } }"#,
        r#"                     ~~~~~~                 "#);
}

#[test]
fn match_catch_all_first_of_last() {
    check_err(
        r#"Catch all must be final item"#,
        r#"grammar; match { _, "abc" }"#,
        r#"                 ~         "#);
}

#[test]
fn match_catch_all_last_of_first() {
    check_err(
        r#"Catch all must be final item"#,
        r#"grammar; match { "abc", _ } else { "foo" }"#,
        r#"                        ~                 "#);
}

#[test]
fn expandable_expression_requires_named_variables() {
    check_err(
        r#"Using `<>` between curly braces \(e.g., `\{<>\}`\) only works when your parsed values have been given names \(e.g., `<x:Foo>`, not just `<Foo>`\)"#,
        r#"grammar; Term = { <A> => Foo {<>} };"#,
        r#"                  ~~~~~~~~~~~~~~~~  "#);
}

#[test]
fn mixing_names_and_anonymous_values() {
    check_err(
        r#"anonymous symbols like this one cannot be combined with named symbols like `b:B`"#,
        r#"grammar; Term = { <A> <b:B> => Alien: Eighth passanger of Nostromo};"#,
        r#"                  ~~~                                               "#);
}<|endoftext|>


<commit_before>use std::path::PathBuf;

use git2::{Repository, Signature};
use toml::Value;

use libimagerror::into::IntoError;
use libimagerror::trace::trace_error;
use libimagstore::hook::error::CustomData;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

use vcs::git::result::Result;
use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};

pub struct Runtime {
    repository: Option<Repository>,
    config: Option<Value>,
}

impl Runtime {

    pub fn new(storepath: &PathBuf) -> Runtime {
        Runtime {
            repository: match Repository::open(storepath) {
                Ok(r) => Some(r),
                Err(e) => {
                    trace_error(&e);
                    None
                },
            },

            config: None,
        }
    }

    pub fn set_config(&mut self, cfg: &Value) -> Result<()> {
        self.config = Some(cfg.clone());
        Ok(())
    }

    pub fn has_repository(&self) -> bool {
        self.repository.is_some()
    }

    pub fn has_config(&self) -> bool {
        self.config.is_some()
    }

    pub fn config_value_or_err(&self) -> HookResult<&Value> {
        self.config
            .as_ref()
            .ok_or(GHEK::NoConfigError.into_error())
            .map_err_into(GHEK::ConfigError)
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
            .map_err(|mut e| e.with_custom_data(CustomData::default().aborting(false)))
    }

    pub fn repository(&self) -> HookResult<&Repository> {
        self.repository
            .as_ref()
            .ok_or(GHEK::MkRepo.into_error())
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
    }

    pub fn ensure_cfg_branch_is_checked_out(&self) -> HookResult<()> {
        use vcs::git::config::ensure_branch;

        let head = try!(self
                        .repository()
                        .and_then(|r| {
                            r.head().map_err_into(GHEK::HeadFetchError).map_err(|e| e.into())
                        }));

        // TODO: Fail if not on branch? hmmh... I'm not sure
        if head.is_branch() {
            return Err(GHEK::NotOnBranch.into_error().into());
        }

        // Check out appropriate branch ... or fail
        match ensure_branch(self.config.as_ref()) {
            Ok(Some(s)) => {
                match head.name().map(|name| name == s) {
                    Some(b) => {
                        if b {
                            debug!("Branch already checked out.");
                            Ok(())
                        } else {
                            debug!("Branch not checked out.");
                            unimplemented!()
                        }
                    },

                    None => Err(GHEK::RepositoryBranchNameFetchingError.into_error())
                        .map_err_into(GHEK::RepositoryBranchError)
                        .map_err_into(GHEK::RepositoryError),
                }
            },
            Ok(None) => {
                debug!("No branch to checkout");
                Ok(())
            },

            Err(e) => Err(e).map_err_into(GHEK::RepositoryError),
        }
        .map_err(Box::new)
        .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
    }

}

<commit_msg>Add debugging output in Runtime<commit_after>use std::path::PathBuf;

use git2::{Repository, Signature};
use toml::Value;

use libimagerror::into::IntoError;
use libimagerror::trace::trace_error;
use libimagstore::hook::error::CustomData;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;
use libimagutil::debug_result::*;

use vcs::git::result::Result;
use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};

pub struct Runtime {
    repository: Option<Repository>,
    config: Option<Value>,
}

impl Runtime {

    pub fn new(storepath: &PathBuf) -> Runtime {
        Runtime {
            repository: match Repository::open(storepath) {
                Ok(r) => Some(r),
                Err(e) => {
                    trace_error(&e);
                    None
                },
            },

            config: None,
        }
    }

    pub fn set_config(&mut self, cfg: &Value) -> Result<()> {
        self.config = Some(cfg.clone());
        Ok(())
    }

    pub fn has_repository(&self) -> bool {
        self.repository.is_some()
    }

    pub fn has_config(&self) -> bool {
        self.config.is_some()
    }

    pub fn config_value_or_err(&self) -> HookResult<&Value> {
        self.config
            .as_ref()
            .ok_or(GHEK::NoConfigError.into_error())
            .map_err_into(GHEK::ConfigError)
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
            .map_err(|mut e| e.with_custom_data(CustomData::default().aborting(false)))
    }

    pub fn repository(&self) -> HookResult<&Repository> {
        self.repository
            .as_ref()
            .ok_or(GHEK::MkRepo.into_error())
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
    }

    pub fn ensure_cfg_branch_is_checked_out(&self) -> HookResult<()> {
        use vcs::git::config::ensure_branch;

        let head = try!(self
                        .repository()
                        .and_then(|r| {
                            debug!("Repository fetched, getting head");
                            r.head()
                                .map_dbg_err_str("Couldn't fetch HEAD")
                                .map_dbg_err(|e| format!("\tbecause = {:?}", e))
                                .map_err_into(GHEK::HeadFetchError)
                                .map_err(|e| e.into())
                        }));
        debug!("HEAD fetched");

        // TODO: Fail if not on branch? hmmh... I'm not sure
        if !head.is_branch() {
            debug!("HEAD is not a branch");
            return Err(GHEK::NotOnBranch.into_error().into());
        }
        debug!("HEAD is a branch");

        // Check out appropriate branch ... or fail
        match ensure_branch(self.config.as_ref()) {
            Ok(Some(s)) => {
                debug!("We have to ensure branch: {}", s);
                match head.name().map(|name| {
                    debug!("{} == {}", name, s);
                    name == s
                }) {
                    Some(b) => {
                        if b {
                            debug!("Branch already checked out.");
                            Ok(())
                        } else {
                            debug!("Branch not checked out.");
                            unimplemented!()
                        }
                    },

                    None => Err(GHEK::RepositoryBranchNameFetchingError.into_error())
                        .map_err_into(GHEK::RepositoryBranchError)
                        .map_err_into(GHEK::RepositoryError),
                }
            },
            Ok(None) => {
                debug!("No branch to checkout");
                Ok(())
            },

            Err(e) => Err(e).map_err_into(GHEK::RepositoryError),
        }
        .map_err(Box::new)
        .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
    }

}

<|endoftext|>


<commit_before>use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
    iter: I,
    /// Remember a peeked value, even if it was None.
    peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
        Peekable { iter, peeked: None }
    }
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        match self.peeked.take() {
            Some(v) => v,
            None => self.iter.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(mut self) -> usize {
        match self.peeked.take() {
            Some(None) => 0,
            Some(Some(_)) => 1 + self.iter.count(),
            None => self.iter.count(),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        match self.peeked.take() {
            Some(None) => None,
            Some(v @ Some(_)) if n == 0 => v,
            Some(Some(_)) => self.iter.nth(n - 1),
            None => self.iter.nth(n),
        }
    }

    #[inline]
    fn last(mut self) -> Option<I::Item> {
        let peek_opt = match self.peeked.take() {
            Some(None) => return None,
            Some(v) => v,
            None => None,
        };
        self.iter.last().or(peek_opt)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = match self.peeked {
            Some(None) => return (0, Some(0)),
            Some(Some(_)) => 1,
            None => 0,
        };
        let (lo, hi) = self.iter.size_hint();
        let lo = lo.saturating_add(peek_len);
        let hi = match hi {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lo, hi)
    }

    #[inline]
    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let acc = match self.peeked.take() {
            Some(None) => return try { init },
            Some(Some(v)) => f(init, v)?,
            None => init,
        };
        self.iter.try_fold(acc, f)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        let acc = match self.peeked {
            Some(None) => return init,
            Some(Some(v)) => fold(init, v),
            None => init,
        };
        self.iter.fold(acc, fold)
    }
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        match self.peeked.as_mut() {
            Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
            Some(None) => None,
            None => self.iter.next_back(),
        }
    }

    #[inline]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        match self.peeked.take() {
            Some(None) => try { init },
            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                Ok(acc) => f(acc, v),
                Err(e) => {
                    self.peeked = Some(Some(v));
                    Try::from_error(e)
                }
            },
            None => self.iter.try_rfold(init, f),
        }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        match self.peeked {
            Some(None) => init,
            Some(Some(v)) => {
                let acc = self.iter.rfold(init, &mut fold);
                fold(acc, v)
            }
            None => self.iter.rfold(init, fold),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
    /// Returns a reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// [`next`]: Iterator::next
    ///
    /// Because `peek()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the
    /// examples below.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let xs = [1, 2, 3];
    ///
    /// let mut iter = xs.iter().peekable();
    ///
    /// // peek() lets us see into the future
    /// assert_eq!(iter.peek(), Some(&&1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// assert_eq!(iter.next(), Some(&2));
    ///
    /// // The iterator does not advance even if we `peek` multiple times
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.peek(), Some(&&3));
    ///
    /// assert_eq!(iter.next(), Some(&3));
    ///
    /// // After the iterator is finished, so is `peek()`
    /// assert_eq!(iter.peek(), None);
    /// assert_eq!(iter.next(), None);
    /// ```
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn peek(&mut self) -> Option<&I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_ref()
    }

    /// Returns a mutable reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// Because `peek_mut()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the examples
    /// below.
    ///
    /// [`next`]: Iterator::next
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(peekable_peek_mut)]
    /// let mut iter = [1, 2, 3].iter().peekable();
    ///
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// // Peek into the iterator and modify the value which will be returned next
    /// if let Some(mut p) = iter.peek_mut() {
    ///     if *p == &2 {
    ///         *p = &5;
    ///     }
    /// }
    ///
    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
    /// ```
    #[inline]
    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
    pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_mut()
    }

    /// Consume and return the next value of this iterator if a condition is true.
    ///
    /// If `func` returns `true` for the next value of this iterator, consume and return it.
    /// Otherwise, return `None`.
    ///
    /// # Examples
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if(|&x| x == 0), None);
    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    ///
    /// Consume any number less than 10.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (1..20).peekable();
    /// // Consume all numbers less than 10
    /// while iter.next_if(|&x| x < 10).is_some() {}
    /// // The next value returned will be 10
    /// assert_eq!(iter.next(), Some(10));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
        match self.next() {
            Some(matched) if func(&matched) => Some(matched),
            other => {
                // Since we called `self.next()`, we consumed `self.peeked`.
                assert!(self.peeked.is_none());
                self.peeked = Some(other);
                None
            }
        }
    }

    /// Consume and return the next item if it is equal to `expected`.
    ///
    /// # Example
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if_eq(&0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if_eq(&0), None);
    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
    where
        T: ?Sized,
        I::Item: PartialEq<T>,
    {
        self.next_if(|next| next == expected)
    }
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
    I: SourceIter<Source = S>,
{
    type Source = S;

    #[inline]
    unsafe fn as_inner(&mut self) -> &mut S {
        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
        unsafe { SourceIter::as_inner(&mut self.iter) }
    }
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
<commit_msg>Expand docs on Peekable::peek_mut<commit_after>use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
    iter: I,
    /// Remember a peeked value, even if it was None.
    peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
        Peekable { iter, peeked: None }
    }
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        match self.peeked.take() {
            Some(v) => v,
            None => self.iter.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(mut self) -> usize {
        match self.peeked.take() {
            Some(None) => 0,
            Some(Some(_)) => 1 + self.iter.count(),
            None => self.iter.count(),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        match self.peeked.take() {
            Some(None) => None,
            Some(v @ Some(_)) if n == 0 => v,
            Some(Some(_)) => self.iter.nth(n - 1),
            None => self.iter.nth(n),
        }
    }

    #[inline]
    fn last(mut self) -> Option<I::Item> {
        let peek_opt = match self.peeked.take() {
            Some(None) => return None,
            Some(v) => v,
            None => None,
        };
        self.iter.last().or(peek_opt)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = match self.peeked {
            Some(None) => return (0, Some(0)),
            Some(Some(_)) => 1,
            None => 0,
        };
        let (lo, hi) = self.iter.size_hint();
        let lo = lo.saturating_add(peek_len);
        let hi = match hi {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lo, hi)
    }

    #[inline]
    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let acc = match self.peeked.take() {
            Some(None) => return try { init },
            Some(Some(v)) => f(init, v)?,
            None => init,
        };
        self.iter.try_fold(acc, f)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        let acc = match self.peeked {
            Some(None) => return init,
            Some(Some(v)) => fold(init, v),
            None => init,
        };
        self.iter.fold(acc, fold)
    }
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        match self.peeked.as_mut() {
            Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
            Some(None) => None,
            None => self.iter.next_back(),
        }
    }

    #[inline]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        match self.peeked.take() {
            Some(None) => try { init },
            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                Ok(acc) => f(acc, v),
                Err(e) => {
                    self.peeked = Some(Some(v));
                    Try::from_error(e)
                }
            },
            None => self.iter.try_rfold(init, f),
        }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        match self.peeked {
            Some(None) => init,
            Some(Some(v)) => {
                let acc = self.iter.rfold(init, &mut fold);
                fold(acc, v)
            }
            None => self.iter.rfold(init, fold),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
    /// Returns a reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// [`next`]: Iterator::next
    ///
    /// Because `peek()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the
    /// examples below.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let xs = [1, 2, 3];
    ///
    /// let mut iter = xs.iter().peekable();
    ///
    /// // peek() lets us see into the future
    /// assert_eq!(iter.peek(), Some(&&1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// assert_eq!(iter.next(), Some(&2));
    ///
    /// // The iterator does not advance even if we `peek` multiple times
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.peek(), Some(&&3));
    ///
    /// assert_eq!(iter.next(), Some(&3));
    ///
    /// // After the iterator is finished, so is `peek()`
    /// assert_eq!(iter.peek(), None);
    /// assert_eq!(iter.next(), None);
    /// ```
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn peek(&mut self) -> Option<&I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_ref()
    }

    /// Returns a mutable reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// Because `peek_mut()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the examples
    /// below.
    ///
    /// [`next`]: Iterator::next
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// #![feature(peekable_peek_mut)]
    /// let mut iter = [1, 2, 3].iter().peekable();
    ///
    /// // Like with `peek()`, we can see into the future without advancing the iterator.
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// // Peek into the iterator and set the value behind the mutable reference.
    /// if let Some(p) = iter.peek_mut() {
    ///     assert_eq!(*p, &2);
    ///     *p = &5;
    /// }
    ///
    /// // The value we put in reappears as the iterator continues.
    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
    /// ```
    #[inline]
    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
    pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_mut()
    }

    /// Consume and return the next value of this iterator if a condition is true.
    ///
    /// If `func` returns `true` for the next value of this iterator, consume and return it.
    /// Otherwise, return `None`.
    ///
    /// # Examples
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if(|&x| x == 0), None);
    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    ///
    /// Consume any number less than 10.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (1..20).peekable();
    /// // Consume all numbers less than 10
    /// while iter.next_if(|&x| x < 10).is_some() {}
    /// // The next value returned will be 10
    /// assert_eq!(iter.next(), Some(10));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
        match self.next() {
            Some(matched) if func(&matched) => Some(matched),
            other => {
                // Since we called `self.next()`, we consumed `self.peeked`.
                assert!(self.peeked.is_none());
                self.peeked = Some(other);
                None
            }
        }
    }

    /// Consume and return the next item if it is equal to `expected`.
    ///
    /// # Example
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if_eq(&0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if_eq(&0), None);
    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
    where
        T: ?Sized,
        I::Item: PartialEq<T>,
    {
        self.next_if(|next| next == expected)
    }
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
    I: SourceIter<Source = S>,
{
    type Source = S;

    #[inline]
    unsafe fn as_inner(&mut self) -> &mut S {
        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
        unsafe { SourceIter::as_inner(&mut self.iter) }
    }
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::{File, metadata, read_dir};
use std::io::{ErrorKind, Read};
use std::path::Path;
use semver::Version;
use super::item::Slice;
use super::section::Section;
use helper;
use version;

/// # Examples
/// ```
/// use std::env;
/// use sb::slice::directory;
/// let current_dir = env::current_dir();
/// let mut current_dir = current_dir.unwrap().to_path_buf();
/// current_dir.push("test_slices");
/// match directory::get_latest_slice_directories(&current_dir) {
///     Ok(directories) => {
///         assert_eq!(directories, vec!["slices-1.0.0-alpha", "slices-1.0.1"]);
///     }
///     Err(error) => panic!("{}", error)
/// }
/// ```
pub fn get_latest_slice_directories(slices_directory: &Path) -> Result<Vec<String>, String> {
    match get_directories_in_directory(&slices_directory) {
        Ok(directories) => {
            if directories.is_empty() {
                return Err("There are no any slices".to_string())
            }
            let directories = get_directories_with_max_semver_major(directories);
            assert!(!directories.is_empty());
            Ok(directories)
        }
        Err(error) => Err(error)
    }
}

pub fn get_latest_slices_from_slice_root_directory(slice_root_directory: &Path)
                                                   -> Result<Vec<Slice>, String> {
    match get_latest_slice_directories(&slice_root_directory) {
        Ok(slice_directories) => {
            let mut slices: Vec<Slice> = Vec::new();
            for directory in slice_directories {
                let mut path = slice_root_directory.to_path_buf();
                path.push(&directory);
                let slices_from_directory = get_slices_from_directory(&path);
                for slice in slices_from_directory {
                    /*
                    {
                        let added_before_slice = slices.iter().find(|other| {
                            other.name == slice.name
                        });
                        if let Some(added_before_slice) = added_before_slice {
                            panic!("{} {}", slice.path.display(), added_before_slice.path.display());
                        }
                    }
                    */
                    /*
                    if let Some(added_before_slice_position) = added_before_slice_position {
                        slices.remove(added_before_slice_position);
                    }
                    */
                    slices.push(slice);
                }
            }
            Ok(slices)
        }
        Err(error) => Err(error),
    }
}

pub fn get_slices_from_directory(directory: &Path) -> Vec<Slice> {
    let mut slices: Vec<Slice> = Vec::new();
    add_slices_from_directory(&mut slices, directory);
    for slice in &mut slices {
        slice.path = helper::relative_path_from(&slice.path, directory).unwrap();
    }
    slices
}

fn get_directories_in_directory(directory: &Path) -> Result<Vec<String>, String> {
    match read_dir(directory) {
        Ok(result) => {
            let directories = result.filter(|entry| {
                if let Ok(ref entry) = *entry {
                    metadata(entry.path()).unwrap().is_dir()
                } else {
                    false
                }
                                    })
                                    .map(|entry| {
                let path = entry.unwrap().path();
                let path = helper::relative_path_from(&path, directory);
                path.unwrap().to_str().unwrap().to_string()
                                    })
                                    .collect();
            Ok(directories)
        }
        Err(error) => match error.kind() {
            ErrorKind::NotFound => {
                let directory = directory.to_str().unwrap();
                let error = format!("Directory \"{}\" is not exist", directory);
                Err(error)
            }
            _ => Err(error.description().to_string())
        }
    }
}

fn get_directories_with_max_semver_major(directories: Vec<String>) -> Vec<String> {
    if directories.is_empty() {
        return Vec::new();
    }

    let mut directories = directories.into_iter()
                                     .map(|d| {
        let (_, version) = get_slice_name_and_version_from_string(&d);
        (version, d)
                                     })
                                     .collect::<Vec<_>>();
    directories.sort_by(|a, b| b.0.cmp(&a.0));
    let major_version_max = directories[0].0.major;
    let mut directories = directories.into_iter()
                                     .filter(|d| d.0.major == major_version_max)
                                     .collect::<Vec<_>>();
    directories.sort_by(|a, b| a.0.cmp(&b.0));
    directories.into_iter().map(|d| d.1).collect::<Vec<_>>()
}

fn add_slices_from_directory(slices: &mut Vec<Slice>, directory: &Path) {
    assert!(metadata(&directory).unwrap().is_dir());
    for entry in read_dir(&directory).unwrap() {
        let entry_path = entry.unwrap().path();
        if metadata(&entry_path).unwrap().is_dir() {
            add_slices_from_directory(slices, &entry_path);
        } else {
            if let Some(slice) = get_slice_from_file_path(&entry_path) {
                slices.push(slice);
            }
        }
    }
}

fn get_slice_name_and_version_from_string(string: &String) -> (String, Version) {
    if let Some(pos) = string.find('-') {
        (string[..pos].to_string(), version::parse(&string[pos+1..]))
    } else {
        (string.clone(), version::zero())
    }
}

fn get_slice_from_file_path(file_path: &Path) -> Option<Slice> {
    if let Some(file_extension) = file_path.extension() {
        let file_extension = file_extension.to_str().unwrap();
        if file_extension == "md" || file_extension == "txt" {
            return None;
        }
    }
    get_slice_from_checked_file_path(&file_path)
}

fn get_slice_from_checked_file_path(file_path: &Path) -> Option<Slice> {
    let mut file = File::open(file_path).unwrap();
    let mut content = String::new();
    let _ = file.read_to_string(&mut content).unwrap();
    let mut lines: Vec<String> = content.split('\n')
                                        .map(|n: &str| n.to_string().trim().to_string())
                                        .collect();
    let mut sections: Vec<Section> = Vec::new();
    while !lines.is_empty() {
        let (section, remaining_lines) = Section::load_from_lines(lines);
        if let Some(section) = section {
            sections.push(section);
            lines = remaining_lines;
        } else {
            return None
        }
    }
    let file_name = &file_path.file_name().unwrap().to_str().unwrap().to_string();
    let (slice_name, version) = get_slice_name_and_version_from_string(file_name);
    let slice = Slice { name: slice_name, path: file_path.to_path_buf(), version: version,
                        sections: sections };
    Some(slice)
}

#[cfg(test)]
mod tests {
    #[test]
    fn get_directories_with_max_semver_major() {
        let mut directories = Vec::new();
        directories.push("slices-1.0.1");
        directories.push("slices-0.2.1-beta.3");
        directories.push("slices-1.0.0-alpha");
        directories.push("slices-0.0.1-beta.3");
        let directories = directories.into_iter().map(|d| d.to_string()).collect::<Vec<_>>();
        let expected_result = vec!["slices-1.0.0-alpha", "slices-1.0.1"];
        let expected_result = expected_result.into_iter()
                                             .map(|d| d.to_string())
                                             .collect::<Vec<_>>();
        assert_eq!(super::get_directories_with_max_semver_major(directories), expected_result);
    }

    #[test]
    fn get_slice_name_and_version_from_string() {
        let string = "my_app-2.0.0-beta".to_string();
        let (slice_name, version) = super::get_slice_name_and_version_from_string(&string);
        assert_eq!(slice_name, "my_app");
        assert_eq!(version.major, 2);
        assert_eq!(version.minor, 0);
        assert_eq!(version.patch, 0);
    }
}
<commit_msg>Fixed #13<commit_after>use std::error::Error;
use std::fs::{File, metadata, read_dir};
use std::io::{ErrorKind, Read};
use std::path::Path;
use semver::Version;
use super::item::Slice;
use super::section::Section;
use helper;
use version;

/// # Examples
/// ```
/// use std::env;
/// use sb::slice::directory;
/// let current_dir = env::current_dir();
/// let mut current_dir = current_dir.unwrap().to_path_buf();
/// current_dir.push("test_slices");
/// match directory::get_latest_slice_directories(&current_dir) {
///     Ok(directories) => {
///         assert_eq!(directories, vec!["slices-1.0.0-alpha", "slices-1.0.1"]);
///     }
///     Err(error) => panic!("{}", error)
/// }
/// ```
pub fn get_latest_slice_directories(slices_directory: &Path) -> Result<Vec<String>, String> {
    match get_directories_in_directory(&slices_directory) {
        Ok(directories) => {
            if directories.is_empty() {
                return Err("There are no any slices".to_string())
            }
            let directories = get_directories_with_max_semver_major(directories);
            assert!(!directories.is_empty());
            Ok(directories)
        }
        Err(error) => Err(error)
    }
}

pub fn get_latest_slices_from_slice_root_directory(slice_root_directory: &Path)
                                                   -> Result<Vec<Slice>, String> {
    match get_latest_slice_directories(&slice_root_directory) {
        Ok(slice_directories) => {
            let mut slices: Vec<Slice> = Vec::new();
            for directory in slice_directories {
                let mut path = slice_root_directory.to_path_buf();
                path.push(&directory);
                let slices_from_directory = get_slices_from_directory(&path);
                for slice in slices_from_directory {
                    slices.push(slice);
                }
            }
            Ok(slices)
        }
        Err(error) => Err(error),
    }
}

pub fn get_slices_from_directory(directory: &Path) -> Vec<Slice> {
    let mut slices: Vec<Slice> = Vec::new();
    add_slices_from_directory(&mut slices, directory);
    for slice in &mut slices {
        slice.path = helper::relative_path_from(&slice.path, directory).unwrap();
    }
    slices
}

fn get_directories_in_directory(directory: &Path) -> Result<Vec<String>, String> {
    match read_dir(directory) {
        Ok(result) => {
            let directories = result.filter(|entry| {
                if let Ok(ref entry) = *entry {
                    metadata(entry.path()).unwrap().is_dir()
                } else {
                    false
                }
                                    })
                                    .map(|entry| {
                let path = entry.unwrap().path();
                let path = helper::relative_path_from(&path, directory);
                path.unwrap().to_str().unwrap().to_string()
                                    })
                                    .collect();
            Ok(directories)
        }
        Err(error) => match error.kind() {
            ErrorKind::NotFound => {
                let directory = directory.to_str().unwrap();
                let error = format!("Directory \"{}\" is not exist", directory);
                Err(error)
            }
            _ => Err(error.description().to_string())
        }
    }
}

fn get_directories_with_max_semver_major(directories: Vec<String>) -> Vec<String> {
    if directories.is_empty() {
        return Vec::new();
    }

    let mut directories = directories.into_iter()
                                     .map(|d| {
        let (_, version) = get_slice_name_and_version_from_string(&d);
        (version, d)
                                     })
                                     .collect::<Vec<_>>();
    directories.sort_by(|a, b| b.0.cmp(&a.0));
    let major_version_max = directories[0].0.major;
    let mut directories = directories.into_iter()
                                     .filter(|d| d.0.major == major_version_max)
                                     .collect::<Vec<_>>();
    directories.sort_by(|a, b| a.0.cmp(&b.0));
    directories.into_iter().map(|d| d.1).collect::<Vec<_>>()
}

fn add_slices_from_directory(slices: &mut Vec<Slice>, directory: &Path) {
    assert!(metadata(&directory).unwrap().is_dir());
    for entry in read_dir(&directory).unwrap() {
        let entry_path = entry.unwrap().path();
        if metadata(&entry_path).unwrap().is_dir() {
            add_slices_from_directory(slices, &entry_path);
        } else {
            if let Some(slice) = get_slice_from_file_path(&entry_path) {
                slices.push(slice);
            }
        }
    }
}

fn get_slice_name_and_version_from_string(string: &str) -> (String, Version) {
    let iter = string.chars().enumerate();
    let positions = iter.filter(|&(_, c)| c == '-')
                        .map(|(i, _)| i)
                        .filter(|i| {
        if let Some(char) = string.chars().nth(i + 1) {
            char.is_digit(10)
        } else {
            false
        }
                        })
                        .collect::<Vec<_>>();
    match positions.len() {
        0 => (string.to_string(), version::zero()),
        _ => {
            let pos = *positions.last().unwrap();
            (string[..pos].to_string(), version::parse(&string[pos + 1..]))
        }
    }
}

fn get_slice_from_file_path(file_path: &Path) -> Option<Slice> {
    if let Some(file_extension) = file_path.extension() {
        let file_extension = file_extension.to_str().unwrap();
        if file_extension == "md" || file_extension == "txt" {
            return None;
        }
    }
    get_slice_from_checked_file_path(&file_path)
}

fn get_slice_from_checked_file_path(file_path: &Path) -> Option<Slice> {
    let mut file = File::open(file_path).unwrap();
    let mut content = String::new();
    let _ = file.read_to_string(&mut content).unwrap();
    let mut lines: Vec<String> = content.split('\n')
                                        .map(|n: &str| n.to_string().trim().to_string())
                                        .collect();
    let mut sections: Vec<Section> = Vec::new();
    while !lines.is_empty() {
        let (section, remaining_lines) = Section::load_from_lines(lines);
        if let Some(section) = section {
            sections.push(section);
            lines = remaining_lines;
        } else {
            return None;
        }
    }
    let file_name = &file_path.file_name().unwrap().to_str().unwrap().to_string();
    let (slice_name, version) = get_slice_name_and_version_from_string(file_name);
    let slice = Slice { name: slice_name, path: file_path.to_path_buf(), version: version,
                        sections: sections };
    Some(slice)
}

#[cfg(test)]
mod tests {
    use version;

    #[test]
    fn get_directories_with_max_semver_major() {
        let mut directories = Vec::new();
        directories.push("slices-1.0.1");
        directories.push("slices-0.2.1-beta.3");
        directories.push("slices-1.0.0-alpha");
        directories.push("slices-0.0.1-beta.3");
        let directories = directories.into_iter().map(|d| d.to_string()).collect::<Vec<_>>();
        let expected_result = vec!["slices-1.0.0-alpha", "slices-1.0.1"];
        let expected_result = expected_result.into_iter()
                                             .map(|d| d.to_string())
                                             .collect::<Vec<_>>();
        assert_eq!(super::get_directories_with_max_semver_major(directories), expected_result);
    }

    #[test]
    fn slice_with_only_major() {
        let (name, version) = super::get_slice_name_and_version_from_string("apache-2");
        assert_eq!(name, "apache");
        assert_eq!(version, version::parse("2"));
    }

    #[test]
    fn slice_with_dash_in_name() {
        let (name, version) = super::get_slice_name_and_version_from_string("my-apache-2");
        assert_eq!(name, "my-apache");
        assert_eq!(version, version::parse("2"));
    }

    #[test]
    fn get_slice_name_and_version_from_string() {
        let string = "my_app-2.0.0-beta".to_string();
        let (slice_name, version) = super::get_slice_name_and_version_from_string(&string);
        assert_eq!(slice_name, "my_app");
        assert_eq!(version.major, 2);
        assert_eq!(version.minor, 0);
        assert_eq!(version.patch, 0);
    }
}
<|endoftext|>