<commit_before>use std::u32;
use std::mem;
use std::cmp;
use std::hash;
use std::borrow::Borrow;
use std::cmp::Ordering;
use iter;

pub type NodeIndex = u32;
const NULL_NODE: NodeIndex = u32::MAX;

#[derive(Debug, Clone)]
pub struct Node<K, V> {
    pub lft: NodeIndex,
    pub rgt: NodeIndex,
    pub key: K,
    pub val: V,
}
impl<K, V> Node<K, V> {
    pub fn rgt(&self) -> Option<NodeIndex> {
        if self.rgt == NULL_NODE {
            None
        } else {
            Some(self.rgt)
        }
    }
    pub fn lft(&self) -> Option<NodeIndex> {
        if self.lft == NULL_NODE {
            None
        } else {
            Some(self.lft)
        }
    }
}
impl<K, V> Node<K, V>
    where K: Ord
{
    fn new(key: K, value: V, lft: NodeIndex, rgt: NodeIndex) -> Self {
        Node {
            key: key,
            val: value,
            lft: lft,
            rgt: rgt,
        }
    }
    fn pop(nodes: &mut Vec<Self>, root: NodeIndex) -> ((K, V), NodeIndex) {
        let children = {
            let n = &mut nodes[root as usize];
            (mem::replace(&mut n.lft, NULL_NODE), mem::replace(&mut n.rgt, NULL_NODE))
        };
        let new_root = match children {
            (NULL_NODE, NULL_NODE) => NULL_NODE,
            (lft, NULL_NODE) => lft,
            (NULL_NODE, rgt) => rgt,
            (lft, mut rgt) => {
                let lft_rgt = mem::replace(&mut nodes[lft as usize].rgt, NULL_NODE);
                if lft_rgt != NULL_NODE {
                    rgt = Node::splay_lftmost(nodes, rgt);
                    nodes[rgt as usize].lft = lft_rgt;
                }
                nodes[lft as usize].rgt = rgt;
                lft
            }
        };
        if nodes.len() as NodeIndex - 1 != root {
            let key = &nodes[nodes.len() - 1].key as *const _;
            let _ = Node::splay(nodes, new_root, unsafe { &*key });
            let last = nodes.pop().unwrap();
            let old = mem::replace(&mut nodes[root as usize], last);
            ((old.key, old.val), root)
        } else {
            (nodes.pop().map(|n| (n.key, n.val)).unwrap(), new_root)
        }
    }
    fn splay<Q: ?Sized>(nodes: &mut [Self], root: NodeIndex, key: &Q) -> (NodeIndex, Ordering)
        where K: Borrow<Q>,
              Q: Ord
    {
        Node::splay_by(nodes, root, |k| key.cmp(k.borrow()))
    }
    fn splay_lftmost(nodes: &mut [Self], root: NodeIndex) -> NodeIndex {
        Node::splay_by(nodes, root, |_| Ordering::Less).0
    }
    fn splay_by<F>(nodes: &mut [Self], root: NodeIndex, cmp: F) -> (NodeIndex, Ordering)
        where F: Fn(&K) -> Ordering
    {
        assert!(root != NULL_NODE);
        let mut node = root;
        let mut lft_root = NULL_NODE;
        let mut rgt_root = NULL_NODE;
        let mut order = cmp(nodes[node as usize].key.borrow());
        {
            let mut lft_rgtmost = &mut lft_root;
            let mut rgt_lftmost = &mut rgt_root;
            loop {
                match order {
                    Ordering::Less if nodes[node as usize].lft != NULL_NODE => {
                        // zig
                        let mut child = mem::replace(&mut nodes[node as usize].lft, NULL_NODE);

                        order = cmp(nodes[child as usize].key.borrow());
                        if let Ordering::Less = order {
                            if nodes[child as usize].lft != NULL_NODE {
                                // zig-zig
                                let grand_child = mem::replace(&mut nodes[child as usize].lft,
                                                               NULL_NODE);
                                nodes[node as usize].lft = nodes[child as usize].rgt;
                                nodes[child as usize].rgt = node;
                                node = child;
                                child = grand_child;
                                order = cmp(nodes[child as usize].key.borrow());
                            }
                        }
                        *rgt_lftmost = node;
                        rgt_lftmost = unsafe { &mut *(&mut nodes[node as usize].lft as *mut _) };

                        node = child;
                    }
                    Ordering::Greater if nodes[node as usize].rgt != NULL_NODE => {
                        // zag
                        let mut child = mem::replace(&mut nodes[node as usize].rgt, NULL_NODE);
                        order = cmp(nodes[child as usize].key.borrow());
                        if let Ordering::Greater = order {
                            if nodes[child as usize].rgt != NULL_NODE {
                                // zag-zag
                                let grand_child = mem::replace(&mut nodes[child as usize].rgt,
                                                               NULL_NODE);
                                nodes[node as usize].rgt = nodes[child as usize].lft;
                                nodes[child as usize].lft = node;
                                node = child;
                                child = grand_child;
                                order = cmp(nodes[child as usize].key.borrow());
                            }
                        }
                        *lft_rgtmost = node;
                        lft_rgtmost = unsafe { &mut *(&mut nodes[node as usize].rgt as *mut _) };

                        node = child;
                    }
                    _ => break,
                }
            }
            *lft_rgtmost = mem::replace(&mut nodes[node as usize].lft, NULL_NODE);
            *rgt_lftmost = mem::replace(&mut nodes[node as usize].rgt, NULL_NODE);
        }
        nodes[node as usize].lft = lft_root;
        nodes[node as usize].rgt = rgt_root;

        (node, order)
    }
}

