<commit_before>use std::iter;
use super::super::bag::Bag;
use super::super::stack;
use super::super::stack::Stack;
use super::super::queue::Queue;

#[derive(Clone, Debug)]
pub struct Digraph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Digraph {
    pub fn new(v: usize) -> Digraph {
        Digraph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn v(&self) -> usize {
        self.v
    }

    pub fn e(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
    }

    pub fn outdegree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.v() {
            for w in self.adj(v) {
                if v == w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("digraph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -> {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Vec<usize> {
        self.adj[v].iter().map(|v| v.clone()).collect::<Vec<usize>>()
    }

    pub fn reverse(&self) -> Digraph {
        let v = self.v;
        let mut adj = iter::repeat(Bag::new()).take(v).collect::<Vec<Bag<usize>>>();
        for s in 0 .. v {
            for e in self.adj(s) {
                adj[e].add(s);
            }
        }
        Digraph {
            v: v,
            e: self.e,
            adj: adj
        }
    }

    pub fn dfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, SearchSource::Single(s));
        path.dfs();
        path
    }

    pub fn bfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, SearchSource::Single(s));
        path.bfs();
        path
    }

    pub fn reverse_dfs_postorder<'a>(&'a self) -> stack::IntoIter<usize> {
        let mut dfo = DepthFirstOrder::new(self);
        dfo.init();
        dfo.reverse_post.into_iter()
    }

    pub fn kosaraju_sharir_scc<'a>(&'a self) -> KosarajuSharirSCC<'a> {
        KosarajuSharirSCC::new(self)
    }
}

pub enum SearchSource {
    Single(usize),
    Multi(Vec<usize>)
}

impl SearchSource {
    fn iter(&self) -> ::std::vec::IntoIter<usize> {
        match *self {
            SearchSource::Single(ref i) => vec![*i].into_iter(),
            SearchSource::Multi(ref vs) => vs.clone().into_iter()
        }
    }

    fn contains(&self, v: usize) -> bool {
        match *self {
            SearchSource::Single(ref i) => *i == v,
            SearchSource::Multi(ref vs) => vs.contains(&v)
        }
    }
}

pub struct SearchPaths<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    edge_to: Vec<Option<usize>>,
    source: SearchSource
}

impl<'a> SearchPaths<'a> {
    fn new<'b>(graph: &'b Digraph, source: SearchSource) -> SearchPaths<'b> {
        let mut marked = iter::repeat(false).take(graph.v()).collect::<Vec<bool>>();
        let edge_to = iter::repeat(None).take(graph.v()).collect();
        for s in source.iter() {
            marked[s] = true;
        }

        SearchPaths {
            graph: graph,
            marked: marked,
            edge_to: edge_to,
            source: source
        }
    }

    fn dfs_from(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs_from(w);
                self.edge_to[w] = Some(v);
            }
        }
    }

    fn dfs(&mut self) {
        for v in self.source.iter() {
            self.dfs_from(v);
        }
    }

    fn bfs(&mut self) {
        let mut q = Queue::new();
        for s in self.source.iter() {
            q.enqueue(s);
        }
        while !q.is_empty() {
            let v = q.dequeue().unwrap();
            for w in self.graph.adj(v) {
                if !self.marked[w] {
                    self.edge_to[w] = Some(v);
                    q.enqueue(w);
                    self.marked[w] = true;
                }
            }
        }
    }

    pub fn has_path_to(&self, v: usize) -> bool {
        self.marked[v]
    }

    pub fn path_to(&self, v: usize) -> Option<Vec<usize>> {
        if !self.has_path_to(v) {
            None
        } else {
            let mut path = Stack::new();
            let mut x = v;
            while !self.source.contains(x) {
                path.push(x);
                x = self.edge_to[x].unwrap();
            }
            path.push(x);
            Some(path.into_iter().collect())
        }
    }
}

pub struct DepthFirstOrder<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    reverse_post: Stack<usize>
}

impl<'a> DepthFirstOrder<'a> {
    fn new<'b>(graph: &'b Digraph) -> DepthFirstOrder<'b> {
        let marked = iter::repeat(false).take(graph.v()).collect();
        DepthFirstOrder {
            graph: graph,
            marked: marked,
            reverse_post: Stack::new()
        }
    }

    fn init(&mut self) {
        for v in 0 .. self.graph.v() {
            if !self.marked[v] {
                self.dfs(v)
            }
        }
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs(w);
            }
        }
        self.reverse_post.push(v);
    }
}

/// Compute the strongly-connected components of a digraph using the
/// Kosaraju-Sharir algorithm.
pub struct KosarajuSharirSCC<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    id: Vec<Option<usize>>,
    count: usize,
}

impl<'a> KosarajuSharirSCC<'a> {
    fn new<'b>(graph: &'b Digraph) -> KosarajuSharirSCC<'b> {
        let n = graph.v();
        let mut cc = KosarajuSharirSCC {
            graph: graph,
            marked: iter::repeat(false).take(n).collect(),
            id: iter::repeat(None).take(n).collect(),
            count: 0
        };
        cc.init();
        cc
    }

    fn init(&mut self) {
        for v in self.graph.reverse().reverse_dfs_postorder() {
            if !self.marked[v] {
                self.dfs(v);
                self.count += 1;
            }
        }
    }

    pub fn count(&self) -> usize {
        self.count
    }

    pub fn id(&self, v: usize) -> usize {
        self.id[v].unwrap()
    }

    pub fn connected(&self, v: usize, w: usize) -> bool {
        self.id[v] == self.id[w]
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        self.id[v] = Some(self.count);
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs(w)
            }
        }
    }
}

#[test]
fn test_digraph_visit() {
    let mut g = Digraph::new(13);
    g.add_edge(0, 1);
    g.add_edge(2, 0);
    g.add_edge(6, 0);
    g.add_edge(0, 5);

    g.add_edge(3, 5);
    g.add_edge(5, 4);

    g.add_edge(2, 3);
    g.add_edge(3, 2);

    g.add_edge(4, 3);
    g.add_edge(4, 2);
    g.add_edge(6, 4);

    g.add_edge(6, 8);
    g.add_edge(8, 6);

    g.add_edge(7, 6);

    g.add_edge(7, 9);
    g.add_edge(6, 9);

    g.add_edge(9, 10);
    g.add_edge(10, 12);
    g.add_edge(9, 11);
    g.add_edge(12, 9);
    g.add_edge(11, 12);

    // println!("dot => \n {}", g.to_dot());
    // println!("dot => \n {}", g.reverse().to_dot());
    assert_eq!(format!("{:?}", g.dfs(0).path_to(3).unwrap()), "[0, 5, 4, 2, 3]");
    assert_eq!(format!("{:?}", g.bfs(0).path_to(3).unwrap()), "[0, 5, 4, 3]");

    let scc = g.kosaraju_sharir_scc();

    assert!(scc.connected(6, 8));
    assert!(scc.connected(9, 12));
    assert!(!scc.connected(6, 7));
}

#[test]
fn test_digraph() {
    let mut g = Digraph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.v());
    assert_eq!(9, g.e());
    assert_eq!(1, g.outdegree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(&w));
    }

    assert_eq!(g.number_of_self_loops(), 0);
}

#[test]
fn test_digraph_functions() {
    let mut g = Digraph::new(5);
    for i in 0 .. 5 {
        for j in 0 .. 5 {
            g.add_edge(i, j);
        }
    }

    assert_eq!(2, g.number_of_self_loops());
}

#[test]
fn test_digraph_depth_first_search_order() {
    let mut g = Digraph::new(7);
    g.add_edge(0, 2);
    g.add_edge(0, 5);
    g.add_edge(0, 1);
    g.add_edge(6, 0);
    g.add_edge(5, 2);
    g.add_edge(3, 2);
    g.add_edge(3, 5);
    g.add_edge(1, 4);
    g.add_edge(3, 4);
    g.add_edge(3, 6);
    g.add_edge(6, 4);

    let dfo: Vec<usize> = g.reverse_dfs_postorder().collect();
    assert_eq!(vec![3, 6, 0, 5, 2, 1, 4], dfo);
}
<commit_msg>graph/directed: add dfs multi source search<commit_after>use std::iter;
use super::super::bag::Bag;
use super::super::stack;
use super::super::stack::Stack;
use super::super::queue::Queue;