#[derive(Debug, Clone)]
pub struct Tree<K, V> {
    root: NodeIndex,
    nodes: Vec<Node<K, V>>,
}
impl<K, V> Tree<K, V>
    where K: Ord
{
    pub fn new() -> Self {
        Tree {
            root: 0,
            nodes: Vec::new(),
        }
    }
    pub fn contains_key<Q: ?Sized>(&mut self, key: &Q) -> bool
        where K: Borrow<Q>,
              Q: Ord
    {
        if self.nodes.is_empty() {
            false
        } else {
            let (root, order) = Node::splay(&mut self.nodes, self.root, key);
            self.root = root;
            order == Ordering::Equal
        }
    }
    pub fn find_lower_bound<Q: ?Sized>(&mut self, key: &Q) -> Option<&K>
        where K: Borrow<Q>,
              Q: Ord
    {
        if self.nodes.is_empty() {
            None
        } else {
            let (root, order) = Node::splay(&mut self.nodes, self.root, key);
            self.root = root;
            if let Ordering::Greater = order {
                let mut root_rgt = self.nodes[self.root as usize].rgt;
                if root_rgt != NULL_NODE {
                    root_rgt = Node::splay_lftmost(&mut self.nodes, root_rgt);
                    self.nodes[self.root as usize].rgt = root_rgt;
                    Some(&self.nodes[root_rgt as usize].key)
                } else {
                    None
                }
            } else {
                Some(&self.nodes[self.root as usize].key)
            }
        }
    }
    pub fn find_upper_bound<Q: ?Sized>(&mut self, key: &Q) -> Option<&K>
        where K: Borrow<Q>,
              Q: Ord
    {
        if self.nodes.is_empty() {
            None
        } else {
            let (root, order) = Node::splay(&mut self.nodes, self.root, key);
            self.root = root;
            if let Ordering::Less = order {
                Some(&self.nodes[self.root as usize].key)
            } else {
                let mut root_rgt = self.nodes[self.root as usize].rgt;
                if root_rgt != NULL_NODE {
                    root_rgt = Node::splay_lftmost(&mut self.nodes, root_rgt);
                    self.nodes[self.root as usize].rgt = root_rgt;
                    Some(&self.nodes[root_rgt as usize].key)
                } else {
                    None
                }
            }
        }
    }
    pub fn get<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
        where K: Borrow<Q>,
              Q: Ord
    {
        if self.contains_key(key) {
            Some(&mut self.nodes[self.root as usize].val)
        } else {
            None
        }
    }
    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        let (new_root, old_value) = if self.nodes.is_empty() {
            self.nodes.push(Node::new(key, value, NULL_NODE, NULL_NODE));
            (0, None)
        } else {
            let (root, order) = Node::splay(&mut self.nodes, self.root, &key);
            match order {
                Ordering::Equal => {
                    let old = mem::replace(&mut self.nodes[root as usize].val, value);
                    (root, Some(old))
                }
                Ordering::Less => {
                    let lft = mem::replace(&mut self.nodes[root as usize].lft, NULL_NODE);
                    self.nodes.push(Node::new(key, value, lft, root));
                    (self.nodes.len() as NodeIndex - 1, None)
                }
                Ordering::Greater => {
                    let rgt = mem::replace(&mut self.nodes[root as usize].rgt, NULL_NODE);
                    self.nodes.push(Node::new(key, value, root, rgt));
                    (self.nodes.len() as NodeIndex - 1, None)
                }
            }

        };
        assert!(new_root != NULL_NODE);

        self.root = new_root;
        old_value
    }
    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
        where K: Borrow<Q>,
              Q: Ord
    {
        if self.contains_key(key) {
            self.pop_root().map(|(_, v)| v)
        } else {
            None
        }
    }
    pub fn pop_last(&mut self) -> Option<(K, V)> {
        if self.nodes.is_empty() {
            None
        } else {
            let key = &self.nodes.last().unwrap().key as *const _;
            self.contains_key(unsafe { &*key });
            self.pop_root()
        }
    }
    pub fn pop_root(&mut self) -> Option<(K, V)> {
        if self.nodes.is_empty() {
            None
        } else {
            let (e, root) = Node::pop(&mut self.nodes, self.root);
            self.root = root;
            Some(e)
        }
    }
    pub fn get_lftmost(&mut self) -> Option<(&K, &V)> {
        if self.nodes.is_empty() {
            None
        } else {
            self.root = Node::splay_lftmost(&mut self.nodes, self.root);
            let n = &self.nodes[self.root as usize];
            Some((&n.key, &n.val))
        }
    }
    pub fn take_lftmost(&mut self) -> Option<(K, V)> {
        if self.nodes.is_empty() {
            None
        } else {
            self.root = Node::splay_lftmost(&mut self.nodes, self.root);
            self.pop_root()
        }
    }
}
impl<K, V> Tree<K, V> {
    pub fn iter(&self) -> iter::Iter<K, V> {
        iter::Iter::new(self)
    }
    pub fn root(&self) -> Option<NodeIndex> {
        if self.nodes.is_empty() {
            None
        } else {
            Some(self.root)
        }
    }
    pub fn node_ref(&self, i: NodeIndex) -> &Node<K, V> {
        &self.nodes[i as usize]
    }
    pub fn node_mut(&mut self, i: NodeIndex) -> &mut Node<K, V> {
        &mut self.nodes[i as usize]
    }
    pub fn root_ref(&self) -> Option<&Node<K, V>> {
        if self.nodes.is_empty() {
            None
        } else {
            Some(&self.nodes[self.root as usize])
        }
    }
    pub fn root_mut(&mut self) -> Option<&mut Node<K, V>> {
        if self.nodes.is_empty() {
            None
        } else {
            Some(&mut self.nodes[self.root as usize])
        }
    }
    pub fn len(&self) -> usize {
        self.nodes.len()
    }
    pub fn capacity(&self) -> usize {
        self.nodes.capacity()
    }
}
impl<K, V> hash::Hash for Tree<K, V>
    where K: hash::Hash,
          V: hash::Hash
{
    fn hash<H>(&self, state: &mut H)
        where H: hash::Hasher
    {
        for (k, v) in self.iter() {
            k.hash(state);
            v.hash(state);
        }
    }
}
impl<K, V> PartialEq for Tree<K, V>
    where K: PartialEq,
          V: PartialEq
{
    fn eq(&self, other: &Self) -> bool {
        self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.eq(&b))
    }
}
impl<K, V> Eq for Tree<K, V>
    where K: Eq,
          V: Eq
{
}
impl<K, V> PartialOrd for Tree<K, V>
    where K: PartialOrd,
          V: PartialOrd
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        let mut i0 = self.iter();
        let mut i1 = other.iter();
        loop {
            match (i0.next(), i1.next()) {
                (None, None) => return Some(cmp::Ordering::Equal),
                (None, _) => return Some(cmp::Ordering::Less),
                (_, None) => return Some(cmp::Ordering::Greater),
                (Some(e0), Some(e1)) => {
                    match e0.partial_cmp(&e1) {
                        Some(cmp::Ordering::Equal) => {}
                        not_equal => return not_equal,
                    }
                }
            }
        }
    }
}
impl<K, V> Ord for Tree<K, V>
    where K: Ord,
          V: Ord
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        let mut i0 = self.iter();
        let mut i1 = other.iter();
        loop {
            match (i0.next(), i1.next()) {
                (None, None) => return cmp::Ordering::Equal,
                (None, _) => return cmp::Ordering::Less,
                (_, None) => return cmp::Ordering::Greater,
                (Some(e0), Some(e1)) => {
                    match e0.cmp(&e1) {
                        cmp::Ordering::Equal => {}
                        not_equal => return not_equal,
                    }
                }
            }
        }
    }
}
<commit_msg>Add internal OptionLike trait<commit_after>use std::u32;
use std::mem;
use std::cmp;
use std::hash;
use std::borrow::Borrow;
use std::cmp::Ordering;
use iter;

pub type NodeIndex = u32;
const NULL_NODE: NodeIndex = u32::MAX;

#[derive(Debug, Clone)]
pub struct Node<K, V> {
    pub lft: NodeIndex,
    pub rgt: NodeIndex,
    pub key: K,
    pub val: V,
}
impl<K, V> Node<K, V> {
    pub fn rgt(&self) -> Option<NodeIndex> {
        (self.rgt != NULL_NODE).as_option().map(|_| self.rgt)
    }
    pub fn lft(&self) -> Option<NodeIndex> {
        (self.lft != NULL_NODE).as_option().map(|_| self.lft)
    }
}
impl<K, V> Node<K, V>
    where K: Ord
{
    fn new(key: K, value: V, lft: NodeIndex, rgt: NodeIndex) -> Self {
        Node {
            key: key,
            val: value,
            lft: lft,
            rgt: rgt,
        }
    }
    fn pop(nodes: &mut Vec<Self>, root: NodeIndex) -> ((K, V), NodeIndex) {
        let children = {
            let n = &mut nodes[root as usize];
            (mem::replace(&mut n.lft, NULL_NODE), mem::replace(&mut n.rgt, NULL_NODE))
        };
        let new_root = match children {
            (NULL_NODE, NULL_NODE) => NULL_NODE,
            (lft, NULL_NODE) => lft,
            (NULL_NODE, rgt) => rgt,
            (lft, mut rgt) => {
                let lft_rgt = mem::replace(&mut nodes[lft as usize].rgt, NULL_NODE);
                if lft_rgt != NULL_NODE {
                    rgt = Node::splay_lftmost(nodes, rgt);
                    nodes[rgt as usize].lft = lft_rgt;
                }
                nodes[lft as usize].rgt = rgt;
                lft
            }
        };
        if nodes.len() as NodeIndex - 1 != root {
            let key = &nodes[nodes.len() - 1].key as *const _;
            let _ = Node::splay(nodes, new_root, unsafe { &*key });
            let last = nodes.pop().unwrap();
            let old = mem::replace(&mut nodes[root as usize], last);
            ((old.key, old.val), root)
        } else {
            (nodes.pop().map(|n| (n.key, n.val)).unwrap(), new_root)
        }
    }
    fn splay<Q: ?Sized>(nodes: &mut [Self], root: NodeIndex, key: &Q) -> (NodeIndex, Ordering)
        where K: Borrow<Q>,
              Q: Ord
    {
        Node::splay_by(nodes, root, |k| key.cmp(k.borrow()))
    }
    fn splay_lftmost(nodes: &mut [Self], root: NodeIndex) -> NodeIndex {
        Node::splay_by(nodes, root, |_| Ordering::Less).0
    }
    fn splay_by<F>(nodes: &mut [Self], root: NodeIndex, cmp: F) -> (NodeIndex, Ordering)
        where F: Fn(&K) -> Ordering
    {
        assert!(root != NULL_NODE);
        let mut node = root;
        let mut lft_root = NULL_NODE;
        let mut rgt_root = NULL_NODE;
        let mut order = cmp(nodes[node as usize].key.borrow());
        {
            let mut lft_rgtmost = &mut lft_root;
            let mut rgt_lftmost = &mut rgt_root;
            loop {
                match order {
                    Ordering::Less if nodes[node as usize].lft != NULL_NODE => {
                        // zig
                        let mut child = mem::replace(&mut nodes[node as usize].lft, NULL_NODE);

                        order = cmp(nodes[child as usize].key.borrow());
                        if let Ordering::Less = order {
                            if nodes[child as usize].lft != NULL_NODE {
                                // zig-zig
                                let grand_child = mem::replace(&mut nodes[child as usize].lft,
                                                               NULL_NODE);
                                nodes[node as usize].lft = nodes[child as usize].rgt;
                                nodes[child as usize].rgt = node;
                                node = child;
                                child = grand_child;
                                order = cmp(nodes[child as usize].key.borrow());
                            }
                        }
                        *rgt_lftmost = node;
                        rgt_lftmost = unsafe { &mut *(&mut nodes[node as usize].lft as *mut _) };

                        node = child;
                    }
                    Ordering::Greater if nodes[node as usize].rgt != NULL_NODE => {
                        // zag
                        let mut child = mem::replace(&mut nodes[node as usize].rgt, NULL_NODE);
                        order = cmp(nodes[child as usize].key.borrow());
                        if let Ordering::Greater = order {
                            if nodes[child as usize].rgt != NULL_NODE {
                                // zag-zag
                                let grand_child = mem::replace(&mut nodes[child as usize].rgt,
                                                               NULL_NODE);
                                nodes[node as usize].rgt = nodes[child as usize].lft;
                                nodes[child as usize].lft = node;
                                node = child;
                                child = grand_child;
                                order = cmp(nodes[child as usize].key.borrow());
                            }
                        }
                        *lft_rgtmost = node;
                        lft_rgtmost = unsafe { &mut *(&mut nodes[node as usize].rgt as *mut _) };

                        node = child;
                    }
                    _ => break,
                }
            }
            *lft_rgtmost = mem::replace(&mut nodes[node as usize].lft, NULL_NODE);
            *rgt_lftmost = mem::replace(&mut nodes[node as usize].rgt, NULL_NODE);
        }
        nodes[node as usize].lft = lft_root;
        nodes[node as usize].rgt = rgt_root;

        (node, order)
    }
}

#[derive(Debug, Clone)]
pub struct Tree<K, V> {
    root: NodeIndex,
    nodes: Vec<Node<K, V>>,
}
impl<K, V> Tree<K, V>
    where K: Ord
{
    pub fn new() -> Self {
        Tree {
            root: 0,
            nodes: Vec::new(),
        }
    }
    pub fn contains_key<Q: ?Sized>(&mut self, key: &Q) -> bool
        where K: Borrow<Q>,
              Q: Ord
    {
        if self.nodes.is_empty() {
            false
        } else {
            let (root, order) = Node::splay(&mut self.nodes, self.root, key);
            self.root = root;
            order == Ordering::Equal
        }
    }
    pub fn find_lower_bound<Q: ?Sized>(&mut self, key: &Q) -> Option<&K>
        where K: Borrow<Q>,
              Q: Ord
    {
        (!self.nodes.is_empty()).as_option().and_then(move |_| {
            let (root, order) = Node::splay(&mut self.nodes, self.root, key);
            self.root = root;
            if let Ordering::Greater = order {
                let mut root_rgt = self.nodes[self.root as usize].rgt;
                if root_rgt != NULL_NODE {
                    root_rgt = Node::splay_lftmost(&mut self.nodes, root_rgt);
                    self.nodes[self.root as usize].rgt = root_rgt;
                    Some(&self.nodes[root_rgt as usize].key)
                } else {
                    None
                }
            } else {
                Some(&self.nodes[self.root as usize].key)
            }
        })
    }
    pub fn find_upper_bound<Q: ?Sized>(&mut self, key: &Q) -> Option<&K>
        where K: Borrow<Q>,
              Q: Ord
    {
        (!self.nodes.is_empty()).as_option().and_then(move |_| {
            let (root, order) = Node::splay(&mut self.nodes, self.root, key);
            self.root = root;
            if let Ordering::Less = order {
                Some(&self.nodes[self.root as usize].key)
            } else {
                let mut root_rgt = self.nodes[self.root as usize].rgt;
                if root_rgt != NULL_NODE {
                    root_rgt = Node::splay_lftmost(&mut self.nodes, root_rgt);
                    self.nodes[self.root as usize].rgt = root_rgt;
                    Some(&self.nodes[root_rgt as usize].key)
                } else {
                    None
                }
            }
        })
    }
    pub fn get<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
        where K: Borrow<Q>,
              Q: Ord
    {
        self.contains_key(key).as_option().map(move |_| &mut self.nodes[self.root as usize].val)
    }
    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        let (new_root, old_value) = if self.nodes.is_empty() {
            self.nodes.push(Node::new(key, value, NULL_NODE, NULL_NODE));
            (0, None)
        } else {
            let (root, order) = Node::splay(&mut self.nodes, self.root, &key);
            match order {
                Ordering::Equal => {
                    let old = mem::replace(&mut self.nodes[root as usize].val, value);
                    (root, Some(old))
                }
                Ordering::Less => {
                    let lft = mem::replace(&mut self.nodes[root as usize].lft, NULL_NODE);
                    self.nodes.push(Node::new(key, value, lft, root));
                    (self.nodes.len() as NodeIndex - 1, None)
                }
                Ordering::Greater => {
                    let rgt = mem::replace(&mut self.nodes[root as usize].rgt, NULL_NODE);
                    self.nodes.push(Node::new(key, value, root, rgt));
                    (self.nodes.len() as NodeIndex - 1, None)
                }
            }

        };
        assert!(new_root != NULL_NODE);

        self.root = new_root;
        old_value
    }
    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
        where K: Borrow<Q>,
              Q: Ord
    {
        self.contains_key(key).as_option().map(|_| self.non_empty_pop_root().1)
    }
    pub fn pop_last(&mut self) -> Option<(K, V)> {
        (!self.nodes.is_empty()).as_option().map(|_| {
            let key = &self.nodes.last().unwrap().key as *const _;
            self.contains_key(unsafe { &*key });
            self.non_empty_pop_root()
        })
    }
    pub fn pop_root(&mut self) -> Option<(K, V)> {
        (!self.nodes.is_empty()).as_option().map(|_| self.non_empty_pop_root())
    }
    pub fn get_lftmost(&mut self) -> Option<(&K, &V)> {
        (!self.nodes.is_empty()).as_option().map(move |_| {
            self.root = Node::splay_lftmost(&mut self.nodes, self.root);
            let n = &self.nodes[self.root as usize];
            (&n.key, &n.val)
        })
    }
    pub fn take_lftmost(&mut self) -> Option<(K, V)> {
        (!self.nodes.is_empty()).as_option().map(|_| {
            self.root = Node::splay_lftmost(&mut self.nodes, self.root);
            self.non_empty_pop_root()
        })
    }
    fn non_empty_pop_root(&mut self) -> (K, V) {
        let (e, root) = Node::pop(&mut self.nodes, self.root);
        self.root = root;
        e
    }
}
impl<K, V> Tree<K, V> {
    pub fn iter(&self) -> iter::Iter<K, V> {
        iter::Iter::new(self)
    }
    pub fn root(&self) -> Option<NodeIndex> {
        (!self.nodes.is_empty()).as_option().map(|_| self.root)
    }
    pub fn root_ref(&self) -> Option<&Node<K, V>> {
        (!self.nodes.is_empty()).as_option().map(|_| &self.nodes[self.root as usize])
    }
    pub fn root_mut(&mut self) -> Option<&mut Node<K, V>> {
        (!self.nodes.is_empty()).as_option().map(move |_| &mut self.nodes[self.root as usize])
    }
    pub fn node_ref(&self, i: NodeIndex) -> &Node<K, V> {
        &self.nodes[i as usize]
    }
    pub fn node_mut(&mut self, i: NodeIndex) -> &mut Node<K, V> {
        &mut self.nodes[i as usize]
    }
    pub fn len(&self) -> usize {
        self.nodes.len()
    }
    pub fn capacity(&self) -> usize {
        self.nodes.capacity()
    }
}
impl<K, V> hash::Hash for Tree<K, V>
    where K: hash::Hash,
          V: hash::Hash
{
    fn hash<H>(&self, state: &mut H)
        where H: hash::Hasher
    {
        for (k, v) in self.iter() {
            k.hash(state);
            v.hash(state);
        }
    }
}
impl<K, V> PartialEq for Tree<K, V>
    where K: PartialEq,
          V: PartialEq
{
    fn eq(&self, other: &Self) -> bool {
        self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.eq(&b))
    }
}
impl<K, V> Eq for Tree<K, V>
    where K: Eq,
          V: Eq
{
}
impl<K, V> PartialOrd for Tree<K, V>
    where K: PartialOrd,
          V: PartialOrd
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        let mut i0 = self.iter();
        let mut i1 = other.iter();
        loop {
            match (i0.next(), i1.next()) {
                (None, None) => return Some(cmp::Ordering::Equal),
                (None, _) => return Some(cmp::Ordering::Less),
                (_, None) => return Some(cmp::Ordering::Greater),
                (Some(e0), Some(e1)) => {
                    match e0.partial_cmp(&e1) {
                        Some(cmp::Ordering::Equal) => {}
                        not_equal => return not_equal,
                    }
                }
            }
        }
    }
}
impl<K, V> Ord for Tree<K, V>
    where K: Ord,
          V: Ord
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        let mut i0 = self.iter();
        let mut i1 = other.iter();
        loop {
            match (i0.next(), i1.next()) {
                (None, None) => return cmp::Ordering::Equal,
                (None, _) => return cmp::Ordering::Less,
                (_, None) => return cmp::Ordering::Greater,
                (Some(e0), Some(e1)) => {
                    match e0.cmp(&e1) {
                        cmp::Ordering::Equal => {}
                        not_equal => return not_equal,
                    }
                }
            }
        }
    }
}