#[derive(Clone, Debug)]
pub struct Digraph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Digraph {
    pub fn new(v: usize) -> Digraph {
        Digraph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn v(&self) -> usize {
        self.v
    }

    pub fn e(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
    }

    pub fn outdegree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.v() {
            for w in self.adj(v) {
                if v == w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("digraph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -> {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Vec<usize> {
        self.adj[v].iter().map(|v| v.clone()).collect::<Vec<usize>>()
    }

    pub fn reverse(&self) -> Digraph {
        let v = self.v;
        let mut adj = iter::repeat(Bag::new()).take(v).collect::<Vec<Bag<usize>>>();
        for s in 0 .. v {
            for e in self.adj(s) {
                adj[e].add(s);
            }
        }
        Digraph {
            v: v,
            e: self.e,
            adj: adj
        }
    }

    pub fn dfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, SearchSource::Single(s));
        path.dfs();
        path
    }

    pub fn dfs_multi_source<'a, T: IntoIterator<Item=usize>>(&'a self, s: T) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, SearchSource::Multi(s.into_iter().collect()));
        path.dfs();
        path
    }

    pub fn bfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, SearchSource::Single(s));
        path.bfs();
        path
    }

    pub fn reverse_dfs_postorder<'a>(&'a self) -> stack::IntoIter<usize> {
        let mut dfo = DepthFirstOrder::new(self);
        dfo.init();
        dfo.reverse_post.into_iter()
    }

    pub fn kosaraju_sharir_scc<'a>(&'a self) -> KosarajuSharirSCC<'a> {
        KosarajuSharirSCC::new(self)
    }
}

pub enum SearchSource {
    Single(usize),
    Multi(Vec<usize>)
}

impl SearchSource {
    fn iter(&self) -> ::std::vec::IntoIter<usize> {
        match *self {
            SearchSource::Single(ref i) => vec![*i].into_iter(),
            SearchSource::Multi(ref vs) => vs.clone().into_iter()
        }
    }

    fn contains(&self, v: usize) -> bool {
        match *self {
            SearchSource::Single(ref i) => *i == v,
            SearchSource::Multi(ref vs) => vs.contains(&v)
        }
    }
}

pub struct SearchPaths<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    edge_to: Vec<Option<usize>>,
    source: SearchSource
}

impl<'a> SearchPaths<'a> {
    fn new<'b>(graph: &'b Digraph, source: SearchSource) -> SearchPaths<'b> {
        let mut marked = iter::repeat(false).take(graph.v()).collect::<Vec<bool>>();
        let edge_to = iter::repeat(None).take(graph.v()).collect();
        for s in source.iter() {
            marked[s] = true;
        }

        SearchPaths {
            graph: graph,
            marked: marked,
            edge_to: edge_to,
            source: source
        }
    }

    fn dfs_from(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs_from(w);
                self.edge_to[w] = Some(v);
            }
        }
    }

    fn dfs(&mut self) {
        for v in self.source.iter() {
            self.dfs_from(v);
        }
    }

    fn bfs(&mut self) {
        let mut q = Queue::new();
        for s in self.source.iter() {
            q.enqueue(s);
        }
        while !q.is_empty() {
            let v = q.dequeue().unwrap();
            for w in self.graph.adj(v) {
                if !self.marked[w] {
                    self.edge_to[w] = Some(v);
                    q.enqueue(w);
                    self.marked[w] = true;
                }
            }
        }
    }

    pub fn has_path_to(&self, v: usize) -> bool {
        self.marked[v]
    }

    pub fn path_to(&self, v: usize) -> Option<Vec<usize>> {
        if !self.has_path_to(v) {
            None
        } else {
            let mut path = Stack::new();
            let mut x = v;
            while !self.source.contains(x) {
                path.push(x);
                x = self.edge_to[x].unwrap();
            }
            path.push(x);
            Some(path.into_iter().collect())
        }
    }
}

pub struct DepthFirstOrder<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    reverse_post: Stack<usize>
}

impl<'a> DepthFirstOrder<'a> {
    fn new<'b>(graph: &'b Digraph) -> DepthFirstOrder<'b> {
        let marked = iter::repeat(false).take(graph.v()).collect();
        DepthFirstOrder {
            graph: graph,
            marked: marked,
            reverse_post: Stack::new()
        }
    }

    fn init(&mut self) {
        for v in 0 .. self.graph.v() {
            if !self.marked[v] {
                self.dfs(v)
            }
        }
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs(w);
            }
        }
        self.reverse_post.push(v);
    }
}

/// Compute the strongly-connected components of a digraph using the
/// Kosaraju-Sharir algorithm.
pub struct KosarajuSharirSCC<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    id: Vec<Option<usize>>,
    count: usize,
}

impl<'a> KosarajuSharirSCC<'a> {
    fn new<'b>(graph: &'b Digraph) -> KosarajuSharirSCC<'b> {
        let n = graph.v();
        let mut cc = KosarajuSharirSCC {
            graph: graph,
            marked: iter::repeat(false).take(n).collect(),
            id: iter::repeat(None).take(n).collect(),
            count: 0
        };
        cc.init();
        cc
    }

    fn init(&mut self) {
        for v in self.graph.reverse().reverse_dfs_postorder() {
            if !self.marked[v] {
                self.dfs(v);
                self.count += 1;
            }
        }
    }

    pub fn count(&self) -> usize {
        self.count
    }

    pub fn id(&self, v: usize) -> usize {
        self.id[v].unwrap()
    }

    pub fn connected(&self, v: usize, w: usize) -> bool {
        self.id[v] == self.id[w]
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        self.id[v] = Some(self.count);
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs(w)
            }
        }
    }
}

#[test]
fn test_digraph_visit() {
    let mut g = Digraph::new(13);
    g.add_edge(0, 1);
    g.add_edge(2, 0);
    g.add_edge(6, 0);
    g.add_edge(0, 5);

    g.add_edge(3, 5);
    g.add_edge(5, 4);

    g.add_edge(2, 3);
    g.add_edge(3, 2);

    g.add_edge(4, 3);
    g.add_edge(4, 2);
    g.add_edge(6, 4);

    g.add_edge(6, 8);
    g.add_edge(8, 6);

    g.add_edge(7, 6);

    g.add_edge(7, 9);
    g.add_edge(6, 9);

    g.add_edge(9, 10);
    g.add_edge(10, 12);
    g.add_edge(9, 11);
    g.add_edge(12, 9);
    g.add_edge(11, 12);

    // println!("dot => \n {}", g.to_dot());
    // println!("dot => \n {}", g.reverse().to_dot());
    assert_eq!(format!("{:?}", g.dfs(0).path_to(3).unwrap()), "[0, 5, 4, 2, 3]");
    assert_eq!(format!("{:?}", g.bfs(0).path_to(3).unwrap()), "[0, 5, 4, 3]");

    // FIXME: bad test case
    assert_eq!(format!("{:?}", g.dfs_multi_source(vec![0, 4]).path_to(3).unwrap()),
               "[4, 2, 3]");

    let scc = g.kosaraju_sharir_scc();

    assert!(scc.connected(6, 8));
    assert!(scc.connected(9, 12));
    assert!(!scc.connected(6, 7));
}

#[test]
fn test_digraph() {
    let mut g = Digraph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.v());
    assert_eq!(9, g.e());
    assert_eq!(1, g.outdegree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(&w));
    }

    assert_eq!(g.number_of_self_loops(), 0);
}

#[test]
fn test_digraph_functions() {
    let mut g = Digraph::new(5);
    for i in 0 .. 5 {
        for j in 0 .. 5 {
            g.add_edge(i, j);
        }
    }

    assert_eq!(2, g.number_of_self_loops());
}

#[test]
fn test_digraph_depth_first_search_order() {
    let mut g = Digraph::new(7);
    g.add_edge(0, 2);
    g.add_edge(0, 5);
    g.add_edge(0, 1);
    g.add_edge(6, 0);
    g.add_edge(5, 2);
    g.add_edge(3, 2);
    g.add_edge(3, 5);
    g.add_edge(1, 4);
    g.add_edge(3, 4);
    g.add_edge(3, 6);
    g.add_edge(6, 4);

    let dfo: Vec<usize> = g.reverse_dfs_postorder().collect();
    assert_eq!(vec![3, 6, 0, 5, 2, 1, 4], dfo);
}
<|endoftext|>


<commit_before>use std::iter::Peekable;

use pest::iterators::Pair;
use pest::Parser;

use crate::error::RenderError;
use crate::grammar::{HandlebarsParser, Rule};

#[derive(PartialEq, Clone, Debug)]
pub enum PathSeg {
    Named(String),
    Ruled(Rule),
}

/// Represents the Json path in templates.
///
/// It can be either a local variable like `@first`, `../@index`,
/// or a normal relative path like `a/b/c`.
#[derive(PartialEq, Clone, Debug)]
pub enum Path {
    Relative((Vec<PathSeg>, String)),
    Local((usize, String, String)),
}

impl Path {
    pub(crate) fn new(raw: &str, segs: Vec<PathSeg>) -> Path {
        if let Some((level, name)) = get_local_path_and_level(&segs) {
            Path::Local((level, name, raw.to_owned()))
        } else {
            Path::Relative((segs, raw.to_owned()))
        }
    }

    pub fn parse(raw: &str) -> Result<Path, RenderError> {
        HandlebarsParser::parse(Rule::path, raw)
            .map(|p| {
                let parsed = p.flatten();
                let segs = parse_json_path_from_iter(&mut parsed.peekable(), raw.len());
                Ok(Path::new(raw, segs))
            })
            .map_err(|_| RenderError::new("Invalid JSON path"))?
    }

    pub(crate) fn raw(&self) -> &str {
        match self {
            Path::Relative((_, ref raw)) => raw,
            Path::Local((_, _, ref raw)) => raw,
        }
    }

    pub(crate) fn current() -> Path {
        Path::Relative((Vec::with_capacity(0), "".to_owned()))
    }

    // for test only
    pub(crate) fn with_named_paths(name_segs: &[&str]) -> Path {
        let segs = name_segs
            .iter()
            .map(|n| PathSeg::Named((*n).to_string()))
            .collect();
        Path::Relative((segs, name_segs.join("/")))
    }

    // for test only
    pub(crate) fn segs(&self) -> Option<&[PathSeg]> {
        match self {
            Path::Relative((segs, _)) => Some(segs),
            _ => None,
        }
    }
}

fn get_local_path_and_level(paths: &[PathSeg]) -> Option<(usize, String)> {
    paths.get(0).and_then(|seg| {
        if seg == &PathSeg::Ruled(Rule::path_local) {
            let mut level = 0;
            while paths[level + 1] == PathSeg::Ruled(Rule::path_up) {
                level += 1;
            }
            if let Some(PathSeg::Named(name)) = paths.get(level + 1) {
                Some((level, name.clone()))
            } else {
                None
            }
        } else {
            None
        }
    })
}

pub(crate) fn parse_json_path_from_iter<'a, I>(it: &mut Peekable<I>, limit: usize) -> Vec<PathSeg>
where
    I: Iterator<Item = Pair<'a, Rule>>,
{
    let mut path_stack = Vec::with_capacity(5);
    while let Some(n) = it.peek() {
        let span = n.as_span();
        if span.end() > limit {
            break;
        }

        match n.as_rule() {
            Rule::path_root => {
                path_stack.push(PathSeg::Ruled(Rule::path_root));
            }
            Rule::path_local => {
                path_stack.push(PathSeg::Ruled(Rule::path_local));
            }
            Rule::path_up => {
                path_stack.push(PathSeg::Ruled(Rule::path_up));
            }
            Rule::path_id | Rule::path_raw_id => {
                let name = n.as_str();
                if name != "this" {
                    path_stack.push(PathSeg::Named(name.to_string()));
                }
            }
            _ => {}
        }

        it.next();
    }

    path_stack
}

pub(crate) fn merge_json_path<'a>(path_stack: &mut Vec<String>, relative_path: &'a [PathSeg]) {
    for seg in relative_path {
        match seg {
            PathSeg::Named(ref s) => {
                path_stack.push(s.to_owned());
            }
            PathSeg::Ruled(Rule::path_root) => {}
            PathSeg::Ruled(Rule::path_up) => {}
            _ => {}
        }
    }
}
<commit_msg>(fix) clippy warnings on needless lifetime<commit_after>use std::iter::Peekable;

use pest::iterators::Pair;
use pest::Parser;

use crate::error::RenderError;
use crate::grammar::{HandlebarsParser, Rule};

#[derive(PartialEq, Clone, Debug)]
pub enum PathSeg {
    Named(String),
    Ruled(Rule),
}

/// Represents the Json path in templates.
///
/// It can be either a local variable like `@first`, `../@index`,
/// or a normal relative path like `a/b/c`.
#[derive(PartialEq, Clone, Debug)]
pub enum Path {
    Relative((Vec<PathSeg>, String)),
    Local((usize, String, String)),
}

impl Path {
    pub(crate) fn new(raw: &str, segs: Vec<PathSeg>) -> Path {
        if let Some((level, name)) = get_local_path_and_level(&segs) {
            Path::Local((level, name, raw.to_owned()))
        } else {
            Path::Relative((segs, raw.to_owned()))
        }
    }

    pub fn parse(raw: &str) -> Result<Path, RenderError> {
        HandlebarsParser::parse(Rule::path, raw)
            .map(|p| {
                let parsed = p.flatten();
                let segs = parse_json_path_from_iter(&mut parsed.peekable(), raw.len());
                Ok(Path::new(raw, segs))
            })
            .map_err(|_| RenderError::new("Invalid JSON path"))?
    }

    pub(crate) fn raw(&self) -> &str {
        match self {
            Path::Relative((_, ref raw)) => raw,
            Path::Local((_, _, ref raw)) => raw,
        }
    }

    pub(crate) fn current() -> Path {
        Path::Relative((Vec::with_capacity(0), "".to_owned()))
    }

    // for test only
    pub(crate) fn with_named_paths(name_segs: &[&str]) -> Path {
        let segs = name_segs
            .iter()
            .map(|n| PathSeg::Named((*n).to_string()))
            .collect();
        Path::Relative((segs, name_segs.join("/")))
    }

    // for test only
    pub(crate) fn segs(&self) -> Option<&[PathSeg]> {
        match self {
            Path::Relative((segs, _)) => Some(segs),
            _ => None,
        }
    }
}

fn get_local_path_and_level(paths: &[PathSeg]) -> Option<(usize, String)> {
    paths.get(0).and_then(|seg| {
        if seg == &PathSeg::Ruled(Rule::path_local) {
            let mut level = 0;
            while paths[level + 1] == PathSeg::Ruled(Rule::path_up) {
                level += 1;
            }
            if let Some(PathSeg::Named(name)) = paths.get(level + 1) {
                Some((level, name.clone()))
            } else {
                None
            }
        } else {
            None
        }
    })
}

pub(crate) fn parse_json_path_from_iter<'a, I>(it: &mut Peekable<I>, limit: usize) -> Vec<PathSeg>
where
    I: Iterator<Item = Pair<'a, Rule>>,
{
    let mut path_stack = Vec::with_capacity(5);
    while let Some(n) = it.peek() {
        let span = n.as_span();
        if span.end() > limit {
            break;
        }

        match n.as_rule() {
            Rule::path_root => {
                path_stack.push(PathSeg::Ruled(Rule::path_root));
            }
            Rule::path_local => {
                path_stack.push(PathSeg::Ruled(Rule::path_local));
            }
            Rule::path_up => {
                path_stack.push(PathSeg::Ruled(Rule::path_up));
            }
            Rule::path_id | Rule::path_raw_id => {
                let name = n.as_str();
                if name != "this" {
                    path_stack.push(PathSeg::Named(name.to_string()));
                }
            }
            _ => {}
        }

        it.next();
    }

    path_stack
}