trait OptionLike {
    fn as_option(&self) -> Option<&Self>;
}
impl OptionLike for bool {
    fn as_option(&self) -> Option<&Self> {
        if *self {
            Some(self)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! Main evaluator loop and setting up the initial stack frame.

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc::hir::def_id::DefId;
use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking and Stacked Borrows are enabled.
    pub validate: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
}

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate),
        MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars);

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;

    if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
        throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx
        .memory
        .create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // For Windows, construct a command string with all the aguments (before we take apart `config.args`).
        let mut cmd = String::new();
        for arg in config.args.iter() {
            if !cmd.is_empty() {
                cmd.push(' ');
            }
            cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
        }
        // Don't forget `0` terminator.
        cmd.push(std::char::from_u32(0).unwrap());
        // Collect the pointers to the individual strings.
        let mut argvs = Vec::<Pointer<Tag>>::new();
        for arg in config.args {
            // Add `0` terminator.
            let mut arg = arg.into_bytes();
            arg.push(0);
            argvs.push(
                ecx.memory
                    .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Env.into()),
            );
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout = ecx.layout_of(
            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64),
        )?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(arg, place.into())?;
        }
        ecx.memory
            .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the argument.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place = ecx.allocate(
                ecx.layout_of(tcx.types.isize)?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(
        ecx.layout_of(tcx.types.isize)?,
        MiriMemoryKind::Env.into(),
    );
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc.into(), argv.into()],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        ecx.run()?;
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            // Disable the leak test on some platforms where we do not
            // correctly implement TLS destructors.
            let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
            let ignore_leaks = target_os == "windows" || target_os == "macos";
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            return Some(return_code)
        }
        Err(mut e) => {
            // Special treatment for some error kinds
            let msg = match e.kind {
                InterpError::MachineStop(ref info) => {
                    let info = info.downcast_ref::<TerminationInfo>()
                        .expect("invalid MachineStop payload");
                    match info {
                        TerminationInfo::Exit(code) => return Some(*code),
                        TerminationInfo::Abort =>
                            format!("the evaluated program aborted execution")
                    }
                }
                err_unsup!(NoMirFor(..)) =>
                    format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
                InterpError::InvalidProgram(_) =>
                    bug!("This error should be impossible in Miri: {}", e),
                _ => e.to_string()
            };
            e.print_backtrace();
            if let Some(frame) = ecx.stack().last() {
                let span = frame.current_source_info().unwrap().span;

                let msg = format!("Miri evaluation error: {}", msg);
                let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
                let frames = ecx.generate_stacktrace(None);
                err.span_label(span, msg);
                // We iterate with indices because we need to look at the next frame (the caller).
                for idx in 0..frames.len() {
                    let frame_info = &frames[idx];
                    let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
                        caller_info.instance.def_id().is_local()
                    });
                    if call_site_is_local {
                        err.span_note(frame_info.call_site, &frame_info.to_string());
                    } else {
                        err.note(&frame_info.to_string());
                    }
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&msg);
            }

            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:?}", frame.return_place.map(|p| *p));
                for (i, local) in frame.locals.iter().enumerate() {
                    trace!("    local {}: {:?}", i, local.value);
                }
            }
            // Let the reported error determine the return code.
            return None;
        }
    }
}
<commit_msg>use write_os_str_to_c_string for unix arg passing<commit_after>//! Main evaluator loop and setting up the initial stack frame.

use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc::hir::def_id::DefId;
use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking and Stacked Borrows are enabled.
    pub validate: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
}

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate),
        MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars);

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;

    if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
        throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx
        .memory
        .create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Scalar<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = arg.len() as u64 + 1;
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into());
            ecx.write_os_str_to_c_string(OsStr::new(arg), arg_place.ptr, size)?;
            argvs.push(arg_place.ptr);
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout = ecx.layout_of(
            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64),
        )?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(arg, place.into())?;
        }
        ecx.memory
            .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place = ecx.allocate(
                ecx.layout_of(tcx.types.isize)?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(
        ecx.layout_of(tcx.types.isize)?,
        MiriMemoryKind::Env.into(),
    );
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc.into(), argv.into()],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        ecx.run()?;
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            // Disable the leak test on some platforms where we do not
            // correctly implement TLS destructors.
            let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
            let ignore_leaks = target_os == "windows" || target_os == "macos";
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            return Some(return_code)
        }
        Err(mut e) => {
            // Special treatment for some error kinds
            let msg = match e.kind {
                InterpError::MachineStop(ref info) => {
                    let info = info.downcast_ref::<TerminationInfo>()
                        .expect("invalid MachineStop payload");
                    match info {
                        TerminationInfo::Exit(code) => return Some(*code),
                        TerminationInfo::Abort =>
                            format!("the evaluated program aborted execution")
                    }
                }
                err_unsup!(NoMirFor(..)) =>
                    format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
                InterpError::InvalidProgram(_) =>
                    bug!("This error should be impossible in Miri: {}", e),
                _ => e.to_string()
            };
            e.print_backtrace();
            if let Some(frame) = ecx.stack().last() {
                let span = frame.current_source_info().unwrap().span;

                let msg = format!("Miri evaluation error: {}", msg);
                let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
                let frames = ecx.generate_stacktrace(None);
                err.span_label(span, msg);
                // We iterate with indices because we need to look at the next frame (the caller).
                for idx in 0..frames.len() {
                    let frame_info = &frames[idx];
                    let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
                        caller_info.instance.def_id().is_local()
                    });
                    if call_site_is_local {
                        err.span_note(frame_info.call_site, &frame_info.to_string());
                    } else {
                        err.note(&frame_info.to_string());
                    }
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&msg);
            }

            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:?}", frame.return_place.map(|p| *p));
                for (i, local) in frame.locals.iter().enumerate() {
                    trace!("    local {}: {:?}", i, local.value);
                }
            }
            // Let the reported error determine the return code.
            return None;
        }
    }
}
<|endoftext|>


<commit_before>
use std::collections::HashMap;
use parse::Env;
use var::Var;
use source::{Src,Next};

/// Creates a possible path from a dot-seperated string
///
/// Returns path, and final symbol
/// Eg: 'items.bag.coins' becomes -> (Some(Vec['items','bag']), 'coins')
pub fn as_path<'a> (lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
    let mut lookups: Vec<&'a str> = lookup.split_terminator('.').collect();
    let item = lookups.pop().unwrap();

    let path;
    if lookups.len() > 0 { path = Some(lookups); }
    else { path = None }

    (path,item)
}

/// Primary Evaluation trait must be implemented to run Evaluator
///
///
pub trait Eval {
    /// Get method to retrieve variable from Rust side
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var>;

    fn as_path<'a> (&self, lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
        as_path(lookup)
    }

    fn get_path (&self, lookup: &str) -> Option<Var> {
        let (path,lookup) = self.as_path(lookup);
        self.get(path, lookup)
    }

    /// Expects var to be written to underlying mem/store in Rust
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var);

    fn set_path (&mut self, lookup: &str, v: Var) {
        let (path,lookup) = self.as_path(&lookup);
        self.set(path,lookup, v);
    }

    /// A custom callable function
    ///
    /// Var represents variable to mutate
    /// Fun is the function name
    /// Vars are any additional arguments
    /// Can optionally return variable back to lichen
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var>;
}

pub struct Evaluator<'e, 'd, D:Eval + 'd> {
    data: &'d mut D,
    env: &'e mut Env,
    next_node: String,
    await_node: String,
}

impl<'e, 'd, D:Eval + 'd> Iterator for Evaluator<'e, 'd, D>
    where D: Eval + 'd {

        type Item = (Vec<Var>, Option<Next>); //here we only return node name as an option to advance
        fn next(&mut self) -> Option<Self::Item> {
            let nn = {
                if !self.await_node.is_empty() {
                    self.await_node.clone()
                }
                else if !self.next_node.is_empty() {
                    self.next_node.clone()
                }
                else { return None }
            };

            self.next_node.clear();
            self.await_node.clear();

            let r = self.run(&nn);
            match r.1 {
                Some(Next::Now(ref node)) => { self.next_node = node.clone(); },
                _ => {},
            }

            Some(r)
        }
    }

impl<'e, 'd, D:Eval> Evaluator<'e, 'd, D> {
    /// Evaluator by default starts on the node named 'root'
    pub fn new (env: &'e mut Env, data: &'d mut D) -> Evaluator<'e, 'd, D> {
        Evaluator {
            env: env, data: data,
            next_node: "root".to_owned(),
            await_node: "".to_owned()
        }
    }

    /// Consumes Evaluator for saving state
    ///
    /// You should save the Env state as well, as it's external to the Evaluator
    pub fn save (self) -> EvaluatorState {
        EvaluatorState {
            next_node: self.next_node,
            await_node: self.await_node,
        }
    }

    /// Advances Evaluator to next node
    ///
    /// If you specify a node name, Evaluator will start there on next step
    pub fn advance (&mut self, node: Option<String>) {
        if let Some(b) = self.env.src.get_mut(&self.await_node) {
            b.await_idx = 0; //reset on advance
        }

        self.await_node.clear();

        if let Some(node) = node {
            self.next_node = node;
        }
    }

    /// Gets the symbol's value, to be formatted into a string
    pub fn get_symbol (&self, s: &str) -> Option<Var> {
        if s.chars().next().unwrap() == '`' {
            let (path,lookup) = as_path(&s[1..]);
            if let Some(path) = path {
                if let Some(ref def) = self.env.def.get(path[0]) {
                    if let Some(v) = def.def.get(&lookup[..]) {
                        return Some(v.clone())
                    }
                }
                else {
                    let v = self.data.get(Some(path),lookup);
                    if v.is_some() { return v }
                }
            }
            else {
                let v = self.data.get_path(&s[1..]);
                if v.is_some() { return v }
            }
        }

        None
    }