pub(crate) fn merge_json_path(path_stack: &mut Vec<String>, relative_path: &[PathSeg]) {
    for seg in relative_path {
        match seg {
            PathSeg::Named(ref s) => {
                path_stack.push(s.to_owned());
            }
            PathSeg::Ruled(Rule::path_root) => {}
            PathSeg::Ruled(Rule::path_up) => {}
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>pub use self::tokens::{Doctype, Attributes, TagKind, StartTag, EndTag, Tag, Token};
pub use self::tokens::{DoctypeToken, TagToken, CommentToken, CharacterToken};

use self::states::{RawLessThanSign, RawEndTagOpen, RawEndTagName};
use self::states::{Rcdata, ScriptData, ScriptDataEscaped};

mod tokens;
mod states;

pub trait TokenSink {
    fn process_token(&mut self, token: Token);
}

fn ascii_letter(c: char) -> Option<char> {
    c.to_ascii_opt()
        .filtered(|a| a.is_alpha())
        .map(|a| a.to_lower().to_char())
}

pub struct Tokenizer<'sink, Sink> {
    priv sink: &'sink mut Sink,
    priv state: states::State,

    // FIXME: The state machine guarantees the tag exists when
    // we need it, so we could eliminate the Option overhead.
    // Leaving it as Option for now, to find bugs.
    priv current_tag: Option<Tag>,

    /// Last start tag name, for use in checking "appropriate end tag".
    priv last_start_tag_name: Option<~str>,

    /// The "temporary buffer" mentioned in the spec.
    priv temp_buf: ~str
}

#[deriving(Eq)]
enum ConsumeCharResult {
    Reconsume,
    Finished,
}

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    pub fn new(sink: &'sink mut Sink) -> Tokenizer<'sink, Sink> {
        Tokenizer {
            sink: sink,
            state: states::Data,
            current_tag: None,
            last_start_tag_name: None,
            temp_buf: ~"",
        }
    }

    pub fn feed(&mut self, input: &str) {
        debug!("feeding {:s}", input);
        let mut it = input.chars(); //.peekable();
        loop {
            match self.state {
                // These states do something other than consume a single character.
                states::CharacterReferenceInData | states::CharacterReferenceInRcdata
                | states::CharacterReferenceInAttributeValue | states::BogusComment
                | states::MarkupDeclarationOpen | states::CdataSection => {
                    fail!("FIXME: state {:?} not implemented", self.state);
                }

                _ => match it.next() {
                    None => return,
                    Some(c) => {
                        while self.process_char(c) == Reconsume {
                            // reconsume
                        }
                    }
                }
            }
        }
    }

    fn parse_error(&self, c: char) {
        error!("Parse error: saw {:?} in state {:?}", c, self.state);
    }

    fn emit_char(&self, c: char) {
        self.sink.process_token(CharacterToken(c));
    }

    fn emit_current_tag(&mut self) {
        let tag = self.current_tag.take().unwrap();
        match tag.kind {
            StartTag => self.last_start_tag_name = Some(tag.name.clone()),
            _ => ()
        }
        self.sink.process_token(TagToken(tag));
    }

    fn emit_temp_buf(&mut self) {
        // FIXME: Add a multi-character token and move temp_buf into it, something like
        //     self.sink.process_token(StringToken(
        //         replace(&mut self.temp_buf, ~"")))
        //
        // Need to make sure that clearing on emit is spec-compatible.
        //
        // Until then we reuse the same buffer allocation forever.
        for c in self.temp_buf.chars() {
            self.emit_char(c);
        }
    }

    fn clear_temp_buf(&mut self) {
        // Do this without a new allocation.
        self.temp_buf.truncate(0);
    }

    fn create_tag(&mut self, kind: TagKind, c: char) {
        assert!(self.current_tag.is_none());
        let mut t = Tag::new(kind);
        t.name.push_char(c);
        self.current_tag = Some(t);
    }

    fn append_to_tag_name(&mut self, c: char) {
        self.current_tag.get_mut_ref().name.push_char(c);
    }

    fn have_appropriate_end_tag(&self) -> bool {
        match (self.last_start_tag_name.as_ref(), self.current_tag.as_ref()) {
            (Some(last), Some(tag)) =>
                (tag.kind == EndTag) && (tag.name.as_slice() == last.as_slice()),
            _ => false
        }
    }
}

// Shorthand for common state machine behaviors.
macro_rules! shorthand (
    ( to          $state:ident             ) => ( self.state = states::$state;        );
    ( to_raw      $state:ident $kind:ident ) => ( self.state = states::$state($kind); );
    ( emit        $c:expr                  ) => ( self.emit_char($c);                 );
    ( create_tag  $kind:expr   $c:expr     ) => ( self.create_tag($kind, $c);         );
    ( append_tag  $c:expr                  ) => ( self.append_to_tag_name($c);        );
    ( emit_tag                             ) => ( self.emit_current_tag();            );
    ( append_temp $c:expr                  ) => ( self.temp_buf.push_char($c);        );
    ( emit_temp                            ) => ( self.emit_temp_buf();               );
    ( clear_temp                           ) => ( self.clear_temp_buf();              );

    // NB: Deliberate capture of 'c'
    ( error                                ) => ( self.parse_error(c);                );
)

// A little DSL for sequencing shorthand actions.
macro_rules! go (
    // A pattern like $($cmd:tt)* ; $($rest:tt)* causes parse ambiguity.
    // We have to tell the parser how much lookahead we need.
    ( $a:tt             ; $($rest:tt)* ) => ({ shorthand!($a);       go!($($rest)*); });
    ( $a:tt $b:tt       ; $($rest:tt)* ) => ({ shorthand!($a $b);    go!($($rest)*); });
    ( $a:tt $b:tt $c:tt ; $($rest:tt)* ) => ({ shorthand!($a $b $c); go!($($rest)*); });

    // These can only come at the end.
    // FIXME: Come up with a better name for 'finish'.
    ( reconsume ) => ( return Reconsume; );
    ( finish    ) => ( return Finished;  );

    // If nothing else matched, it's a single command
    ( $($cmd:tt)+ ) => ( shorthand!($($cmd)+); );

    // or nothing.
    () => (());
)

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    // FIXME: explicitly represent the EOF character?
    // For now the plan is to handle EOF in a separate match.
    fn process_char(&mut self, c: char) -> ConsumeCharResult {
        debug!("Processing {:?} in state {:?}", c, self.state);
        match self.state {
            states::Data => match c {
                '&'  => go!(to CharacterReferenceInData),
                '<'  => go!(to TagOpen),
                '\0' => go!(error; emit '\0'),
                _    => go!(emit c),
            },

            // RCDATA, RAWTEXT, script, or script escaped
            states::RawData(kind) => match c {
                '&' if kind == Rcdata            => go!(to CharacterReferenceInRcdata),
                '-' if kind == ScriptDataEscaped => go!(to ScriptDataEscapedDash; emit '-'),
                '<'  => go!(to_raw RawLessThanSign kind),
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::Plaintext => match c {
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::TagOpen => match c {
                '!' => go!(to MarkupDeclarationOpen),
                '/' => go!(to EndTagOpen),
                '?' => go!(error; to BogusComment),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag StartTag cl; to TagName),
                    None     => go!(error; emit '<'; to Data; reconsume),
                }
            },

            states::EndTagOpen => match c {
                '>' => go!(error; to Data),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag EndTag cl; to TagName),
                    None     => go!(error; to BogusComment),
                }
            },

            states::TagName => match c {
                '\t' | '\n' | '\x0C' | ' '
                     => go!(to BeforeAttributeName),
                '/'  => go!(to SelfClosingStartTag),
                '>'  => go!(emit_tag; to Data),
                '\0' => go!(error; append_tag '\ufffd'),
                _    => go!(append_tag (ascii_letter(c).unwrap_or(c))),
            },

            // kind = ScriptDataEscaped
            states::RawLessThanSign(ScriptDataEscaped) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen ScriptDataEscaped),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(clear_temp; append_temp cl;
                                    to ScriptDataDoubleEscapeStart; emit '<'; emit c),
                    None => go!(to_raw RawData ScriptDataEscaped; emit '<'; reconsume),
                }
            },

            // otherwise
            states::RawLessThanSign(kind) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen kind),
                '!' if kind == ScriptData => go!(to ScriptDataEscapeStart; emit '<'; emit '!'),
                _   => go!(to_raw RawData Rcdata; emit '<'; reconsume),
            },

            states::RawEndTagOpen(kind) => match ascii_letter(c) {
                Some(cl) => go!(create_tag EndTag cl; append_temp c; to_raw RawEndTagName kind),
                None     => go!(to_raw RawData kind; emit '<'; emit '/'; reconsume),
            },

            states::RawEndTagName(kind) => {
                if self.have_appropriate_end_tag() {
                    match c {
                        '\t' | '\n' | '\x0C' | ' '
                            => go!(to BeforeAttributeName; finish),
                        '/' => go!(to SelfClosingStartTag; finish),
                        '>' => go!(emit_tag; to Data; finish),
                        // All of the above end with a return from this function.

                        _ => (),
                    }
                }

                match ascii_letter(c) {
                    Some(cl) => go!(append_tag cl; append_temp c),
                    None     => go!(emit '<'; emit '/'; emit_temp; to_raw RawData kind; reconsume),
                }
            },

            s => fail!("FIXME: state {:?} not implemented", s),
        }

        Finished

    }
}
<commit_msg>Note reconsume bug<commit_after>pub use self::tokens::{Doctype, Attributes, TagKind, StartTag, EndTag, Tag, Token};
pub use self::tokens::{DoctypeToken, TagToken, CommentToken, CharacterToken};

use self::states::{RawLessThanSign, RawEndTagOpen, RawEndTagName};
use self::states::{Rcdata, ScriptData, ScriptDataEscaped};

mod tokens;
mod states;

pub trait TokenSink {
    fn process_token(&mut self, token: Token);
}

fn ascii_letter(c: char) -> Option<char> {
    c.to_ascii_opt()
        .filtered(|a| a.is_alpha())
        .map(|a| a.to_lower().to_char())
}

pub struct Tokenizer<'sink, Sink> {
    priv sink: &'sink mut Sink,
    priv state: states::State,

    // FIXME: The state machine guarantees the tag exists when
    // we need it, so we could eliminate the Option overhead.
    // Leaving it as Option for now, to find bugs.
    priv current_tag: Option<Tag>,

    /// Last start tag name, for use in checking "appropriate end tag".
    priv last_start_tag_name: Option<~str>,

    /// The "temporary buffer" mentioned in the spec.
    priv temp_buf: ~str
}

#[deriving(Eq)]
enum ConsumeCharResult {
    Reconsume,
    Finished,
}

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    pub fn new(sink: &'sink mut Sink) -> Tokenizer<'sink, Sink> {
        Tokenizer {
            sink: sink,
            state: states::Data,
            current_tag: None,
            last_start_tag_name: None,
            temp_buf: ~"",
        }
    }

    pub fn feed(&mut self, input: &str) {
        debug!("feeding {:s}", input);
        let mut it = input.chars(); //.peekable();
        loop {
            match self.state {
                // These states do something other than consume a single character.
                states::CharacterReferenceInData | states::CharacterReferenceInRcdata
                | states::CharacterReferenceInAttributeValue | states::BogusComment
                | states::MarkupDeclarationOpen | states::CdataSection => {
                    fail!("FIXME: state {:?} not implemented", self.state);
                }

                _ => match it.next() {
                    None => return,
                    Some(c) => {
                        while self.process_char(c) == Reconsume {
                            // FIXME: this is not correct when state changes to one
                            // of the above!
                        }
                    }
                }
            }
        }
    }

    fn parse_error(&self, c: char) {
        error!("Parse error: saw {:?} in state {:?}", c, self.state);
    }

    fn emit_char(&self, c: char) {
        self.sink.process_token(CharacterToken(c));
    }

    fn emit_current_tag(&mut self) {
        let tag = self.current_tag.take().unwrap();
        match tag.kind {
            StartTag => self.last_start_tag_name = Some(tag.name.clone()),
            _ => ()
        }
        self.sink.process_token(TagToken(tag));
    }

    fn emit_temp_buf(&mut self) {
        // FIXME: Add a multi-character token and move temp_buf into it, something like
        //     self.sink.process_token(StringToken(
        //         replace(&mut self.temp_buf, ~"")))
        //
        // Need to make sure that clearing on emit is spec-compatible.
        //
        // Until then we reuse the same buffer allocation forever.
        for c in self.temp_buf.chars() {
            self.emit_char(c);
        }
    }

    fn clear_temp_buf(&mut self) {
        // Do this without a new allocation.
        self.temp_buf.truncate(0);
    }

    fn create_tag(&mut self, kind: TagKind, c: char) {
        assert!(self.current_tag.is_none());
        let mut t = Tag::new(kind);
        t.name.push_char(c);
        self.current_tag = Some(t);
    }

    fn append_to_tag_name(&mut self, c: char) {
        self.current_tag.get_mut_ref().name.push_char(c);
    }

    fn have_appropriate_end_tag(&self) -> bool {
        match (self.last_start_tag_name.as_ref(), self.current_tag.as_ref()) {
            (Some(last), Some(tag)) =>
                (tag.kind == EndTag) && (tag.name.as_slice() == last.as_slice()),
            _ => false
        }
    }
}

// Shorthand for common state machine behaviors.
macro_rules! shorthand (
    ( to          $state:ident             ) => ( self.state = states::$state;        );
    ( to_raw      $state:ident $kind:ident ) => ( self.state = states::$state($kind); );
    ( emit        $c:expr                  ) => ( self.emit_char($c);                 );
    ( create_tag  $kind:expr   $c:expr     ) => ( self.create_tag($kind, $c);         );
    ( append_tag  $c:expr                  ) => ( self.append_to_tag_name($c);        );
    ( emit_tag                             ) => ( self.emit_current_tag();            );
    ( append_temp $c:expr                  ) => ( self.temp_buf.push_char($c);        );
    ( emit_temp                            ) => ( self.emit_temp_buf();               );
    ( clear_temp                           ) => ( self.clear_temp_buf();              );

    // NB: Deliberate capture of 'c'
    ( error                                ) => ( self.parse_error(c);                );
)