    /// Manually run the Evaluator, starting at node specified
    pub fn run (&mut self, node_name: &str)
                -> (Vec<Var>, Option<Next>)
        where D: Eval + 'd
    {
        let mut r = vec!();
        let mut node: Option<Next> = None;

        let mut or_valid = false; //track for OR

        if let Some(b) = self.env.src.get_mut(node_name) {
            let mut state: HashMap<String,bool> = HashMap::new();
            state.insert("this.visited".to_owned(), b.visited);
            b.visited = true;

            let await_idx = b.await_idx;
            b.await_idx = 0;

            for (i,src) in b.src[await_idx..].iter().enumerate() {
                match src {
                    &Src::Next(ref next) => {
                        match next {
                            &Next::Await(ref nn) => {
                                b.await_idx = i+1;
                                node = Some(next.clone());
                                self.await_node = node_name.to_owned();
                                self.next_node = nn.to_owned();
                                break
                            },
                            &Next::Select(_) => {
                                b.await_idx = i+1;
                                node = Some(next.clone());
                                self.await_node = node_name.to_owned();
                                break
                            },
                            _ => {}
                        }
                    },
                    &Src::Or(_,_) => {
                        if !or_valid {
                            continue
                        }
                        else { or_valid = false; }
                    }
                    &Src::If(_,_,_) => { or_valid = true; }
                    _ => { or_valid = false; },
                }

                let (mut vars, next) = src.eval(&mut state, self.data, &mut self.env.def);

                // reset if if was successful
                if (vars.len() > 0) || next.is_some() { or_valid = false; }

                for n in vars.drain(..) {
                    match n {
                        Var::Sym(s) => {
                            if let Some(val) = self.env.def.get_path(&s) {
                                r.push(val);
                            }
                            else if let Some(val) = self.data.get_path(&s) {
                                r.push(val);
                            }
                            // otherwise we silently fail
                        },
                        _ => { r.push(n); }
                    }
                }

                if let Some(next) = next {
                    match next {
                        Next::Await(ref nn) => {
                            b.await_idx = i+1;
                            self.await_node = node_name.to_owned();
                            self.next_node = nn.to_owned();
                        },
                        Next::Select(_) => {
                            b.await_idx = i+1;
                            self.await_node = node_name.to_owned();
                        },
                        Next::Now(_) => { }
                    }

                    node = Some(next);
                    break;
                }
            }
        }

        for var in r.iter_mut() {
            let mut val = None;
            match var {
                &mut Var::String(ref mut s) => { //format string
                    let mut fs = String::new();
                    let mut started = false;

                    // NOTE: we should move this out to a SYM varkind instead
                    // (parsed earlier)
                    if s.split_terminator(' ').count() == 1 {
                        val = self.get_symbol(&s);
                    }
                    else {
                        for word in s.split_terminator(' ') {
                            if started { fs.push(' '); }

                            if let Some(ref v) = self.get_symbol(&word) {
                                fs.push_str(&v.to_string());
                            }
                            else {
                                fs.push_str(word);
                            }

                            started = true;
                        }
                        *s = fs;
                    }
                },
                _ => {}
            }

            if let Some(val) = val {
                *var = val;
            }
        }

        return (r,node)
    }
}

pub struct EvaluatorState {
    next_node: String,
    await_node: String,
}

impl EvaluatorState {
    pub fn to_eval<'e, 'd, D:Eval + 'd> (self, env: &'e mut Env, data: &'d mut D) -> Evaluator<'e, 'd, D> {
        Evaluator {
            env: env, data: data,
            next_node: self.next_node,
            await_node: self.await_node
        }
    }
}
<commit_msg>convenience functions<commit_after>
use std::collections::HashMap;
use parse::Env;
use var::Var;
use source::{Src,Next};

/// Creates a possible path from a dot-seperated string
///
/// Returns path, and final symbol
/// Eg: 'items.bag.coins' becomes -> (Some(Vec['items','bag']), 'coins')
pub fn as_path<'a> (lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
    let mut lookups: Vec<&'a str> = lookup.split_terminator('.').collect();
    let item = lookups.pop().unwrap();

    let path;
    if lookups.len() > 0 { path = Some(lookups); }
    else { path = None }

    (path,item)
}

/// Primary Evaluation trait must be implemented to run Evaluator
///
///
pub trait Eval {
    /// Get method to retrieve variable from Rust side
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var>;

    fn as_path<'a> (&self, lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
        as_path(lookup)
    }

    fn get_path (&self, lookup: &str) -> Option<Var> {
        let (path,lookup) = self.as_path(lookup);
        self.get(path, lookup)
    }

    /// Expects var to be written to underlying mem/store in Rust
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var);

    fn set_path (&mut self, lookup: &str, v: Var) {
        let (path,lookup) = self.as_path(&lookup);
        self.set(path,lookup, v);
    }

    /// A custom callable function
    ///
    /// Var represents variable to mutate
    /// Fun is the function name
    /// Vars are any additional arguments
    /// Can optionally return variable back to lichen
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var>;
}

pub struct Evaluator<'e, 'd, D:Eval + 'd> {
    data: &'d mut D,
    env: &'e mut Env,
    next_node: String,
    await_node: String,
}

impl<'e, 'd, D:Eval + 'd> Iterator for Evaluator<'e, 'd, D>
    where D: Eval + 'd {

        type Item = (Vec<Var>, Option<Next>); //here we only return node name as an option to advance
        fn next(&mut self) -> Option<Self::Item> {
            let nn = {
                if !self.await_node.is_empty() {
                    self.await_node.clone()
                }
                else if !self.next_node.is_empty() {
                    self.next_node.clone()
                }
                else { return None }
            };

            self.next_node.clear();
            self.await_node.clear();

            let r = self.run(&nn);
            match r.1 {
                Some(Next::Now(ref node)) => { self.next_node = node.clone(); },
                _ => {},
            }

            Some(r)
        }
    }

impl<'e, 'd, D:Eval> Evaluator<'e, 'd, D> {
    /// Evaluator by default starts on the node named 'root'
    pub fn new (env: &'e mut Env, data: &'d mut D) -> Evaluator<'e, 'd, D> {
        Evaluator {
            env: env, data: data,
            next_node: "root".to_owned(),
            await_node: "".to_owned()
        }
    }

    /// Consumes Evaluator for saving state
    ///
    /// You should save the Env state as well, as it's external to the Evaluator
    pub fn save (self) -> EvaluatorState {
        EvaluatorState {
            next_node: self.next_node,
            await_node: self.await_node,
        }
    }

    /// Advances Evaluator to next node
    ///
    /// If you specify a node name, Evaluator will start there on next step
    pub fn advance (&mut self, node: Option<String>) {
        if let Some(b) = self.env.src.get_mut(&self.await_node) {
            b.await_idx = 0; //reset on advance
        }

        self.await_node.clear();

        if let Some(node) = node {
            self.next_node = node;
        }
    }

    /// Gets the symbol's value, to be formatted into a string
    pub fn get_symbol (&self, s: &str) -> Option<Var> {
        if s.chars().next().unwrap() == '`' {
            let (path,lookup) = as_path(&s[1..]);
            if let Some(path) = path {
                if let Some(ref def) = self.env.def.get(path[0]) {
                    if let Some(v) = def.def.get(&lookup[..]) {
                        return Some(v.clone())
                    }
                }
                else {
                    let v = self.data.get(Some(path),lookup);
                    if v.is_some() { return v }
                }
            }
            else {
                let v = self.data.get_path(&s[1..]);
                if v.is_some() { return v }
            }
        }

        None
    }

    /// Manually run the Evaluator, starting at node specified
    pub fn run (&mut self, node_name: &str)
                -> (Vec<Var>, Option<Next>)
        where D: Eval + 'd
    {
        let mut r = vec!();
        let mut node: Option<Next> = None;

        let mut or_valid = false; //track for OR

        if let Some(b) = self.env.src.get_mut(node_name) {
            let mut state: HashMap<String,bool> = HashMap::new();
            state.insert("this.visited".to_owned(), b.visited);
            b.visited = true;

            let await_idx = b.await_idx;
            b.await_idx = 0;

            for (i,src) in b.src[await_idx..].iter().enumerate() {
                match src {
                    &Src::Next(ref next) => {
                        match next {
                            &Next::Await(ref nn) => {
                                b.await_idx = i+1;
                                node = Some(next.clone());
                                self.await_node = node_name.to_owned();
                                self.next_node = nn.to_owned();
                                break
                            },
                            &Next::Select(_) => {
                                b.await_idx = i+1;
                                node = Some(next.clone());
                                self.await_node = node_name.to_owned();
                                break
                            },
                            _ => {}
                        }
                    },
                    &Src::Or(_,_) => {
                        if !or_valid {
                            continue
                        }
                        else { or_valid = false; }
                    }
                    &Src::If(_,_,_) => { or_valid = true; }
                    _ => { or_valid = false; },
                }

                let (mut vars, next) = src.eval(&mut state, self.data, &mut self.env.def);

                // reset if if was successful
                if (vars.len() > 0) || next.is_some() { or_valid = false; }

                for n in vars.drain(..) {
                    match n {
                        Var::Sym(s) => {
                            if let Some(val) = self.env.def.get_path(&s) {
                                r.push(val);
                            }
                            else if let Some(val) = self.data.get_path(&s) {
                                r.push(val);
                            }
                            // otherwise we silently fail
                        },
                        _ => { r.push(n); }
                    }
                }

                if let Some(next) = next {
                    match next {
                        Next::Await(ref nn) => {
                            b.await_idx = i+1;
                            self.await_node = node_name.to_owned();
                            self.next_node = nn.to_owned();
                        },
                        Next::Select(_) => {
                            b.await_idx = i+1;
                            self.await_node = node_name.to_owned();
                        },
                        Next::Now(_) => { }
                    }

                    node = Some(next);
                    break;
                }
            }
        }

        for var in r.iter_mut() {
            let mut val = None;
            match var {
                &mut Var::String(ref mut s) => { //format string
                    let mut fs = String::new();
                    let mut started = false;

                    // NOTE: we should move this out to a SYM varkind instead
                    // (parsed earlier)
                    if s.split_terminator(' ').count() == 1 {
                        val = self.get_symbol(&s);
                    }
                    else {
                        for word in s.split_terminator(' ') {
                            if started { fs.push(' '); }

                            if let Some(ref v) = self.get_symbol(&word) {
                                fs.push_str(&v.to_string());
                            }
                            else {
                                fs.push_str(word);
                            }

                            started = true;
                        }
                        *s = fs;
                    }
                },
                _ => {}
            }

            if let Some(val) = val {
                *var = val;
            }
        }

        return (r,node)
    }
}

#[derive(Clone,Debug)]
pub struct EvaluatorState {
    next_node: String,
    await_node: String,
}

impl EvaluatorState {
    pub fn to_eval<'e, 'd, D:Eval + 'd> (self, env: &'e mut Env, data: &'d mut D) -> Evaluator<'e, 'd, D> {
        Evaluator {
            env: env, data: data,
            next_node: self.next_node,
            await_node: self.await_node
        }
    }

    pub fn as_eval<'e, 'd, D:Eval + 'd> (&self, env: &'e mut Env, data: &'d mut D) -> Evaluator<'e, 'd, D> {
        self.clone().to_eval(env,data)
    }
}
<|endoftext|>


<commit_before>extern crate config;
use self::config::types::{Config, ScalarValue, Value};

use std::process::Command;

fn make_command_vec(vec: &Vec<Value>) -> Result<Command, String> {
    if vec.is_empty() {
        return Err(format!("empty execution vector"));
    }

    let mut prog_args = vec![];
    for v in vec {
        match v {
            &Value::Svalue(ref sv) => {
                match sv {
                    &ScalarValue::Str(ref s) => prog_args.push(s),
                    _ => {
                        return Err(format!("non-string program value"));
                    }
                }
            },
            _ => {
                return Err(format!("non-string program value"));
            }
        }
    }

    let (prog, args) = prog_args.split_at(1);
    let mut cmd = Command::new(prog[0]);
    cmd.args(args);

    Ok(cmd)
}

fn make_command_str(string: &String) -> Result<Command, String> {
    if string.is_empty() {
        Err(format!("empty execution string"))
    } else {
        Ok(Command::new(string))
    }
}

pub fn run_config_program(conf: &Config, path: &str) -> Result<(), String> {
    let val = conf.lookup(path);
    if val.is_none() {
        return Ok(());
    }

    let cmd = try!(match val.unwrap() {
        &Value::Array(ref a) => make_command_vec(a),
        &Value::Svalue(ref sv) => {
            match sv {
                &ScalarValue::Str(ref s) => make_command_str(s),
                _ => Err(format!("unsupported type for {}", path))
            }
        },
        _ => Err(format!("unsupported type for {}", path))
    }).output();

    match cmd {
        Ok(output) => {
            if output.status.success() {
                Ok(())
            } else {
                Err(format!("failed to execute process ({:?}):\noutput:\n{}\nerror:{}",
                            output.status.code(),
                            String::from_utf8_lossy(&output.stdout),
                            String::from_utf8_lossy(&output.stderr)))
            }
        },
        _ => Err(format!("failed to execute process"))
    }
}
<commit_msg>exec: handle ~/path expansion<commit_after>extern crate config;
use self::config::types::{Config, ScalarValue, Value};

use std::env::home_dir;
use std::process::Command;

fn expand_home(path: &String) -> String {
    if path.starts_with("~/") {
        match home_dir() {
            Some(home) => format!("{}/{}", home.display(), &path[2..]),
            _ => format!("{}", path)
        }
    } else {
        format!("{}", path)
    }
}

fn make_command_vec(vec: &Vec<Value>) -> Result<Command, String> {
    if vec.is_empty() {
        return Err(format!("empty execution vector"));
    }

    let mut prog_args = vec![];
    for v in vec {
        match v {
            &Value::Svalue(ref sv) => {
                match sv {
                    &ScalarValue::Str(ref s) => prog_args.push(s),
                    _ => {
                        return Err(format!("non-string program value"));
                    }
                }
            },
            _ => {
                return Err(format!("non-string program value"));
            }
        }
    }

    let (prog, args) = prog_args.split_at(1);
    let mut cmd = Command::new(expand_home(prog[0]));
    cmd.args(args);

    Ok(cmd)
}

fn make_command_str(string: &String) -> Result<Command, String> {
    if string.is_empty() {
        Err(format!("empty execution string"))
    } else {
        Ok(Command::new(expand_home(string)))
    }
}

pub fn run_config_program(conf: &Config, path: &str) -> Result<(), String> {
    let val = conf.lookup(path);
    if val.is_none() {
        return Ok(());
    }

    let cmd = try!(match val.unwrap() {
        &Value::Array(ref a) => make_command_vec(a),
        &Value::Svalue(ref sv) => {
            match sv {
                &ScalarValue::Str(ref s) => make_command_str(s),
                _ => Err(format!("unsupported type for {}", path))
            }
        },
        _ => Err(format!("unsupported type for {}", path))
    }).output();

    match cmd {
        Ok(output) => {
            if output.status.success() {
                Ok(())
            } else {
                Err(format!("failed to execute process ({:?}):\noutput:\n{}\nerror:{}",
                            output.status.code(),
                            String::from_utf8_lossy(&output.stdout),
                            String::from_utf8_lossy(&output.stderr)))
            }
        },
        _ => Err(format!("failed to execute process"))
    }
}
<|endoftext|>


<commit_before>#![allow(const_err)] // don't warn about truncating casts

enum Foo {
    Bar = 42,
    Baz,
    Quux = 100,
}

enum Signed {
    Bar = -42,
    Baz,
    Quux = 100,
}

fn foo() -> [u8; 3] {
    let baz = Foo::Baz; // let-expansion changes the MIR significantly
    [Foo::Bar as u8, baz as u8, Foo::Quux as u8]
}

fn signed() -> [i8; 3] {
    let baz = Signed::Baz; // let-expansion changes the MIR significantly
    [Signed::Bar as i8, baz as i8, Signed::Quux as i8]
}

fn unsafe_match() -> bool {
    match unsafe { std::mem::transmute::<u8, Foo>(43) } {
        Foo::Baz => true,
        _ => false,
    }
}

fn main() {
    assert_eq!(foo(), [42, 43, 100]);
    assert_eq!(signed(), [-42, -41, 100]);
    assert!(unsafe_match());
}
<commit_msg>Auto merge of #1139 - RalfJung:fixme, r=RalfJung<commit_after>#![allow(const_err)] // don't warn about truncating casts. FIXME: remove this, the error shouldn't even be shown

enum Foo {
    Bar = 42,
    Baz,
    Quux = 100,
}

enum Signed {
    Bar = -42,
    Baz,
    Quux = 100,
}

fn foo() -> [u8; 3] {
    let baz = Foo::Baz; // let-expansion changes the MIR significantly
    [Foo::Bar as u8, baz as u8, Foo::Quux as u8]
}

fn signed() -> [i8; 3] {
    let baz = Signed::Baz; // let-expansion changes the MIR significantly
    [Signed::Bar as i8, baz as i8, Signed::Quux as i8]
}

fn unsafe_match() -> bool {
    match unsafe { std::mem::transmute::<u8, Foo>(43) } {
        Foo::Baz => true,
        _ => false,
    }
}