// A little DSL for sequencing shorthand actions.
macro_rules! go (
    // A pattern like $($cmd:tt)* ; $($rest:tt)* causes parse ambiguity.
    // We have to tell the parser how much lookahead we need.
    ( $a:tt             ; $($rest:tt)* ) => ({ shorthand!($a);       go!($($rest)*); });
    ( $a:tt $b:tt       ; $($rest:tt)* ) => ({ shorthand!($a $b);    go!($($rest)*); });
    ( $a:tt $b:tt $c:tt ; $($rest:tt)* ) => ({ shorthand!($a $b $c); go!($($rest)*); });

    // These can only come at the end.
    // FIXME: Come up with a better name for 'finish'.
    ( reconsume ) => ( return Reconsume; );
    ( finish    ) => ( return Finished;  );

    // If nothing else matched, it's a single command
    ( $($cmd:tt)+ ) => ( shorthand!($($cmd)+); );

    // or nothing.
    () => (());
)

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    // FIXME: explicitly represent the EOF character?
    // For now the plan is to handle EOF in a separate match.
    fn process_char(&mut self, c: char) -> ConsumeCharResult {
        debug!("Processing {:?} in state {:?}", c, self.state);
        match self.state {
            states::Data => match c {
                '&'  => go!(to CharacterReferenceInData),
                '<'  => go!(to TagOpen),
                '\0' => go!(error; emit '\0'),
                _    => go!(emit c),
            },

            // RCDATA, RAWTEXT, script, or script escaped
            states::RawData(kind) => match c {
                '&' if kind == Rcdata            => go!(to CharacterReferenceInRcdata),
                '-' if kind == ScriptDataEscaped => go!(to ScriptDataEscapedDash; emit '-'),
                '<'  => go!(to_raw RawLessThanSign kind),
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::Plaintext => match c {
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::TagOpen => match c {
                '!' => go!(to MarkupDeclarationOpen),
                '/' => go!(to EndTagOpen),
                '?' => go!(error; to BogusComment),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag StartTag cl; to TagName),
                    None     => go!(error; emit '<'; to Data; reconsume),
                }
            },

            states::EndTagOpen => match c {
                '>' => go!(error; to Data),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag EndTag cl; to TagName),
                    None     => go!(error; to BogusComment),
                }
            },

            states::TagName => match c {
                '\t' | '\n' | '\x0C' | ' '
                     => go!(to BeforeAttributeName),
                '/'  => go!(to SelfClosingStartTag),
                '>'  => go!(emit_tag; to Data),
                '\0' => go!(error; append_tag '\ufffd'),
                _    => go!(append_tag (ascii_letter(c).unwrap_or(c))),
            },

            // kind = ScriptDataEscaped
            states::RawLessThanSign(ScriptDataEscaped) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen ScriptDataEscaped),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(clear_temp; append_temp cl;
                                    to ScriptDataDoubleEscapeStart; emit '<'; emit c),
                    None => go!(to_raw RawData ScriptDataEscaped; emit '<'; reconsume),
                }
            },

            // otherwise
            states::RawLessThanSign(kind) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen kind),
                '!' if kind == ScriptData => go!(to ScriptDataEscapeStart; emit '<'; emit '!'),
                _   => go!(to_raw RawData Rcdata; emit '<'; reconsume),
            },

            states::RawEndTagOpen(kind) => match ascii_letter(c) {
                Some(cl) => go!(create_tag EndTag cl; append_temp c; to_raw RawEndTagName kind),
                None     => go!(to_raw RawData kind; emit '<'; emit '/'; reconsume),
            },

            states::RawEndTagName(kind) => {
                if self.have_appropriate_end_tag() {
                    match c {
                        '\t' | '\n' | '\x0C' | ' '
                            => go!(to BeforeAttributeName; finish),
                        '/' => go!(to SelfClosingStartTag; finish),
                        '>' => go!(emit_tag; to Data; finish),
                        // All of the above end with a return from this function.

                        _ => (),
                    }
                }

                match ascii_letter(c) {
                    Some(cl) => go!(append_tag cl; append_temp c),
                    None     => go!(emit '<'; emit '/'; emit_temp; to_raw RawData kind; reconsume),
                }
            },

            s => fail!("FIXME: state {:?} not implemented", s),
        }

        Finished

    }
}
<|endoftext|>


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

use clap;

use std::ffi::OsString;

use super::{Context, ArgumentType};
use super::internal::{Feedback, CollectedCommand};

pub struct ClapBackend;

impl ClapBackend {
    // TODO: remove code duplication (ECR-164)
    #[doc(hidden)]
    pub fn execute_cmd_string<I, T>(commands: &[CollectedCommand], line: I) -> Feedback
    where
        I: IntoIterator<Item = T>,
        T: Into<OsString> + Clone,
    {
        let subcommands: Vec<_> = commands
            .iter()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();
        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about(
                "It contain basic set of command, to deploy network on exonum.",
            )
            .subcommands(subcommands.into_iter())
            .get_matches_from_safe(line)
            .unwrap();

        let subcommand = matches.subcommand();
        for command in commands {
            if command.name() == subcommand.0 {
                return command.execute(Context::new_from_args(
                    command.args(),
                    subcommand.1.expect("Arguments not found."),
                ));
            }
        }

        panic!("Subcommand not found");
    }

    pub fn execute(commands: &[CollectedCommand]) -> Feedback {
        let subcommands: Vec<_> = commands
            .iter()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();

        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about("Exonum application based on fabric configuration.")
            .subcommands(subcommands.into_iter())
            .get_matches();

        let subcommand = matches.subcommand();
        for command in commands {
            if command.name() == subcommand.0 {
                return command.execute(Context::new_from_args(
                    command.args(),
                    subcommand.1.expect("Arguments not found."),
                ));
            }
        }

        panic!("Subcommand not found");
    }

    fn command_into_subcommand(command: &CollectedCommand) -> clap::App {
        let mut index = 1;
        let command_args: Vec<_> = command
            .args()
            .iter()
            .map(|arg| {
                let clap_arg = clap::Arg::with_name(arg.name);
                let clap_arg = match arg.argument_type {
                    ArgumentType::Positional => {
                        let arg = clap_arg.index(index);
                        index += 1;
                        arg
                    }
                    ArgumentType::Named(detail) => {
                        let mut clap_arg = clap_arg.long(detail.long_name);
                        if let Some(short) = detail.short_name {
                            clap_arg = clap_arg.short(short);
                        }
                        clap_arg.multiple(detail.multiple).takes_value(true)
                    }
                };
                clap_arg.help(arg.help).required(arg.required)

            })
            .collect();

        let mut subcommand = clap::SubCommand::with_name(command.name()).about(command.about());

        subcommand = subcommand.args(&command_args);

        subcommand
    }
}
<commit_msg>ClapBackend: Show a help message when there're no args<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap;

use std::ffi::OsString;

use super::{Context, ArgumentType};
use super::internal::{Feedback, CollectedCommand};

pub struct ClapBackend;

impl ClapBackend {
    // TODO: remove code duplication (ECR-164)
    #[doc(hidden)]
    pub fn execute_cmd_string<I, T>(commands: &[CollectedCommand], line: I) -> Feedback
    where
        I: IntoIterator<Item = T>,
        T: Into<OsString> + Clone,
    {
        let subcommands: Vec<_> = commands
            .iter()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();
        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about(
                "It contain basic set of command, to deploy network on exonum.",
            )
            .subcommands(subcommands.into_iter())
            .get_matches_from_safe(line)
            .unwrap();

        let subcommand = matches.subcommand();
        for command in commands {
            if command.name() == subcommand.0 {
                return command.execute(Context::new_from_args(
                    command.args(),
                    subcommand.1.expect("Arguments not found."),
                ));
            }
        }

        panic!("Subcommand not found");
    }

    pub fn execute(commands: &[CollectedCommand]) -> Feedback {
        let subcommands: Vec<_> = commands
            .iter()
            .map(|command| ClapBackend::command_into_subcommand(command))
            .collect();

        let matches = clap::App::new("Exonum application based on fabric configuration.")
            .setting(clap::AppSettings::ArgRequiredElseHelp)
            .version(crate_version!())
            .author(crate_authors!("\n"))
            .about("Exonum application based on fabric configuration.")
            .subcommands(subcommands.into_iter())
            .get_matches();

        let subcommand = matches.subcommand();
        for command in commands {
            if command.name() == subcommand.0 {
                return command.execute(Context::new_from_args(
                    command.args(),
                    subcommand.1.expect("Arguments not found."),
                ));
            }
        }

        panic!("Subcommand not found");
    }