fn main() {
    assert_eq!(foo(), [42, 43, 100]);
    assert_eq!(signed(), [-42, -41, 100]);
    assert!(unsafe_match());
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use quote::{ToTokens, Tokens};
use syn::{Data, DataEnum, DeriveInput, Field, Fields};
use utils::{field_idents, get_field_types, named_to_vec, number_idents, unnamed_to_vec};

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
pub fn expand(input: &DeriveInput, trait_name: &str) -> Tokens {
    match input.data {
        Data::Struct(ref data_struct) => match data_struct.fields {
            Fields::Unnamed(ref fields) => tuple_from(input, &unnamed_to_vec(fields)),
            Fields::Named(ref fields) => struct_from(input, &named_to_vec(fields)),
            Fields::Unit => struct_from(input, &[]),
        },
        Data::Enum(ref data_enum) => enum_from(input, data_enum),
        _ => panic!(format!(
            "Only structs and enums can use derive({})",
            trait_name
        )),
    }
}

pub fn from_impl<T: ToTokens>(input: &DeriveInput, fields: &[&Field], body: T) -> Tokens {
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let input_type = &input.ident;
    let original_types = &get_field_types(fields);
    quote!{
        impl#impl_generics ::std::convert::From<(#(#original_types),*)> for
            #input_type#ty_generics #where_clause {

            #[allow(unused_variables)]
            #[inline]
            fn from(original: (#(#original_types),*)) -> #input_type#ty_generics {
                #body
            }
        }
    }
}

fn tuple_from(input: &DeriveInput, fields: &[&Field]) -> Tokens {
    let input_type = &input.ident;
    let body = tuple_body(input_type, fields);
    from_impl(input, fields, body)
}

fn tuple_body<T: ToTokens>(return_type: T, fields: &[&Field]) -> Tokens {
    if fields.len() == 1 {
        quote!(#return_type(original))
    } else {
        let field_names = &number_idents(fields.len());
        quote!(#return_type(#(original.#field_names),*))
    }
}

fn struct_from(input: &DeriveInput, fields: &[&Field]) -> Tokens {
    let input_type = &input.ident;
    let body = struct_body(input_type, fields);
    from_impl(input, fields, body)
}

fn struct_body<T: ToTokens>(return_type: T, fields: &[&Field]) -> Tokens {
    if fields.len() == 1 {
        let field_name = &fields[0].ident;
        quote!(#return_type{#field_name: original})
    } else {
        let argument_field_names = &number_idents(fields.len());
        let field_names = &field_idents(fields);
        quote!(#return_type{#(#field_names: original.#argument_field_names),*})
    }
}

fn enum_from(input: &DeriveInput, data_enum: &DataEnum) -> Tokens {
    let mut type_signature_counts = HashMap::new();
    let input_type = &input.ident;

    for variant in &data_enum.variants {
        match variant.fields {
            Fields::Unnamed(ref fields) => {
                let original_types = unnamed_to_vec(fields).iter().map(|f| &f.ty).collect();
                let counter = type_signature_counts.entry(original_types).or_insert(0);
                *counter += 1;
            }
            Fields::Named(ref fields) => {
                let original_types = named_to_vec(fields).iter().map(|f| &f.ty).collect();
                let counter = type_signature_counts.entry(original_types).or_insert(0);
                *counter += 1;
            }
            Fields::Unit => {
                let counter = type_signature_counts.entry(vec![]).or_insert(0);
                *counter += 1;
            }
        }
    }

    let mut tokens = Tokens::new();

    for variant in &data_enum.variants {
        match variant.fields {
            Fields::Unnamed(ref fields) => {
                let field_vec = &unnamed_to_vec(fields);
                let original_types = get_field_types(field_vec);

                if *type_signature_counts.get(&original_types).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = tuple_body(quote!(#input_type::#variant_ident), field_vec);
                    from_impl(input, field_vec, body).to_tokens(&mut tokens)
                }
            }

            Fields::Named(ref fields) => {
                let field_vec = &named_to_vec(fields);
                let original_types = get_field_types(field_vec);

                if *type_signature_counts.get(&original_types).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = struct_body(quote!(#input_type::#variant_ident), field_vec);
                    from_impl(input, field_vec, body).to_tokens(&mut tokens)
                }
            }
            Fields::Unit => {
                if *type_signature_counts.get(&vec![]).unwrap() == 1 {
                    let variant_ident = &variant.ident;
                    let body = struct_body(quote!(#input_type::#variant_ident), &[]);
                    from_impl(input, &[], body).to_tokens(&mut tokens)
                }
            }
        }
    }
    tokens
}
<commit_msg>Clippy fix<commit_after>use std::collections::HashMap;
use std::ops::Index;

use quote::{ToTokens, Tokens};
use syn::{Data, DataEnum, DeriveInput, Field, Fields};
use utils::{field_idents, get_field_types, named_to_vec, number_idents, unnamed_to_vec};

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
pub fn expand(input: &DeriveInput, trait_name: &str) -> Tokens {
    match input.data {
        Data::Struct(ref data_struct) => match data_struct.fields {
            Fields::Unnamed(ref fields) => tuple_from(input, &unnamed_to_vec(fields)),
            Fields::Named(ref fields) => struct_from(input, &named_to_vec(fields)),
            Fields::Unit => struct_from(input, &[]),
        },
        Data::Enum(ref data_enum) => enum_from(input, data_enum),
        _ => panic!(format!(
            "Only structs and enums can use derive({})",
            trait_name
        )),
    }
}

pub fn from_impl<T: ToTokens>(input: &DeriveInput, fields: &[&Field], body: T) -> Tokens {
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let input_type = &input.ident;
    let original_types = &get_field_types(fields);
    quote!{
        impl#impl_generics ::std::convert::From<(#(#original_types),*)> for
            #input_type#ty_generics #where_clause {

            #[allow(unused_variables)]
            #[inline]
            fn from(original: (#(#original_types),*)) -> #input_type#ty_generics {
                #body
            }
        }
    }
}

fn tuple_from(input: &DeriveInput, fields: &[&Field]) -> Tokens {
    let input_type = &input.ident;
    let body = tuple_body(input_type, fields);
    from_impl(input, fields, body)
}

fn tuple_body<T: ToTokens>(return_type: T, fields: &[&Field]) -> Tokens {
    if fields.len() == 1 {
        quote!(#return_type(original))
    } else {
        let field_names = &number_idents(fields.len());
        quote!(#return_type(#(original.#field_names),*))
    }
}

fn struct_from(input: &DeriveInput, fields: &[&Field]) -> Tokens {
    let input_type = &input.ident;
    let body = struct_body(input_type, fields);
    from_impl(input, fields, body)
}

fn struct_body<T: ToTokens>(return_type: T, fields: &[&Field]) -> Tokens {
    if fields.len() == 1 {
        let field_name = &fields[0].ident;
        quote!(#return_type{#field_name: original})
    } else {
        let argument_field_names = &number_idents(fields.len());
        let field_names = &field_idents(fields);
        quote!(#return_type{#(#field_names: original.#argument_field_names),*})
    }
}

fn enum_from(input: &DeriveInput, data_enum: &DataEnum) -> Tokens {
    let mut type_signature_counts = HashMap::new();
    let input_type = &input.ident;

    for variant in &data_enum.variants {
        match variant.fields {
            Fields::Unnamed(ref fields) => {
                let original_types = unnamed_to_vec(fields).iter().map(|f| &f.ty).collect();
                let counter = type_signature_counts.entry(original_types).or_insert(0);
                *counter += 1;
            }
            Fields::Named(ref fields) => {
                let original_types = named_to_vec(fields).iter().map(|f| &f.ty).collect();
                let counter = type_signature_counts.entry(original_types).or_insert(0);
                *counter += 1;
            }
            Fields::Unit => {
                let counter = type_signature_counts.entry(vec![]).or_insert(0);
                *counter += 1;
            }
        }
    }

    let mut tokens = Tokens::new();

    for variant in &data_enum.variants {
        match variant.fields {
            Fields::Unnamed(ref fields) => {
                let field_vec = &unnamed_to_vec(fields);
                let original_types = get_field_types(field_vec);

                if *type_signature_counts.index(&original_types) == 1 {
                    let variant_ident = &variant.ident;
                    let body = tuple_body(quote!(#input_type::#variant_ident), field_vec);
                    from_impl(input, field_vec, body).to_tokens(&mut tokens)
                }
            }

            Fields::Named(ref fields) => {
                let field_vec = &named_to_vec(fields);
                let original_types = get_field_types(field_vec);

                if *type_signature_counts.index(&original_types) == 1 {
                    let variant_ident = &variant.ident;
                    let body = struct_body(quote!(#input_type::#variant_ident), field_vec);
                    from_impl(input, field_vec, body).to_tokens(&mut tokens)
                }
            }
            Fields::Unit => {
                if *type_signature_counts.index(&vec![]) == 1 {
                    let variant_ident = &variant.ident;
                    let body = struct_body(quote!(#input_type::#variant_ident), &[]);
                    from_impl(input, &[], body).to_tokens(&mut tokens)
                }
            }
        }
    }
    tokens
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use http::header::{self, HeaderName};
use httprequest::HttpRequest;

const X_FORWARDED_FOR: &str = "X-FORWARDED-FOR";
const X_FORWARDED_HOST: &str = "X-FORWARDED-HOST";
const X_FORWARDED_PROTO: &str = "X-FORWARDED-PROTO";

/// `HttpRequest` connection information
///
/// While it is possible to create `ConnectionInfo` directly,
/// consider using `HttpRequest::load_connection_info()` which cache result.
pub struct ConnectionInfo<'a> {
    scheme: &'a str,
    host: &'a str,
    remote: Option<&'a str>,
    peer: Option<String>,
}

impl<'a> ConnectionInfo<'a> {

    /// Create *ConnectionInfo* instance for a request.
    pub fn new<S>(req: &'a HttpRequest<S>) -> ConnectionInfo<'a> {
        let mut host = None;
        let mut scheme = None;
        let mut remote = None;
        let mut peer = None;

        // load forwarded header
        for hdr in req.headers().get_all(header::FORWARDED) {
            if let Ok(val) = hdr.to_str() {
                for pair in val.split(';') {
                    for el in pair.split(',') {
                        let mut items = el.trim().splitn(2, '=');
                        if let Some(name) = items.next() {
                            if let Some(val) = items.next() {
                                match &name.to_lowercase() as &str {
                                    "for" => if remote.is_none() {
                                        remote = Some(val.trim());
                                    },
                                    "proto" => if scheme.is_none() {
                                        scheme = Some(val.trim());
                                    },
                                    "host" => if host.is_none() {
                                        host = Some(val.trim());
                                    },
                                    _ => (),
                                }
                            }
                        }
                    }
                }
            }
        }

        // scheme
        if scheme.is_none() {
            if let Some(h) = req.headers().get(
                HeaderName::from_str(X_FORWARDED_PROTO).unwrap()) {
                if let Ok(h) = h.to_str() {
                    scheme = h.split(',').next().map(|v| v.trim());
                }
            }
            if scheme.is_none() {
                if let Some(a) = req.uri().scheme_part() {
                    scheme = Some(a.as_str())
                }
            }
        }

        // host
        if host.is_none() {
            if let Some(h) = req.headers().get(HeaderName::from_str(X_FORWARDED_HOST).unwrap()) {
                if let Ok(h) = h.to_str() {
                    host = h.split(',').next().map(|v| v.trim());
                }
            }
            if host.is_none() {
                if let Some(h) = req.headers().get(header::HOST) {
                    if let Ok(h) = h.to_str() {
                        host = Some(h);
                    }
                }
                if host.is_none() {
                    if let Some(a) = req.uri().authority_part() {
                        host = Some(a.as_str())
                    }
                }
            }
        }

        // remote addr
        if remote.is_none() {
            if let Some(h) = req.headers().get(
                HeaderName::from_str(X_FORWARDED_FOR).unwrap()) {
                if let Ok(h) = h.to_str() {
                    remote = h.split(',').next().map(|v| v.trim());
                }
            }
            if remote.is_none() {
                if let Some(addr) = req.peer_addr() {
                    // get peeraddr from socketaddr
                    peer = Some(format!("{}", addr));
                }
            }
        }

        ConnectionInfo {
            scheme: scheme.unwrap_or("http"),
            host: host.unwrap_or("localhost"),
            remote: remote,
            peer: peer,
        }
    }

    /// Scheme of the request.
    ///
    /// Scheme is resolved through the following headers, in this order:
    ///
    /// - Forwarded
    /// - X-Forwarded-Proto
    /// - Uri
    #[inline]
    pub fn scheme(&self) -> &str {
        self.scheme
    }

    /// Hostname of the request.
    ///
    /// Hostname is resolved through the following headers, in this order:
    ///
    /// - Forwarded
    /// - X-Forwarded-Host
    /// - Host
    /// - Uri
    pub fn host(&self) -> &str {
        self.host
    }

    /// Remote IP of client initiated HTTP request.
    ///
    /// The IP is resolved through the following headers, in this order:
    ///
    /// - Forwarded
    /// - X-Forwarded-For
    /// - peername of opened socket
    #[inline]
    pub fn remote(&self) -> Option<&str> {
        if let Some(r) = self.remote {
            Some(r)
        } else if let Some(ref peer) = self.peer {
            Some(peer)
        } else {
            None
        }
    }
}

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

    #[test]
    fn test_forwarded() {
        let req = HttpRequest::default();
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "http");
        assert_eq!(info.host(), "localhost");

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            header::FORWARDED,
            HeaderValue::from_static(
                "for=192.0.2.60; proto=https; by=203.0.113.43; host=rust-lang.org"));

        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "https");
        assert_eq!(info.host(), "rust-lang.org");
        assert_eq!(info.remote(), Some("192.0.2.60"));

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            header::HOST, HeaderValue::from_static("rust-lang.org"));

        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "http");
        assert_eq!(info.host(), "rust-lang.org");
        assert_eq!(info.remote(), None);

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            HeaderName::from_str(X_FORWARDED_FOR).unwrap(), HeaderValue::from_static("192.0.2.60"));
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.remote(), Some("192.0.2.60"));

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            HeaderName::from_str(X_FORWARDED_HOST).unwrap(), HeaderValue::from_static("192.0.2.60"));
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.host(), "192.0.2.60");
        assert_eq!(info.remote(), None);

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            HeaderName::from_str(X_FORWARDED_PROTO).unwrap(), HeaderValue::from_static("https"));
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "https");
    }
}
<commit_msg>cleanup<commit_after>use std::str::FromStr;
use http::header::{self, HeaderName};
use httprequest::HttpRequest;

const X_FORWARDED_FOR: &str = "X-FORWARDED-FOR";
const X_FORWARDED_HOST: &str = "X-FORWARDED-HOST";
const X_FORWARDED_PROTO: &str = "X-FORWARDED-PROTO";

/// `HttpRequest` connection information
///
/// While it is possible to create `ConnectionInfo` directly,
/// consider using `HttpRequest::load_connection_info()` which cache result.
pub struct ConnectionInfo<'a> {
    scheme: &'a str,
    host: &'a str,
    remote: Option<&'a str>,
    peer: Option<String>,
}

impl<'a> ConnectionInfo<'a> {

    /// Create *ConnectionInfo* instance for a request.
    pub fn new<S>(req: &'a HttpRequest<S>) -> ConnectionInfo<'a> {
        let mut host = None;
        let mut scheme = None;
        let mut remote = None;
        let mut peer = None;

        // load forwarded header
        for hdr in req.headers().get_all(header::FORWARDED) {
            if let Ok(val) = hdr.to_str() {
                for pair in val.split(';') {
                    for el in pair.split(',') {
                        let mut items = el.trim().splitn(2, '=');
                        if let Some(name) = items.next() {
                            if let Some(val) = items.next() {
                                match &name.to_lowercase() as &str {
                                    "for" => if remote.is_none() {
                                        remote = Some(val.trim());
                                    },
                                    "proto" => if scheme.is_none() {
                                        scheme = Some(val.trim());
                                    },
                                    "host" => if host.is_none() {
                                        host = Some(val.trim());
                                    },
                                    _ => (),
                                }
                            }
                        }
                    }
                }
            }
        }

        // scheme
        if scheme.is_none() {
            if let Some(h) = req.headers().get(
                HeaderName::from_str(X_FORWARDED_PROTO).unwrap()) {
                if let Ok(h) = h.to_str() {
                    scheme = h.split(',').next().map(|v| v.trim());
                }
            }
            if scheme.is_none() {
                scheme = req.uri().scheme_part().map(|a| a.as_str());
            }
        }

        // host
        if host.is_none() {
            if let Some(h) = req.headers().get(HeaderName::from_str(X_FORWARDED_HOST).unwrap()) {
                if let Ok(h) = h.to_str() {
                    host = h.split(',').next().map(|v| v.trim());
                }
            }
            if host.is_none() {
                if let Some(h) = req.headers().get(header::HOST) {
                    host = h.to_str().ok();
                }
                if host.is_none() {
                    host = req.uri().authority_part().map(|a| a.as_str())
                }
            }
        }

        // remote addr
        if remote.is_none() {
            if let Some(h) = req.headers().get(
                HeaderName::from_str(X_FORWARDED_FOR).unwrap()) {
                if let Ok(h) = h.to_str() {
                    remote = h.split(',').next().map(|v| v.trim());
                }
            }
            if remote.is_none() {
                // get peeraddr from socketaddr
                peer = req.peer_addr().map(|addr| format!("{}", addr));
            }
        }

        ConnectionInfo {
            scheme: scheme.unwrap_or("http"),
            host: host.unwrap_or("localhost"),
            remote: remote,
            peer: peer,
        }
    }

    /// Scheme of the request.
    ///
    /// Scheme is resolved through the following headers, in this order:
    ///
    /// - Forwarded
    /// - X-Forwarded-Proto
    /// - Uri
    #[inline]
    pub fn scheme(&self) -> &str {
        self.scheme
    }

    /// Hostname of the request.
    ///
    /// Hostname is resolved through the following headers, in this order:
    ///
    /// - Forwarded
    /// - X-Forwarded-Host
    /// - Host
    /// - Uri
    pub fn host(&self) -> &str {
        self.host
    }

    /// Remote IP of client initiated HTTP request.
    ///
    /// The IP is resolved through the following headers, in this order:
    ///
    /// - Forwarded
    /// - X-Forwarded-For
    /// - peername of opened socket
    #[inline]
    pub fn remote(&self) -> Option<&str> {
        if let Some(r) = self.remote {
            Some(r)
        } else if let Some(ref peer) = self.peer {
            Some(peer)
        } else {
            None
        }
    }
}

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

    #[test]
    fn test_forwarded() {
        let req = HttpRequest::default();
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "http");
        assert_eq!(info.host(), "localhost");

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            header::FORWARDED,
            HeaderValue::from_static(
                "for=192.0.2.60; proto=https; by=203.0.113.43; host=rust-lang.org"));

        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "https");
        assert_eq!(info.host(), "rust-lang.org");
        assert_eq!(info.remote(), Some("192.0.2.60"));

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            header::HOST, HeaderValue::from_static("rust-lang.org"));

        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "http");
        assert_eq!(info.host(), "rust-lang.org");
        assert_eq!(info.remote(), None);

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            HeaderName::from_str(X_FORWARDED_FOR).unwrap(), HeaderValue::from_static("192.0.2.60"));
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.remote(), Some("192.0.2.60"));

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            HeaderName::from_str(X_FORWARDED_HOST).unwrap(), HeaderValue::from_static("192.0.2.60"));
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.host(), "192.0.2.60");
        assert_eq!(info.remote(), None);

        let mut req = HttpRequest::default();
        req.headers_mut().insert(
            HeaderName::from_str(X_FORWARDED_PROTO).unwrap(), HeaderValue::from_static("https"));
        let info = ConnectionInfo::new(&req);
        assert_eq!(info.scheme(), "https");
    }
}
<|endoftext|>