    fn command_into_subcommand(command: &CollectedCommand) -> clap::App {
        let mut index = 1;
        let command_args: Vec<_> = command
            .args()
            .iter()
            .map(|arg| {
                let clap_arg = clap::Arg::with_name(arg.name);
                let clap_arg = match arg.argument_type {
                    ArgumentType::Positional => {
                        let arg = clap_arg.index(index);
                        index += 1;
                        arg
                    }
                    ArgumentType::Named(detail) => {
                        let mut clap_arg = clap_arg.long(detail.long_name);
                        if let Some(short) = detail.short_name {
                            clap_arg = clap_arg.short(short);
                        }
                        clap_arg.multiple(detail.multiple).takes_value(true)
                    }
                };
                clap_arg.help(arg.help).required(arg.required)

            })
            .collect();

        let mut subcommand = clap::SubCommand::with_name(command.name()).about(command.about());

        subcommand = subcommand.args(&command_args);

        subcommand
    }
}
<|endoftext|>


<commit_before>use specs::*;

use amq_protocol_types::types::*;
use itertools::Itertools;
use serde_json::Value;

use std::collections::BTreeMap;

/* Modified version of AMQProtocolDefinition to handle deserialization */
#[derive(Debug, Deserialize)]
pub struct _AMQProtocolDefinition {
    name:          ShortString,
    #[serde(rename="major-version")]
    major_version: ShortShortUInt,
    #[serde(rename="minor-version")]
    minor_version: ShortShortUInt,
    revision:      ShortShortUInt,
    port:          LongUInt,
    copyright:     Vec<LongString>,
    domains:       Vec<_AMQPDomain>,
    constants:     Vec<AMQPConstant>,
    classes:       Vec<_AMQPClass>,
}

impl _AMQProtocolDefinition {
    pub fn to_specs(self) -> AMQProtocolDefinition {
        let domains = self.domains.iter().fold(BTreeMap::new(), |mut domains, domain| {
            domains.insert(domain.0.clone(), domain.1.to_specs());
            domains
        });
        let classes = self.classes.iter().map(|klass| klass.to_specs(&domains)).collect();
        AMQProtocolDefinition {
            name:          self.name,
            major_version: self.major_version,
            minor_version: self.minor_version,
            revision:      self.revision,
            port:          self.port,
            copyright:     self.copyright.iter().join(""),
            domains:       domains,
            constants:     self.constants,
            classes:       classes,
        }
    }
}

/* Defined as a two-elems array in the spec */
#[derive(Debug, Deserialize)]
struct _AMQPDomain(ShortString, _AMQPType);

/* Subset of AMQPType used in specs for deserialization */
#[derive(Debug, Deserialize)]
enum _AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl _AMQPType {
    fn to_specs(&self) -> AMQPType {
        match *self {
            _AMQPType::Bit       => AMQPType::Boolean,
            _AMQPType::Octet     => AMQPType::ShortShortUInt,
            _AMQPType::Short     => AMQPType::ShortUInt,
            _AMQPType::Long      => AMQPType::LongUInt,
            _AMQPType::LongLong  => AMQPType::LongLongUInt,
            _AMQPType::ShortStr  => AMQPType::ShortString,
            _AMQPType::LongStr   => AMQPType::LongString,
            _AMQPType::Table     => AMQPType::FieldTable,
            _AMQPType::Timestamp => AMQPType::Timestamp,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPClass {
    id:         ShortUInt,
    methods:    Vec<_AMQPMethod>,
    name:       ShortString,
    properties: Option<Vec<_AMQPProperty>>,
}

impl _AMQPClass {
    fn to_specs(&self, domains: &BTreeMap<String, AMQPType>) -> AMQPClass {
        AMQPClass {
            id:            self.id,
            methods:       self.methods.iter().map(|method| method.to_specs(domains)).collect(),
            name:          self.name.clone(),
            properties:    match self.properties {
                Some(ref properties) => properties.iter().map(|prop| prop.to_specs()).collect(),
                None                 => Vec::new(),
            },
            is_connection: self.id == 10,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPMethod {
    id:          ShortUInt,
    arguments:   Vec<_AMQPArgument>,
    name:        ShortString,
    synchronous: Option<Boolean>,
}

impl _AMQPMethod {
    fn to_specs(&self, domains: &BTreeMap<ShortString, AMQPType>) -> AMQPMethod {
        AMQPMethod {
            id:          self.id,
            arguments:   self.arguments.iter().map(|arg| arg.to_specs(domains)).collect(),
            name:        self.name.clone(),
            synchronous: self.synchronous.unwrap_or(false),
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPArgument {
    #[serde(rename="type")]
    amqp_type:     Option<_AMQPType>,
    name:          ShortString,
    #[serde(rename="default-value")]
    default_value: Option<Value>,
    domain:        Option<ShortString>,
}

impl _AMQPArgument {
    fn to_specs(&self, domains: &BTreeMap<ShortString, AMQPType>) -> AMQPArgument {
        AMQPArgument::Value(AMQPValueArgument {
            amqp_type:     match self.amqp_type {
                Some(ref amqp_type) => amqp_type.to_specs(),
                None                => {
                    let domain = match self.domain {
                        Some(ref domain) => domain,
                        None             => panic!(format!("{} has no type nor domain", self.name)),
                    };
                    domains.get(domain).expect(&format!("No {} domain exists", domain)).clone()
                },
            },
            name:          self.name.clone(),
            default_value: self.default_value.as_ref().map(From::from),
            domain:        self.domain.clone(),
        })
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPProperty {
    #[serde(rename="type")]
    amqp_type: _AMQPType,
    name:      ShortString,
}

impl _AMQPProperty {
    fn to_specs(&self) -> AMQPProperty {
        AMQPProperty {
            amqp_type: self.amqp_type.to_specs(),
            name:      self.name.clone(),
        }
    }
}
<commit_msg>codegen: export flags as such<commit_after>use specs::*;

use amq_protocol_types::types::*;
use itertools::Itertools;
use serde_json::Value;

use std::collections::BTreeMap;

/* Modified version of AMQProtocolDefinition to handle deserialization */
#[derive(Debug, Deserialize)]
pub struct _AMQProtocolDefinition {
    name:          ShortString,
    #[serde(rename="major-version")]
    major_version: ShortShortUInt,
    #[serde(rename="minor-version")]
    minor_version: ShortShortUInt,
    revision:      ShortShortUInt,
    port:          LongUInt,
    copyright:     Vec<LongString>,
    domains:       Vec<_AMQPDomain>,
    constants:     Vec<AMQPConstant>,
    classes:       Vec<_AMQPClass>,
}

impl _AMQProtocolDefinition {
    pub fn to_specs(self) -> AMQProtocolDefinition {
        let domains = self.domains.iter().fold(BTreeMap::new(), |mut domains, domain| {
            domains.insert(domain.0.clone(), domain.1.to_specs());
            domains
        });
        let classes = self.classes.iter().map(|klass| klass.to_specs(&domains)).collect();
        AMQProtocolDefinition {
            name:          self.name,
            major_version: self.major_version,
            minor_version: self.minor_version,
            revision:      self.revision,
            port:          self.port,
            copyright:     self.copyright.iter().join(""),
            domains:       domains,
            constants:     self.constants,
            classes:       classes,
        }
    }
}

/* Defined as a two-elems array in the spec */
#[derive(Debug, Deserialize)]
struct _AMQPDomain(ShortString, _AMQPType);

/* Subset of AMQPType used in specs for deserialization */
#[derive(Debug, Deserialize)]
enum _AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl _AMQPType {
    fn to_specs(&self) -> AMQPType {
        match *self {
            _AMQPType::Bit       => AMQPType::Boolean,
            _AMQPType::Octet     => AMQPType::ShortShortUInt,
            _AMQPType::Short     => AMQPType::ShortUInt,
            _AMQPType::Long      => AMQPType::LongUInt,
            _AMQPType::LongLong  => AMQPType::LongLongUInt,
            _AMQPType::ShortStr  => AMQPType::ShortString,
            _AMQPType::LongStr   => AMQPType::LongString,
            _AMQPType::Table     => AMQPType::FieldTable,
            _AMQPType::Timestamp => AMQPType::Timestamp,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPClass {
    id:         ShortUInt,
    methods:    Vec<_AMQPMethod>,
    name:       ShortString,
    properties: Option<Vec<_AMQPProperty>>,
}

impl _AMQPClass {
    fn to_specs(&self, domains: &BTreeMap<String, AMQPType>) -> AMQPClass {
        AMQPClass {
            id:            self.id,
            methods:       self.methods.iter().map(|method| method.to_specs(domains)).collect(),
            name:          self.name.clone(),
            properties:    match self.properties {
                Some(ref properties) => properties.iter().map(|prop| prop.to_specs()).collect(),
                None                 => Vec::new(),
            },
            is_connection: self.id == 10,
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPMethod {
    id:          ShortUInt,
    arguments:   Vec<_AMQPArgument>,
    name:        ShortString,
    synchronous: Option<Boolean>,
}

impl _AMQPMethod {
    fn to_specs(&self, domains: &BTreeMap<ShortString, AMQPType>) -> AMQPMethod {
        AMQPMethod {
            id:          self.id,
            arguments:   self.arguments_to_specs(domains),
            name:        self.name.clone(),
            synchronous: self.synchronous.unwrap_or(false),
        }
    }

    fn arguments_to_specs(&self, domains: &BTreeMap<ShortString, AMQPType>) -> Vec<AMQPArgument> {
        let mut arguments                            = Vec::new();
        let mut flags : Option<Vec<AMQPFlagArgument>> = None;
        for argument in &self.arguments {
            let amqp_type = argument.get_type(domains);
            if amqp_type == AMQPType::Boolean {
                let mut flgs = flags.take().unwrap_or_else(|| Vec::new());
                flgs.push(argument.to_flag_specs());
                flags = Some(flgs);
            } else {
                if let Some(flags) = flags.take() {
                    arguments.push(AMQPArgument::Flags(flags));
                }
                arguments.push(AMQPArgument::Value(argument.to_value_specs(amqp_type)));
            }
        }
        if let Some(flags) = flags.take() {
            arguments.push(AMQPArgument::Flags(flags));
        }
        arguments
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPArgument {
    #[serde(rename="type")]
    amqp_type:     Option<_AMQPType>,
    name:          ShortString,
    #[serde(rename="default-value")]
    default_value: Option<Value>,
    domain:        Option<ShortString>,
}

impl _AMQPArgument {
    fn to_flag_specs(&self) -> AMQPFlagArgument {
        AMQPFlagArgument {
            name:          self.name.clone(),
            default_value: self.default_value.as_ref().and_then(|v| v.as_u64()).map(|u| u != 0).unwrap_or(false),
        }
    }

    fn to_value_specs(&self, amqp_type: AMQPType) -> AMQPValueArgument {
        AMQPValueArgument {
            amqp_type:     amqp_type,
            name:          self.name.clone(),
            default_value: self.default_value.as_ref().map(From::from),
            domain:        self.domain.clone(),
        }
    }

    fn get_type(&self, domains: &BTreeMap<ShortString, AMQPType>) -> AMQPType {
        match self.amqp_type {
            Some(ref amqp_type) => amqp_type.to_specs(),
            None                => {
                let domain = match self.domain {
                    Some(ref domain) => domain,
                    None             => panic!(format!("{} has no type nor domain", self.name)),
                };
                domains.get(domain).expect(&format!("No {} domain exists", domain)).clone()
            },
        }
    }
}

#[derive(Debug, Deserialize)]
struct _AMQPProperty {
    #[serde(rename="type")]
    amqp_type: _AMQPType,
    name:      ShortString,
}

impl _AMQPProperty {
    fn to_specs(&self) -> AMQPProperty {
        AMQPProperty {
            amqp_type: self.amqp_type.to_specs(),
            name:      self.name.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use decoders::RawImage;
use imageops::{OpBuffer,ImageOp,Pipeline};

#[derive(Copy, Clone, Debug)]
pub struct OpLevel {
}

impl OpLevel {
  pub fn new(_img: &RawImage) -> OpLevel {
    OpLevel{}
  }
}

impl ImageOp for OpLevel {
  fn name(&self) -> &str {"level"}
  fn run(&self, pipeline: &Pipeline, buf: &OpBuffer) -> OpBuffer {
    level_and_balance(pipeline.image, buf)
  }
}

pub fn level_and_balance(img: &RawImage, buf: &OpBuffer) -> OpBuffer {
  let mut buf = buf.clone();

  // Calculate the blacklevels
  let mins = img.blacklevels.iter().map(|&x| x as f32).collect::<Vec<f32>>();
  let ranges = img.whitelevels.iter().enumerate().map(|(i, &x)| (x as f32) - mins[i]).collect::<Vec<f32>>();

  let coeffs = if img.is_monochrome() {
    [1.0, 1.0, 1.0, 1.0]
  } else if !img.wb_coeffs[0].is_normal() ||
            !img.wb_coeffs[1].is_normal() ||
            !img.wb_coeffs[2].is_normal() {
    img.neutralwb()
  } else {
    img.wb_coeffs
  };

  // Set green multiplier as 1.0
  let unity: f32 = coeffs[1];
  let mul = coeffs.iter().map(|x| if !x.is_normal() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

  buf.mutate_lines(&(|line: &mut [f32], _| {
    for pix in line.chunks_mut(4) {
      pix[0] = (((pix[0] - mins[0]) / ranges[0]) * mul[0]).min(1.0);
      pix[1] = (((pix[1] - mins[1]) / ranges[1]) * mul[1]).min(1.0);
      pix[2] = (((pix[2] - mins[2]) / ranges[2]) * mul[2]).min(1.0);
      pix[3] = (((pix[3] - mins[3]) / ranges[3]) * mul[3]).min(1.0);
    }
  }));

  buf
}
<commit_msg>level: move settings to struct<commit_after>use decoders::RawImage;
use imageops::{OpBuffer,ImageOp,Pipeline};

#[derive(Copy, Clone, Debug)]
pub struct OpLevel {
  blacklevels: [f32;4],
  whitelevels: [f32;4],
  wb_coeffs: [f32;4],
}

impl OpLevel {
  pub fn new(img: &RawImage) -> OpLevel {
    let coeffs = if img.is_monochrome() {
      [1.0, 1.0, 1.0, 1.0]
    } else if !img.wb_coeffs[0].is_normal() ||
              !img.wb_coeffs[1].is_normal() ||
              !img.wb_coeffs[2].is_normal() {
      img.neutralwb()
    } else {
      img.wb_coeffs
    };

    OpLevel{
      blacklevels: [
        img.blacklevels[0] as f32,
        img.blacklevels[1] as f32,
        img.blacklevels[2] as f32,
        img.blacklevels[3] as f32
      ],
      whitelevels: [
        img.whitelevels[0] as f32,
        img.whitelevels[1] as f32,
        img.whitelevels[2] as f32,
        img.whitelevels[3] as f32
      ],
      wb_coeffs: coeffs,
    }
  }
}

impl ImageOp for OpLevel {
  fn name(&self) -> &str {"level"}
  fn run(&self, _pipeline: &Pipeline, buf: &OpBuffer) -> OpBuffer {
    let mut buf = buf.clone();

    // Calculate the levels
    let mins = self.blacklevels;
    let ranges = self.whitelevels.iter().enumerate().map(|(i, &x)| x - mins[i]).collect::<Vec<f32>>();

    // Set green multiplier as 1.0
    let unity: f32 = self.wb_coeffs[1];
    let mul = self.wb_coeffs.iter().map(|x| if !x.is_normal() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

    buf.mutate_lines(&(|line: &mut [f32], _| {
      for pix in line.chunks_mut(4) {
        pix[0] = (((pix[0] - mins[0]) / ranges[0]) * mul[0]).min(1.0);
        pix[1] = (((pix[1] - mins[1]) / ranges[1]) * mul[1]).min(1.0);
        pix[2] = (((pix[2] - mins[2]) / ranges[2]) * mul[2]).min(1.0);
        pix[3] = (((pix[3] - mins[3]) / ranges[3]) * mul[3]).min(1.0);
      }
    }));

    buf
  }
}
<|endoftext|>