<commit_before>use super::Rdx;

use std::cell::RefCell;
use std::marker::PhantomData;
use std::fmt;
use std::rc::Rc;

#[derive(Clone)]
enum Node<T> where T: Clone + Rdx {
    Inner(Rc<RefCell<NodeInner<T>>>),
    Pruned(Rc<RefCell<NodePruned<T>>>),
    Child(T),
    Free,
}

#[derive(Clone)]
enum NodeLimited<T> where T: Clone + Rdx {
    Inner(Rc<RefCell<NodeInner<T>>>),
    Child(T),
}

impl<'a, T> From<&'a NodeLimited<T>> for Node<T> where T: Clone + Rdx {
    fn from(obj: &'a NodeLimited<T>) -> Node<T> {
        match obj {
            &NodeLimited::Inner(ref inner) => Node::Inner(inner.clone()),
            &NodeLimited::Child(ref x) => Node::Child(x.clone()),
        }
    }
}

#[derive(Clone)]
struct NodeInner<T> where T: Clone + Rdx {
    round: usize,
    children: Vec<Node<T>>,
}

#[derive(Clone)]
struct NodePruned<T> where T: Clone + Rdx {
    round: usize,
    nbuckets: usize,
    buckets: Vec<usize>,
    child: NodeLimited<T>,
}

impl<T> NodeInner<T> where T: Clone + Rdx {
    fn new(round: usize, nbuckets: usize) -> NodeInner<T> {
        let mut children = Vec::with_capacity(nbuckets);
        for _ in 0..nbuckets {
            children.push(Node::Free);
        }
        NodeInner {
            round: round,
            children: children,
        }
    }

    fn insert(&mut self, x: T) {
        let bucket = x.get_bucket(self.round - 1);

        if self.round > 1 {
            let clen = self.children.len();
            let replace = match self.children[bucket] {
                Node::Free => {
                    let pruned = Rc::new(RefCell::new(NodePruned::new(self.round - 1, clen, x)));
                    Some(Node::Pruned(pruned))
                },
                Node::Inner(ref mut inner) => {
                    inner.borrow_mut().insert(x);
                    None
                },
                Node::Pruned(ref mut pruned) => {
                    Some(pruned.borrow().insert_or_split(x))
                }
                Node::Child(_) => unreachable!(),
            };

            if let Some(obj) = replace {
                self.children[bucket] = obj;
            }
        } else {
            let alloc = match self.children[bucket] {
                Node::Free => true,
                Node::Child(_) => false,
                Node::Inner(_) => unreachable!(),
                Node::Pruned(_) => unreachable!(),
            };

            if alloc {
                self.children[bucket] = Node::Child(x);
            } else {
                match self.children[bucket] {
                    Node::Child(ref mut y) => *y = x,  // XXX: is that a good idea?
                    _ => unreachable!(),
                }
            }
        }
    }

    fn nnodes(&self) -> (usize, usize, usize, usize) {
        let mut result = (1, 0, 0, 0);
        for c in self.children.iter() {
            match c {
                &Node::Inner(ref inner) => {
                    let tmp = inner.borrow().nnodes();
                    result.0 += tmp.0;
                    result.1 += tmp.1;
                    result.2 += tmp.2;
                    result.3 += tmp.3;
                },
                &Node::Pruned(ref pruned) => {
                    let tmp = pruned.borrow().nnodes();
                    result.0 += tmp.0;
                    result.1 += tmp.1;
                    result.2 += tmp.2;
                    result.3 += tmp.3;
                },
                &Node::Child(_) => {
                    result.2 += 1;
                },
                &Node::Free => {
                    result.3 += 1;
                },
            }
        }
        result
    }
}

impl<T> NodePruned<T> where T: Clone + Rdx {
    fn new(round: usize, nbuckets: usize, x: T) -> NodePruned<T> {
        let mut buckets = Vec::with_capacity(round);
        for i in 0..round {
            let r = round - i;
            let bucket = x.get_bucket(r - 1);
            buckets.push(bucket);
        }
        let child = NodeLimited::Child(x);
        NodePruned {
            round: round,
            nbuckets: nbuckets,
            buckets: buckets,
            child: child,
        }
    }

    fn insert_or_split(&self, x: T) -> Node<T> {
        for i in 0..self.buckets.len() {
            let r = self.round - i;
            let bucket_y = self.buckets[i];
            let bucket_x = x.get_bucket(r - 1);

            if bucket_x != bucket_y {
                // === outcome a: split ===
                //
                //     [head][middle/diff][tail]
                //
                // becomes
                //
                //                     |-[tail1]
                //     [head]-[middle]-|
                //                     |-[tail2]
                //

                // split head, middle and tail
                let mut buckets_head = self.buckets.clone();
                let buckets_tail = buckets_head.split_off(i + 1);
                buckets_head.pop();  // remove middle part

                // inner node = middle part
                let mut inner = NodeInner::new(self.round - buckets_head.len(), self.nbuckets);

                // add old tail and new branch to inner node
                if buckets_tail.is_empty() {
                    inner.children[bucket_y] = (&self.child).into();
                } else {
                    let tail = Rc::new(RefCell::new(NodePruned {
                        round: self.round - i - 1,
                        nbuckets: self.nbuckets,
                        buckets: buckets_tail,
                        child: self.child.clone(),
                    }));
                    inner.children[bucket_y] = Node::Pruned(tail);
                }
                inner.insert(x);

                // either return inner node (when head is empty) or create new head
                if buckets_head.is_empty() {
                    return Node::Inner(Rc::new(RefCell::new(inner)));
                } else {
                    let head = Rc::new(RefCell::new(NodePruned {
                        round: self.round,
                        nbuckets: self.nbuckets,
                        buckets: buckets_head,
                        child: NodeLimited::Inner(Rc::new(RefCell::new(inner))),
                    }));
                    return Node::Pruned(head);
                }
            }
        }

        // === outcome b: insert ===
        // INFO: Copying seems to be faster than returning an Option and do the change in-place.
        //       I don't know why this is the case.
        let mut cpy = self.clone();
        match cpy.child {
            NodeLimited::Inner(ref mut inner) => {
                inner.borrow_mut().insert(x);
            },
            NodeLimited::Child(ref mut y) => {
                *y = x;
            },
        }
        Node::Pruned(Rc::new(RefCell::new(cpy)))
    }

    fn nnodes(&self) -> (usize, usize, usize, usize) {
        let mut result = (0, 1, 0, 0);
        match self.child {
            NodeLimited::Inner(ref inner) => {
                let tmp = inner.borrow().nnodes();
                result.0 += tmp.0;
                result.1 += tmp.1;
                result.2 += tmp.2;
                result.3 += tmp.3;
            },
            NodeLimited::Child(_) => {
                result.2 += 1;
            },
        }
        result
    }
}

pub struct RdxTree<T> where T: Clone + Rdx {
    root: Node<T>,
}

impl<T> RdxTree<T> where T: Clone + Rdx {
    pub fn new() -> RdxTree<T> {
        let rounds = <T as Rdx>::cfg_nrounds();
        let buckets = <T as Rdx>::cfg_nbuckets();
        RdxTree {
            root: Node::Inner(
                Rc::new(RefCell::new(NodeInner::<T>::new(rounds, buckets)))
            ),
        }
    }

    pub fn insert(&mut self, x: T) {
        match self.root {
            Node::Inner(ref mut inner) => {
                inner.borrow_mut().insert(x);
            },
            _ => {
                unreachable!();
            }
        }
    }

    pub fn iter<'a>(&'a self) -> RdxTreeIter<'a, T> {
        let mut iters = Vec::new();
        match self.root {
            Node::Inner(ref inner) => {
                iters.push((inner.clone(), 0));
            },
            _ => unreachable!(),
        }
        RdxTreeIter {
            iters: iters,
            phantom: PhantomData,
        }
    }

    pub fn nnodes(&self) -> (usize, usize, usize, usize) {
        match self.root {
            Node::Inner(ref inner) => {
                inner.borrow().nnodes()
            },
            _ => {
                unreachable!()
            }
        }
    }
}

pub struct RdxTreeIter<'a, T> where T: Clone + Rdx + 'a {
    iters: Vec<(Rc<RefCell<NodeInner<T>>>, usize)>,  // do not work with iterators directly since we need a checked but dynamic borrow
    phantom: PhantomData<&'a RdxTree<T>>,            // keep tree borrow intact
}

impl<'a, T> Iterator for RdxTreeIter<'a, T> where T: Clone + Rdx + 'a {
    type Item = T;  // XXX: do not copy!

    fn next(&mut self) -> Option<Self::Item> {
        let mut result: Option<T> = None;

        while self.iters.len() > 0 && result.is_none() {
            let mut push: Option<Rc<RefCell<NodeInner<T>>>> = None;
            let mut pop = false;

            if let Some(pair) = self.iters.last_mut() {
                let &mut (ref rc, ref mut i) = pair;
                let borrow = rc.borrow();
                if *i >= borrow.children.len() {
                    pop = true;
                } else {
                    match borrow.children[*i] {
                        Node::Free => {},
                        Node::Child(ref x) => {
                            result = Some(x.clone());
                        },
                        Node::Inner(ref inner) => {
                            push = Some(inner.clone());
                        },
                        Node::Pruned(ref pruned) => {
                            match pruned.borrow().child {
                                NodeLimited::Child(ref x) => {
                                    result = Some(x.clone());
                                },
                                NodeLimited::Inner(ref inner) => {
                                    push = Some(inner.clone());
                                },
                            }
                        },
                    }

                    *i += 1;
                }
            } else {
                unreachable!();
            }

            if pop {
                self.iters.pop();
            } else if let Some(next) = push {
                self.iters.push((next, 0));
            }
        }

        result
    }
}

fn print_node<T>(node: &Node<T>, depth: usize) where T: Clone + fmt::Display + Rdx {
    let prefix: String = (0..depth).map(|_| ' ').collect();
    match *node {
        Node::Inner(ref inner) => {
            for (i, c) in inner.borrow().children.iter().enumerate() {
                println!("{}{}:", prefix, i);
                print_node(c, depth + 1);
            }
        },
        Node::Pruned(ref pruned) => {
            let borrowed = pruned.borrow();
            println!("{}P: [{:?}]", prefix, borrowed.buckets);
            let c = (&(borrowed.child)).into();
            print_node(&c, depth + borrowed.buckets.len());
        },
        Node::Child(ref x) => {
            println!("{}=> {}", prefix, x);
        },
        Node::Free => {
            println!("{}X", prefix);
        },
    }
}

fn print_tree<T>(tree: &RdxTree<T>) where T: Clone + fmt::Display + Rdx {
    print_node(&tree.root, 0);
}

#[test]
fn test_insert() {
    let mut tree: RdxTree<u32> = RdxTree::new();
    tree.insert(1);
    tree.insert(22);
    tree.insert(2);
    tree.insert(1024);
    tree.insert(0);

    let should = vec![0, 1, 2, 22, 1024];
    let is: Vec<u32> = tree.iter().collect();
    assert_eq!(should, is);
    assert_eq!(tree.nnodes(), (4, 3, 5, 56));
}
<commit_msg>add support for iterating trees with reversed Rdx<commit_after>use super::Rdx;

use std::cell::RefCell;
use std::marker::PhantomData;
use std::fmt;
use std::rc::Rc;

#[derive(Clone)]
enum Node<T> where T: Clone + Rdx {
    Inner(Rc<RefCell<NodeInner<T>>>),
    Pruned(Rc<RefCell<NodePruned<T>>>),
    Child(T),
    Free,
}

#[derive(Clone)]
enum NodeLimited<T> where T: Clone + Rdx {
    Inner(Rc<RefCell<NodeInner<T>>>),
    Child(T),
}

impl<'a, T> From<&'a NodeLimited<T>> for Node<T> where T: Clone + Rdx {
    fn from(obj: &'a NodeLimited<T>) -> Node<T> {
        match obj {
            &NodeLimited::Inner(ref inner) => Node::Inner(inner.clone()),
            &NodeLimited::Child(ref x) => Node::Child(x.clone()),
        }
    }
}

#[derive(Clone)]
struct NodeInner<T> where T: Clone + Rdx {
    round: usize,
    children: Vec<Node<T>>,
}

#[derive(Clone)]
struct NodePruned<T> where T: Clone + Rdx {
    round: usize,
    nbuckets: usize,
    buckets: Vec<usize>,
    child: NodeLimited<T>,
}

impl<T> NodeInner<T> where T: Clone + Rdx {
    fn new(round: usize, nbuckets: usize) -> NodeInner<T> {
        let mut children = Vec::with_capacity(nbuckets);
        for _ in 0..nbuckets {
            children.push(Node::Free);
        }
        NodeInner {
            round: round,
            children: children,
        }
    }

    fn insert(&mut self, x: T) {
        let bucket = x.get_bucket(self.round - 1);

        if self.round > 1 {
            let clen = self.children.len();
            let replace = match self.children[bucket] {
                Node::Free => {
                    let pruned = Rc::new(RefCell::new(NodePruned::new(self.round - 1, clen, x)));
                    Some(Node::Pruned(pruned))
                },
                Node::Inner(ref mut inner) => {
                    inner.borrow_mut().insert(x);
                    None
                },
                Node::Pruned(ref mut pruned) => {
                    Some(pruned.borrow().insert_or_split(x))
                }
                Node::Child(_) => unreachable!(),
            };

            if let Some(obj) = replace {
                self.children[bucket] = obj;
            }
        } else {
            let alloc = match self.children[bucket] {
                Node::Free => true,
                Node::Child(_) => false,
                Node::Inner(_) => unreachable!(),
                Node::Pruned(_) => unreachable!(),
            };

            if alloc {
                self.children[bucket] = Node::Child(x);
            } else {
                match self.children[bucket] {
                    Node::Child(ref mut y) => *y = x,  // XXX: is that a good idea?
                    _ => unreachable!(),
                }
            }
        }
    }

    fn nnodes(&self) -> (usize, usize, usize, usize) {
        let mut result = (1, 0, 0, 0);
        for c in self.children.iter() {
            match c {
                &Node::Inner(ref inner) => {
                    let tmp = inner.borrow().nnodes();
                    result.0 += tmp.0;
                    result.1 += tmp.1;
                    result.2 += tmp.2;
                    result.3 += tmp.3;
                },
                &Node::Pruned(ref pruned) => {
                    let tmp = pruned.borrow().nnodes();
                    result.0 += tmp.0;
                    result.1 += tmp.1;
                    result.2 += tmp.2;
                    result.3 += tmp.3;
                },
                &Node::Child(_) => {
                    result.2 += 1;
                },
                &Node::Free => {
                    result.3 += 1;
                },
            }
        }
        result
    }
}

impl<T> NodePruned<T> where T: Clone + Rdx {
    fn new(round: usize, nbuckets: usize, x: T) -> NodePruned<T> {
        let mut buckets = Vec::with_capacity(round);
        for i in 0..round {
            let r = round - i;
            let bucket = x.get_bucket(r - 1);
            buckets.push(bucket);
        }
        let child = NodeLimited::Child(x);
        NodePruned {
            round: round,
            nbuckets: nbuckets,
            buckets: buckets,
            child: child,
        }
    }

    fn insert_or_split(&self, x: T) -> Node<T> {
        for i in 0..self.buckets.len() {
            let r = self.round - i;
            let bucket_y = self.buckets[i];
            let bucket_x = x.get_bucket(r - 1);

            if bucket_x != bucket_y {
                // === outcome a: split ===
                //
                //     [head][middle/diff][tail]
                //
                // becomes
                //
                //                     |-[tail1]
                //     [head]-[middle]-|
                //                     |-[tail2]
                //

                // split head, middle and tail
                let mut buckets_head = self.buckets.clone();
                let buckets_tail = buckets_head.split_off(i + 1);
                buckets_head.pop();  // remove middle part

                // inner node = middle part
                let mut inner = NodeInner::new(self.round - buckets_head.len(), self.nbuckets);

                // add old tail and new branch to inner node
                if buckets_tail.is_empty() {
                    inner.children[bucket_y] = (&self.child).into();
                } else {
                    let tail = Rc::new(RefCell::new(NodePruned {
                        round: self.round - i - 1,
                        nbuckets: self.nbuckets,
                        buckets: buckets_tail,
                        child: self.child.clone(),
                    }));
                    inner.children[bucket_y] = Node::Pruned(tail);
                }
                inner.insert(x);

                // either return inner node (when head is empty) or create new head
                if buckets_head.is_empty() {
                    return Node::Inner(Rc::new(RefCell::new(inner)));
                } else {
                    let head = Rc::new(RefCell::new(NodePruned {
                        round: self.round,
                        nbuckets: self.nbuckets,
                        buckets: buckets_head,
                        child: NodeLimited::Inner(Rc::new(RefCell::new(inner))),
                    }));
                    return Node::Pruned(head);
                }
            }
        }

        // === outcome b: insert ===
        // INFO: Copying seems to be faster than returning an Option and do the change in-place.
        //       I don't know why this is the case.
        let mut cpy = self.clone();
        match cpy.child {
            NodeLimited::Inner(ref mut inner) => {
                inner.borrow_mut().insert(x);
            },
            NodeLimited::Child(ref mut y) => {
                *y = x;
            },
        }
        Node::Pruned(Rc::new(RefCell::new(cpy)))
    }

    fn nnodes(&self) -> (usize, usize, usize, usize) {
        let mut result = (0, 1, 0, 0);
        match self.child {
            NodeLimited::Inner(ref inner) => {
                let tmp = inner.borrow().nnodes();
                result.0 += tmp.0;
                result.1 += tmp.1;
                result.2 += tmp.2;
                result.3 += tmp.3;
            },
            NodeLimited::Child(_) => {
                result.2 += 1;
            },
        }
        result
    }
}

pub struct RdxTree<T> where T: Clone + Rdx {
    root: Node<T>,
}

impl<T> RdxTree<T> where T: Clone + Rdx {
    pub fn new() -> RdxTree<T> {
        let rounds = <T as Rdx>::cfg_nrounds();
        let buckets = <T as Rdx>::cfg_nbuckets();
        RdxTree {
            root: Node::Inner(
                Rc::new(RefCell::new(NodeInner::<T>::new(rounds, buckets)))
            ),
        }
    }

    pub fn insert(&mut self, x: T) {
        match self.root {
            Node::Inner(ref mut inner) => {
                inner.borrow_mut().insert(x);
            },
            _ => {
                unreachable!();
            }
        }
    }

    pub fn iter<'a>(&'a self) -> RdxTreeIter<'a, T> {
        let mut stack = Vec::new();
        match self.root {
            Node::Inner(ref inner) => {
                stack.push(((inner.clone(), 1, false)));
            },
            _ => unreachable!(),
        }
        RdxTreeIter {
            stack: stack,
            phantom: PhantomData,
        }
    }

    pub fn nnodes(&self) -> (usize, usize, usize, usize) {
        match self.root {
            Node::Inner(ref inner) => {
                inner.borrow().nnodes()
            },
            _ => {
                unreachable!()
            }
        }
    }
}

pub struct RdxTreeIter<'a, T> where T: Clone + Rdx + 'a {
    // iterator stack:
    //   - reference to inner node (do not work with iterators directly since we need a checked but dynamic borrow)
    //   - current iterator state + 1 (so `0` encodes the "the one BEFORE beginning)
    //   - reverse the iterator order for this subpart if `True`
    stack: Vec<(Rc<RefCell<NodeInner<T>>>, usize, bool)>,

    // keep tree borrow intact
    phantom: PhantomData<&'a RdxTree<T>>,
}

impl<'a, T> Iterator for RdxTreeIter<'a, T> where T: Clone + Rdx + 'a {
    type Item = T;  // XXX: do not copy!

    fn next(&mut self) -> Option<Self::Item> {
        // the iteration is basically the processing of a stack machine

        let mut result: Option<T> = None;

        // iterate until stack is empty or we have a result
        while !self.stack.is_empty() && result.is_none() {
            // the stack is immutable since we work with the current state,
            // therefore we need to store pending operations (push or pop) and execute afterwards
            let mut push: Option<(Rc<RefCell<NodeInner<T>>>, bool)> = None;
            let mut pop = false;
            let stacksize = self.stack.len();

            if let Some(state) = self.stack.last_mut() {
                let &mut (ref rc, ref mut i, reverse) = state;
                let borrowed = rc.borrow();

                // bounds check for current iterator state
                if (reverse && (*i == 0)) || (*i >= borrowed.children.len() + 1) {
                    pop = true;
                } else {
                    // bounds are fine => inspect current sub-element
                    match borrowed.children[*i - 1] {
                        Node::Free => {
                            // it's a free node, we can ignore that and continue with the iteration
                        },
                        Node::Child(ref x) => {
                            // we have found some usable data :)
                            result = Some(x.clone());
                        },
                        Node::Inner(ref inner) => {
                            // inner node => push a new state to the stack
                            let round = <T as Rdx>::cfg_nrounds() - stacksize;
                            let rev = reverse ^ <T as Rdx>::reverse(round, *i - 1);
                            push = Some((inner.clone(), rev));
                        },
                        Node::Pruned(ref pruned) => {
                            // pruned tree part => let's check what the child is
                            let borrowed2 = pruned.borrow();
                            match borrowed2.child {
                                NodeLimited::Child(ref x) => {
                                    // usable data :)
                                    result = Some(x.clone());
                                },
                                NodeLimited::Inner(ref inner) => {
                                    // simulate traversal of pruned tree part to recover `reverse`
                                    let mut round = <T as Rdx>::cfg_nrounds() - stacksize;
                                    let mut rev = reverse ^ <T as Rdx>::reverse(round, *i - 1);
                                    for j in &borrowed2.buckets {
                                        round += 1;
                                        rev ^= <T as Rdx>::reverse(round, j.clone());
                                    }

                                    push = Some((inner.clone(), rev));
                                },
                            }
                        },
                    }

                    if reverse {
                        *i -= 1;
                    } else {
                        *i += 1;
                    }
                }
            } else {
                // that cannot happen since we have already checked if the stack is not empty
                unreachable!();
            }

            // execute all pending operations
            if pop {
                self.stack.pop();
            } else if let Some((next, rev)) = push {
                // the iteration of the next stack part starts either at the beginning or end,
                // depending on the fact that it is a reversed iteration or not
                let idx_start = if rev {
                    next.borrow().children.len()
                } else {
                    1
                };
                self.stack.push((next, idx_start, rev));
            }
        }

        // this can be `None` here in case we've finished iteration and the stack is empty
        result
    }
}

fn print_node<T>(node: &Node<T>, depth: usize) where T: Clone + fmt::Display + Rdx {
    let prefix: String = (0..depth).map(|_| ' ').collect();
    match *node {
        Node::Inner(ref inner) => {
            for (i, c) in inner.borrow().children.iter().enumerate() {
                println!("{}{}:", prefix, i);
                print_node(c, depth + 1);
            }
        },
        Node::Pruned(ref pruned) => {
            let borrowed = pruned.borrow();
            println!("{}P: [{:?}]", prefix, borrowed.buckets);
            let c = (&(borrowed.child)).into();
            print_node(&c, depth + borrowed.buckets.len());
        },
        Node::Child(ref x) => {
            println!("{}=> {}", prefix, x);
        },
        Node::Free => {
            println!("{}X", prefix);
        },
    }
}

fn print_tree<T>(tree: &RdxTree<T>) where T: Clone + fmt::Display + Rdx {
    print_node(&tree.root, 0);
}

#[test]
fn test_insert() {
    let mut tree: RdxTree<u32> = RdxTree::new();
    tree.insert(1);
    tree.insert(22);
    tree.insert(2);
    tree.insert(1024);
    tree.insert(0);

    let should = vec![0, 1, 2, 22, 1024];
    let is: Vec<u32> = tree.iter().collect();
    assert_eq!(should, is);
    assert_eq!(tree.nnodes(), (4, 3, 5, 56));
}

#[test]
fn test_insert_float() {
    let mut tree: RdxTree<f32> = RdxTree::new();
    tree.insert(1f32);
    tree.insert(22f32);
    tree.insert(2f32);
    tree.insert(-1024f32);
    tree.insert(-1f32);
    tree.insert(1024f32);
    tree.insert(0f32);

    let should = vec![-1024f32, -1f32, 0f32, 1f32, 2f32, 22f32, 1024f32];
    let is: Vec<f32> = tree.iter().collect();
    assert_eq!(should, is);
    assert_eq!(tree.nnodes(), (4, 7, 7, 54));
}
<|endoftext|>


<commit_before>use urlparse::{urlparse, urlunparse};

/// Strip tracking junk and URL suffixes.
pub fn tidy_url(url: &str) -> String {
    let mut parsed_url = urlparse(url);

    // Always get the desktop version of Twitter URLs
    if parsed_url.netloc == "mobile.twitter.com" {
        parsed_url.netloc = String::from("twitter.com");
    }

    // Remove any tracking junk from Amazon URLs so they're not a
    // ridiculous length
    if parsed_url.netloc == "www.amazon.co.uk" {
        parsed_url.query = None;
        let mut new_path = String::from("");
        for component in parsed_url.path.split("ref=") {
            new_path = String::from(component);
            break;
        }
        parsed_url.path = new_path;
    }

    // Strip tracking junk from Medium, Mashable and Buzzfeed
    if (parsed_url.netloc == "medium.com") ||
       (parsed_url.netloc == "www.buzzfeed.com") ||
       (parsed_url.netloc == "mashable.com") {
            parsed_url.fragment = None;
    }

    // Remove '#notes' from Tumblr URLs
    if parsed_url.netloc.ends_with("tumblr.com") {
        let new_fragment: Option<String> = match parsed_url.fragment {
            Some(fragment) => {
                if fragment == "notes" {
                    None
                } else {
                    Some(fragment)
                }
            }
            None => None,
        };
        parsed_url.fragment = new_fragment;
    }

  // Remove &feature=youtu.be from YouTube URLs
  if parsed_url.netloc.ends_with("youtube.com") {
    parsed_url.query = match parsed_url.query {
      Some(q) => {
        let new_q = q
          .replace("&feature=youtu.be", "")
          .replace("feature=youtu.be&", "")
          .replace("feature=youtu.be", "");
        if new_q != "" {
          Some(new_q)
        } else {
          None
        }
      },
      None => None,
    };
  }

  urlunparse(parsed_url)
}

macro_rules! tidy_url_tests {
    ($($name:ident: $value:expr,)*) => {
    $(
        #[test]
        fn $name() {
            let (input, expected) = $value;
            assert_eq!(expected, tidy_url(input));
        }
    )*
    }
}

tidy_url_tests! {
    url_tw_0:  ("https://mobile.twitter.com/Breaking911/status/822589852596191235",
                "https://twitter.com/Breaking911/status/822589852596191235"),
    url_tw_1:  ("https://twitter.com/elise3aum/status/822903824268533762",
                "https://twitter.com/elise3aum/status/822903824268533762"),

    url_az_0:  ("https://www.amazon.co.uk/dp/B01DFKBL68/ref=gw_aucc_comb_AB_clean_2?pf_rd_r=N1MF2PWADRHS55427ETG&pf_rd_p=c11a2c11-c670-46ff-87a1-c1eef4fad652",
                "https://www.amazon.co.uk/dp/B01DFKBL68/"),

    url_md_0:  ("https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20#.sjyskxdsz",
                "https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20"),

    url_tm_0:  ("http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539#notes",
                "http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539"),

    url_8:   ("https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man#.biqmkzz8kn",
              "https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man"),
    url_9:   ("http://mashable.com/2016/03/21/apple-liam-recycling-robot/#b9y4lv3m4qqX",
              "http://mashable.com/2016/03/21/apple-liam-recycling-robot/"),

  youtube_plain_video: (
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
  ),

  youtube_with_timestamp: (
    "https://www.youtube.com/watch?v=D68cUzqcTrg&feature=youtu.be#t=1m",
    "https://www.youtube.com/watch?v=D68cUzqcTrg#t=1m",
  ),

  youtube_with_trailing_feature: (
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0&feature=youtu.be",
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0",
  ),

  youtube_with_leading_feature: (
    "https://www.youtube.com/watch?feature=youtu.be&v=oPo4n9tBPsk",
    "https://www.youtube.com/watch?v=oPo4n9tBPsk",
  ),

  youtube_with_only_feature: (
    "https://www.youtube.com/watch?feature=youtu.be",
    "https://www.youtube.com/watch",
  ),

  youtube_channel: (
    "https://www.youtube.com/user/TheQIElves",
    "https://www.youtube.com/user/TheQIElves"
  ),
}
<commit_msg>Internal refactor to do query-string manipulation properly<commit_after>use urlparse::{Query, parse_qs, urlparse, urlunparse};

/// Re-encode a query string for Rust
fn encode_querystring(query: Query) -> Option<String> {
  let mut query_components: Vec<String> = vec![];
  for (key, value) in query {
    for v in value.iter() {
      query_components.push(format!("{}={}", key, v));
    }
  }
  if query_components.len() > 0 {
    Some(query_components.join("&"))
  } else {
    None
  }
}

/// Strip tracking junk and URL suffixes.
pub fn tidy_url(url: &str) -> String {
    let mut parsed_url = urlparse(url);

    // Always get the desktop version of Twitter URLs
    if parsed_url.netloc == "mobile.twitter.com" {
        parsed_url.netloc = String::from("twitter.com");
    }

    // Remove any tracking junk from Amazon URLs so they're not a
    // ridiculous length
    if parsed_url.netloc == "www.amazon.co.uk" {
        parsed_url.query = None;
        let mut new_path = String::from("");
        for component in parsed_url.path.split("ref=") {
            new_path = String::from(component);
            break;
        }
        parsed_url.path = new_path;
    }

    // Strip tracking junk from Medium, Mashable and Buzzfeed
    if (parsed_url.netloc == "medium.com") ||
       (parsed_url.netloc == "www.buzzfeed.com") ||
       (parsed_url.netloc == "mashable.com") {
            parsed_url.fragment = None;
    }

    // Remove '#notes' from Tumblr URLs
    if parsed_url.netloc.ends_with("tumblr.com") {
        let new_fragment: Option<String> = match parsed_url.fragment {
            Some(fragment) => {
                if fragment == "notes" {
                    None
                } else {
                    Some(fragment)
                }
            }
            None => None,
        };
        parsed_url.fragment = new_fragment;
    }

  // Remove &feature=youtu.be from YouTube URLs
  if parsed_url.netloc.ends_with("youtube.com") {
    parsed_url.query = match parsed_url.query {
      Some(qs) => {
        let mut query = parse_qs(&qs);
        query.remove("feature");
        encode_querystring(query)
      },
      None => None,
    };
  }

  urlunparse(parsed_url)
}

macro_rules! tidy_url_tests {
    ($($name:ident: $value:expr,)*) => {
    $(
        #[test]
        fn $name() {
            let (input, expected) = $value;
            assert_eq!(expected, tidy_url(input));
        }
    )*
    }
}

tidy_url_tests! {
    url_tw_0:  ("https://mobile.twitter.com/Breaking911/status/822589852596191235",
                "https://twitter.com/Breaking911/status/822589852596191235"),
    url_tw_1:  ("https://twitter.com/elise3aum/status/822903824268533762",
                "https://twitter.com/elise3aum/status/822903824268533762"),

    url_az_0:  ("https://www.amazon.co.uk/dp/B01DFKBL68/ref=gw_aucc_comb_AB_clean_2?pf_rd_r=N1MF2PWADRHS55427ETG&pf_rd_p=c11a2c11-c670-46ff-87a1-c1eef4fad652",
                "https://www.amazon.co.uk/dp/B01DFKBL68/"),

    url_md_0:  ("https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20#.sjyskxdsz",
                "https://medium.com/@anildash/forget-why-its-time-to-get-to-work-c49ac5f0da20"),

    url_tm_0:  ("http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539#notes",
                "http://azurelunatic.tumblr.com/post/155525051123/things-about-hufflepuffs-539"),

    url_8:   ("https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man#.biqmkzz8kn",
              "https://www.buzzfeed.com/katienotopoulos/the-end-of-apple-man"),
    url_9:   ("http://mashable.com/2016/03/21/apple-liam-recycling-robot/#b9y4lv3m4qqX",
              "http://mashable.com/2016/03/21/apple-liam-recycling-robot/"),

  youtube_plain_video: (
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
    "https://www.youtube.com/watch?v=zB4I68XVPzQ",
  ),

  youtube_with_timestamp: (
    "https://www.youtube.com/watch?v=D68cUzqcTrg&feature=youtu.be#t=1m",
    "https://www.youtube.com/watch?v=D68cUzqcTrg#t=1m",
  ),

  youtube_with_trailing_feature: (
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0&feature=youtu.be",
    "https://www.youtube.com/watch?v=PbJqNa0_Oz0",
  ),

  youtube_with_leading_feature: (
    "https://www.youtube.com/watch?feature=youtu.be&v=oPo4n9tBPsk",
    "https://www.youtube.com/watch?v=oPo4n9tBPsk",
  ),

  youtube_with_only_feature: (
    "https://www.youtube.com/watch?feature=youtu.be",
    "https://www.youtube.com/watch",
  ),

  youtube_channel: (
    "https://www.youtube.com/user/TheQIElves",
    "https://www.youtube.com/user/TheQIElves"
  ),
}
<|endoftext|>


<commit_before>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::ops::Deref;
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ParseError, RenderingError};
use crate::length::*;
use crate::node::{CascadedValues, Node, NodeBorrow};
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterInput, FilterResult};

mod error;
use self::error::FilterError;

/// Trait to render filter effect primitives.
pub trait FilterRender {
    /// Renders this filter primitive.
    ///
    /// If this filter primitive can't be rendered for whatever reason (for instance, a required
    /// property hasn't been provided), an error is returned.
    fn render(
        &self,
        node: &Node,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError>;
}

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw + FilterRender {
    /// Returns `true` if this filter primitive is affected by the `color-interpolation-filters`
    /// property.
    ///
    /// Primitives that do color blending (like `feComposite` or `feBlend`) should return `true`
    /// here, whereas primitives that don't (like `feOffset`) should return `false`.
    fn is_affected_by_color_interpolation_filters(&self) -> bool;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// The base filter primitive node containing common properties.
struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )?)
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

/// The base node for filter primitives which accept input.
struct PrimitiveWithInput {
    base: Primitive,
    in_: Option<Input>,
}

impl Primitive {
    /// Constructs a new `Primitive` with empty properties.
    #[inline]
    fn new<T: FilterEffect>() -> Primitive {
        Primitive {
            x: None,
            y: None,
            width: None,
            height: None,
            result: None,
        }
    }

    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds<'a>(&self, ctx: &'a FilterContext) -> Result<BoundsBuilder, FilterError> {
        // With ObjectBoundingBox, only fractions and percents are allowed.
        if ctx.primitive_units() == CoordUnits::ObjectBoundingBox {
            check_units(self.x)?;
            check_units(self.y)?;
            check_units(self.width)?;
            check_units(self.height)?;
        }

        let transform = ctx.paffine();
        if !transform.is_invertible() {
            return Err(FilterError::InvalidParameter(
                "transform is not invertible".to_string(),
            ));
        }

        Ok(BoundsBuilder::new(
            self.x,
            self.y,
            self.width,
            self.height,
            transform,
        ))
    }
}

fn check_units<N: Normalize, V: Validate>(
    length: Option<CssLength<N, V>>,
) -> Result<(), FilterError> {
    match length {
        Some(l) if l.unit == LengthUnit::Px || l.unit == LengthUnit::Percent => Ok(()),
        Some(_) => Err(FilterError::InvalidUnits),
        None => Ok(()),
    }
}

impl SetAttributes for Primitive {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl PrimitiveWithInput {
    /// Constructs a new `PrimitiveWithInput` with empty properties.
    #[inline]
    fn new<T: FilterEffect>() -> PrimitiveWithInput {
        PrimitiveWithInput {
            base: Primitive::new::<T>(),
            in_: None,
        }
    }

    /// Returns the input Cairo surface for this filter primitive.
    #[inline]
    fn get_input(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterInput, FilterError> {
        ctx.get_input(acquired_nodes, draw_ctx, self.in_.as_ref())
    }
}

impl SetAttributes for PrimitiveWithInput {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.base.set_attributes(attrs)?;

        self.in_ = attrs
            .iter()
            .find(|(attr, _)| attr.expanded() == expanded_name!("", "in"))
            .and_then(|(attr, value)| attr.parse(value).ok());

        Ok(())
    }
}

impl Deref for PrimitiveWithInput {
    type Target = Primitive;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.base
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    computed_from_node_being_filtered: &ComputedValues,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    if filter_node.borrow_element().is_in_error() {
        return Ok(source_surface);
    }

    let filter = borrow_element_as!(filter_node, Filter);
    let mut filter_ctx = FilterContext::new(
        &filter,
        computed_from_node_being_filtered,
        source_surface,
        draw_ctx,
        transform,
        node_bbox,
    );

    // If paffine is non-invertible, we won't draw anything. Also bbox combining in bounds
    // computations will panic due to non-invertible martrix.
    if !filter_ctx.paffine().is_invertible() {
        return Ok(filter_ctx.into_output()?);
    }

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        // Check if the node wants linear RGB.
        .map(|c| {
            let linear_rgb = {
                let cascaded = CascadedValues::new_from_node(&c);
                let values = cascaded.get();

                values.color_interpolation_filters() == ColorInterpolationFilters::LinearRgb
            };

            (c, linear_rgb)
        });

    for (c, linear_rgb) in primitives {
        let elt = c.borrow_element();
        let filter = elt.as_filter_effect().unwrap();

        let mut render = |filter_ctx: &mut FilterContext| {
            if let Err(err) = filter
                .render(&c, filter_ctx, acquired_nodes, draw_ctx)
                .and_then(|result| filter_ctx.store_result(result))
            {
                rsvg_log!("(filter primitive {} returned an error: {})", c, err);

                // Exit early on Cairo errors. Continue rendering otherwise.
                if let FilterError::CairoError(status) = err {
                    return Err(status);
                }
            }

            Ok(())
        };

        let start = Instant::now();

        if filter.is_affected_by_color_interpolation_filters() && linear_rgb {
            filter_ctx.with_linear_rgb(render)?;
        } else {
            render(&mut filter_ctx)?;
        }

        let elapsed = start.elapsed();
        rsvg_log!(
            "(rendered filter primitive {} in\n    {} seconds)",
            c,
            elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
        );
    }

    Ok(filter_ctx.into_output()?)
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<commit_msg>Remove unnecessary lifetime<commit_after>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::ops::Deref;
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ParseError, RenderingError};
use crate::length::*;
use crate::node::{CascadedValues, Node, NodeBorrow};
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterInput, FilterResult};

mod error;
use self::error::FilterError;

/// Trait to render filter effect primitives.
pub trait FilterRender {
    /// Renders this filter primitive.
    ///
    /// If this filter primitive can't be rendered for whatever reason (for instance, a required
    /// property hasn't been provided), an error is returned.
    fn render(
        &self,
        node: &Node,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError>;
}

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw + FilterRender {
    /// Returns `true` if this filter primitive is affected by the `color-interpolation-filters`
    /// property.
    ///
    /// Primitives that do color blending (like `feComposite` or `feBlend`) should return `true`
    /// here, whereas primitives that don't (like `feOffset`) should return `false`.
    fn is_affected_by_color_interpolation_filters(&self) -> bool;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// The base filter primitive node containing common properties.
struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )?)
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

/// The base node for filter primitives which accept input.
struct PrimitiveWithInput {
    base: Primitive,
    in_: Option<Input>,
}

impl Primitive {
    /// Constructs a new `Primitive` with empty properties.
    #[inline]
    fn new<T: FilterEffect>() -> Primitive {
        Primitive {
            x: None,
            y: None,
            width: None,
            height: None,
            result: None,
        }
    }

    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> Result<BoundsBuilder, FilterError> {
        // With ObjectBoundingBox, only fractions and percents are allowed.
        if ctx.primitive_units() == CoordUnits::ObjectBoundingBox {
            check_units(self.x)?;
            check_units(self.y)?;
            check_units(self.width)?;
            check_units(self.height)?;
        }

        let transform = ctx.paffine();
        if !transform.is_invertible() {
            return Err(FilterError::InvalidParameter(
                "transform is not invertible".to_string(),
            ));
        }

        Ok(BoundsBuilder::new(
            self.x,
            self.y,
            self.width,
            self.height,
            transform,
        ))
    }
}

fn check_units<N: Normalize, V: Validate>(
    length: Option<CssLength<N, V>>,
) -> Result<(), FilterError> {
    match length {
        Some(l) if l.unit == LengthUnit::Px || l.unit == LengthUnit::Percent => Ok(()),
        Some(_) => Err(FilterError::InvalidUnits),
        None => Ok(()),
    }
}

impl SetAttributes for Primitive {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl PrimitiveWithInput {
    /// Constructs a new `PrimitiveWithInput` with empty properties.
    #[inline]
    fn new<T: FilterEffect>() -> PrimitiveWithInput {
        PrimitiveWithInput {
            base: Primitive::new::<T>(),
            in_: None,
        }
    }

    /// Returns the input Cairo surface for this filter primitive.
    #[inline]
    fn get_input(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterInput, FilterError> {
        ctx.get_input(acquired_nodes, draw_ctx, self.in_.as_ref())
    }
}

impl SetAttributes for PrimitiveWithInput {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.base.set_attributes(attrs)?;

        self.in_ = attrs
            .iter()
            .find(|(attr, _)| attr.expanded() == expanded_name!("", "in"))
            .and_then(|(attr, value)| attr.parse(value).ok());

        Ok(())
    }
}

impl Deref for PrimitiveWithInput {
    type Target = Primitive;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.base
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    computed_from_node_being_filtered: &ComputedValues,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    if filter_node.borrow_element().is_in_error() {
        return Ok(source_surface);
    }

    let filter = borrow_element_as!(filter_node, Filter);
    let mut filter_ctx = FilterContext::new(
        &filter,
        computed_from_node_being_filtered,
        source_surface,
        draw_ctx,
        transform,
        node_bbox,
    );

    // If paffine is non-invertible, we won't draw anything. Also bbox combining in bounds
    // computations will panic due to non-invertible martrix.
    if !filter_ctx.paffine().is_invertible() {
        return Ok(filter_ctx.into_output()?);
    }

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        // Check if the node wants linear RGB.
        .map(|c| {
            let linear_rgb = {
                let cascaded = CascadedValues::new_from_node(&c);
                let values = cascaded.get();

                values.color_interpolation_filters() == ColorInterpolationFilters::LinearRgb
            };

            (c, linear_rgb)
        });

    for (c, linear_rgb) in primitives {
        let elt = c.borrow_element();
        let filter = elt.as_filter_effect().unwrap();

        let mut render = |filter_ctx: &mut FilterContext| {
            if let Err(err) = filter
                .render(&c, filter_ctx, acquired_nodes, draw_ctx)
                .and_then(|result| filter_ctx.store_result(result))
            {
                rsvg_log!("(filter primitive {} returned an error: {})", c, err);

                // Exit early on Cairo errors. Continue rendering otherwise.
                if let FilterError::CairoError(status) = err {
                    return Err(status);
                }
            }

            Ok(())
        };

        let start = Instant::now();

        if filter.is_affected_by_color_interpolation_filters() && linear_rgb {
            filter_ctx.with_linear_rgb(render)?;
        } else {
            render(&mut filter_ctx)?;
        }

        let elapsed = start.elapsed();
        rsvg_log!(
            "(rendered filter primitive {} in\n    {} seconds)",
            c,
            elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
        );
    }

    Ok(filter_ctx.into_output()?)
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<|endoftext|>


<commit_before>use colored::*;
use regex::Regex;

// http://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python
pub fn iec(n: u64) -> String {
    let units = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"];

    let i = (n as f64).log(1024_f64).floor() as u32;
    let p = 1024_u64.pow(i);
    let s = (n as f64)/(p as f64);
    format!("{:.0}{}", s, units[i as usize])
}

// /dev/mapper/vg-lv -> /dev/vg/lv
pub fn shorten_lv(path: &str) -> String {
    let re = Regex::new(r"^/dev/mapper/(.*?)-(.*)").unwrap();

    match re.captures(path) {
        Some(caps) => return format!("/dev/{}/{}", &caps[1], &caps[2].replace("--", "-")),
        None       => {},
    }

    path.to_string()
}

pub fn bargraph(percent: f64) -> String {
    let chars = "■■■■■■■■■■■■■■■■■■■■";
    let s1 = (percent / 10.0).round() as usize * 2;
    let s2 = 20 - s1;
    format!("{}{}", chars.chars().take(s1).collect::<String>().green(),
            chars.chars().take(s2).collect::<String>().white().dimmed())
}
<commit_msg>Add tests for shorten_lv.<commit_after>use colored::*;
use regex::Regex;

// http://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python
pub fn iec(n: u64) -> String {
    let units = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"];

    let i = (n as f64).log(1024_f64).floor() as u32;
    let p = 1024_u64.pow(i);
    let s = (n as f64)/(p as f64);
    format!("{:.0}{}", s, units[i as usize])
}

// /dev/mapper/vg-lv -> /dev/vg/lv
pub fn shorten_lv(path: &str) -> String {
    let re = Regex::new(r"^/dev/mapper/(.*?)-(.*)").unwrap();

    match re.captures(path) {
        Some(caps) => return format!("/dev/{}/{}", &caps[1], &caps[2].replace("--", "-")),
        None       => {},
    }

    path.to_string()
}

pub fn bargraph(percent: f64) -> String {
    let chars = "■■■■■■■■■■■■■■■■■■■■";
    let s1 = (percent / 10.0).round() as usize * 2;
    let s2 = 20 - s1;
    format!("{}{}", chars.chars().take(s1).collect::<String>().green(),
            chars.chars().take(s2).collect::<String>().white().dimmed())
}

mod tests {
    use super::shorten_lv;

    #[test]
    fn test_shorten_lv() {
        assert_eq!(shorten_lv("/dev/mapper/vg-lv"), "/dev/vg/lv");
        assert_eq!(shorten_lv("/dev/mapper/vg-lv--1"), "/dev/vg/lv-1");
        assert_eq!(shorten_lv("/dev/mapper/vg--one-lv"), "/dev/vg-one/lv");
        assert_eq!(shorten_lv("/dev/mapper/vg--one-lv--one"), "/dev/vg-one/lv-one");
    }
}
<|endoftext|>


<commit_before>use crate::codec::{CodecResult, FramedIo};
use crate::*;

use asynchronous_codec::FramedRead;
use bytes::Bytes;
use futures_util::{SinkExt, StreamExt};
use num_traits::Pow;
use rand::Rng;

use std::convert::{TryFrom, TryInto};
use std::ops::Deref;
use std::str::FromStr;
use std::sync::Arc;
use uuid::Uuid;

#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
pub struct PeerIdentity(Bytes);

impl PeerIdentity {
    pub const MAX_LENGTH: usize = 255;

    pub fn new() -> Self {
        let id = Uuid::new_v4();
        Self(Bytes::copy_from_slice(id.as_bytes()))
    }
}

impl AsRef<[u8]> for PeerIdentity {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Deref for PeerIdentity {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for PeerIdentity {
    fn default() -> Self {
        Self::new()
    }
}

impl FromStr for PeerIdentity {
    type Err = ZmqError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::try_from(s.as_bytes())
    }
}

impl TryFrom<Bytes> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: Bytes) -> Result<Self, ZmqError> {
        if data.is_empty() {
            Ok(Self::new())
        } else if data.len() > Self::MAX_LENGTH {
            Err(ZmqError::PeerIdentity)
        } else {
            Ok(Self(data))
        }
    }
}

impl TryFrom<&[u8]> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: &[u8]) -> Result<Self, ZmqError> {
        Self::try_from(Bytes::copy_from_slice(data))
    }
}

impl TryFrom<Vec<u8>> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: Vec<u8>) -> Result<Self, ZmqError> {
        Self::try_from(Bytes::from(data))
    }
}

impl From<PeerIdentity> for Bytes {
    fn from(p_id: PeerIdentity) -> Self {
        p_id.0
    }
}

impl From<PeerIdentity> for Vec<u8> {
    fn from(p_id: PeerIdentity) -> Self {
        p_id.0.to_vec()
    }
}

pub(crate) struct Peer {
    pub(crate) _identity: PeerIdentity,
    pub(crate) send_queue: FramedWrite<Box<dyn FrameableWrite>, ZmqCodec>,
    pub(crate) recv_queue: FramedRead<Box<dyn FrameableRead>, ZmqCodec>,
}

/// Given the result of the greetings exchange, determines the version of the
/// ZMTP protocol that should be used for communication with the peer according
/// to https://rfc.zeromq.org/spec/23/#version-negotiation.
fn negotiate_version(greeting: Message) -> ZmqResult<ZmtpVersion> {
    let my_version = ZmqGreeting::default().version;

    match greeting {
        Message::Greeting(peer) => {
            if peer.version >= my_version {
                // A peer MUST accept higher protocol versions as valid. That is,
                // a ZMTP peer MUST accept protocol versions greater or equal to 3.0.
                // This allows future implementations to safely interoperate with
                // current implementations.
                //
                // A peer SHALL always use its own protocol (including framing)
                // when talking to an equal or higher protocol peer.
                Ok(my_version)
            } else {
                // A peer MAY downgrade its protocol to talk to a lower protocol peer.
                //
                // If a peer cannot downgrade its protocol to match its peer, it MUST
                // close the connection.
                // TODO: implement interoperability with older protocol versions
                Err(ZmqError::UnsupportedVersion(peer.version))
            }
        }
        _ => Err(ZmqError::Other("Failed Greeting exchange")),
    }
}

pub(crate) async fn greet_exchange(raw_socket: &mut FramedIo) -> ZmqResult<ZmtpVersion> {
    raw_socket
        .write_half
        .send(Message::Greeting(ZmqGreeting::default()))
        .await?;

    let greeting = match raw_socket.read_half.next().await {
        Some(message) => message?,
        None => return Err(ZmqError::Other("Failed Greeting exchange")),
    };
    negotiate_version(greeting)
}

pub(crate) async fn ready_exchange(
    raw_socket: &mut FramedIo,
    socket_type: SocketType,
    props: Option<HashMap<String, Bytes>>,
) -> ZmqResult<PeerIdentity> {
    let mut ready = ZmqCommand::ready(socket_type);
    if let Some(props) = props {
        ready.add_properties(props);
    }
    raw_socket.write_half.send(Message::Command(ready)).await?;

    let ready_repl: Option<CodecResult<Message>> = raw_socket.read_half.next().await;
    match ready_repl {
        Some(Ok(Message::Command(command))) => match command.name {
            ZmqCommandName::READY => {
                let other_sock_type = match command.properties.get("Socket-Type") {
                    Some(s) => SocketType::try_from(&s[..])?,
                    None => Err(ZmqError::Other("Failed to parse other socket type"))?,
                };

                let peer_id = command
                    .properties
                    .get("Identity")
                    .map(|x| x.clone().try_into())
                    .transpose()?
                    .unwrap_or_default();

                if socket_type.compatible(other_sock_type) {
                    Ok(peer_id)
                } else {
                    Err(ZmqError::Other(
                        "Provided sockets combination is not compatible",
                    ))
                }
            }
        },
        Some(Ok(_)) => Err(ZmqError::Other("Failed to confirm ready state")),
        Some(Err(e)) => Err(e.into()),
        None => Err(ZmqError::Other("No reply from server")),
    }
}

pub(crate) async fn peer_connected(
    mut raw_socket: FramedIo,
    backend: Arc<dyn MultiPeerBackend>,
) -> ZmqResult<PeerIdentity> {
    greet_exchange(&mut raw_socket).await?;
    let mut props = None;
    if let Some(identity) = &backend.socket_options().peer_id {
        let mut connect_ops = HashMap::new();
        connect_ops.insert("Identity".to_string(), identity.clone().into());
        props = Some(connect_ops);
    }
    let peer_id = ready_exchange(&mut raw_socket, backend.socket_type(), props).await?;
    backend.peer_connected(&peer_id, raw_socket).await;
    Ok(peer_id)
}

pub(crate) async fn connect_forever(endpoint: Endpoint) -> ZmqResult<(FramedIo, Endpoint)> {
    let mut try_num: u64 = 0;
    loop {
        match transport::connect(&endpoint).await {
            Ok(res) => return Ok(res),
            Err(ZmqError::Network(e)) if e.kind() == std::io::ErrorKind::ConnectionRefused => {
                if try_num < 5 {
                    try_num += 1;
                }
                let delay = {
                    let mut rng = rand::thread_rng();
                    std::f64::consts::E.powf(try_num as f64 / 3.0) + rng.gen_range(0.0f64..0.1f64)
                };
                async_rt::task::sleep(std::time::Duration::from_secs_f64(delay)).await;
                continue;
            }
            Err(e) => return Err(e),
        }
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use super::*;
    use crate::codec::mechanism::ZmqMechanism;

    pub async fn test_bind_to_unspecified_interface_helper(
        any: std::net::IpAddr,
        mut sock: impl Socket,
        start_port: u16,
    ) -> ZmqResult<()> {
        assert!(sock.binds().is_empty());
        assert!(any.is_unspecified());

        for i in 0..4 {
            sock.bind(
                Endpoint::Tcp(any.into(), start_port + i)
                    .to_string()
                    .as_str(),
            )
            .await?;
        }

        let bound_to = sock.binds();
        assert_eq!(bound_to.len(), 4);

        let mut port_set = std::collections::HashSet::new();
        for b in bound_to.keys() {
            if let Endpoint::Tcp(host, port) = b {
                assert_eq!(host, &any.into());
                port_set.insert(*port);
            } else {
                unreachable!()
            }
        }

        (start_port..start_port + 4).for_each(|p| assert!(port_set.contains(&p)));

        Ok(())
    }

    pub async fn test_bind_to_any_port_helper(mut sock: impl Socket) -> ZmqResult<()> {
        assert!(sock.binds().is_empty());
        for _ in 0..4 {
            sock.bind("tcp://localhost:0").await?;
        }

        let bound_to = sock.binds();
        assert_eq!(bound_to.len(), 4);
        let mut port_set = std::collections::HashSet::new();
        for b in bound_to.keys() {
            if let Endpoint::Tcp(host, port) = b {
                assert_eq!(host, &Host::Domain("localhost".to_string()));
                assert_ne!(*port, 0);
                // Insert and check that it wasn't already present
                assert!(port_set.insert(*port));
            } else {
                unreachable!()
            }
        }

        Ok(())
    }

    fn new_greeting(version: ZmtpVersion) -> Message {
        Message::Greeting(ZmqGreeting {
            version,
            mechanism: ZmqMechanism::PLAIN,
            as_server: false,
        })
    }

    #[test]
    fn negotiate_version_peer_is_using_the_same_version() {
        // if both peers are using the same protocol version, negotiation is trivial
        let peer_version = ZmqGreeting::default().version;
        let expected = ZmqGreeting::default().version;
        let actual = negotiate_version(new_greeting(peer_version)).unwrap();
        assert_eq!(actual, expected);
    }

    #[test]
    fn negotiate_version_peer_is_using_a_newer_version() {
        // if the other end is using a newer protocol version, they should adjust to us
        let peer_version = (3, 1);
        let expected = ZmqGreeting::default().version;
        let actual = negotiate_version(new_greeting(peer_version)).unwrap();
        assert_eq!(actual, expected);
    }

    #[test]
    fn negotiate_version_peer_is_using_an_older_version() {
        // if the other end is using an older protocol version, we should adjust to
        // them, but interoperability with older peers is not implemented at the
        // moment, so we just give up immediately, which is allowed by the spec
        let peer_version = (2, 1);
        let actual = negotiate_version(new_greeting(peer_version));
        match actual {
            Err(ZmqError::UnsupportedVersion(version)) => assert_eq!(version, peer_version),
            _ => panic!("Unexpected result"),
        }
    }

    #[test]
    fn negotiate_version_invalid_greeting() {
        // unexpected message during greetings exchange
        let message = Message::Message(ZmqMessage::from(""));
        let actual = negotiate_version(message);
        match actual {
            Err(ZmqError::Other(_)) => {}
            _ => panic!("Unexpected result"),
        }
    }
}
<commit_msg>Update util.rs<commit_after>use crate::codec::{CodecResult, FramedIo};
use crate::*;

use asynchronous_codec::FramedRead;
use bytes::Bytes;
use futures_util::{SinkExt, StreamExt};
use rand::Rng;

use std::convert::{TryFrom, TryInto};
use std::ops::Deref;
use std::str::FromStr;
use std::sync::Arc;
use uuid::Uuid;

#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
pub struct PeerIdentity(Bytes);

impl PeerIdentity {
    pub const MAX_LENGTH: usize = 255;

    pub fn new() -> Self {
        let id = Uuid::new_v4();
        Self(Bytes::copy_from_slice(id.as_bytes()))
    }
}

impl AsRef<[u8]> for PeerIdentity {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Deref for PeerIdentity {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for PeerIdentity {
    fn default() -> Self {
        Self::new()
    }
}

impl FromStr for PeerIdentity {
    type Err = ZmqError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::try_from(s.as_bytes())
    }
}

impl TryFrom<Bytes> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: Bytes) -> Result<Self, ZmqError> {
        if data.is_empty() {
            Ok(Self::new())
        } else if data.len() > Self::MAX_LENGTH {
            Err(ZmqError::PeerIdentity)
        } else {
            Ok(Self(data))
        }
    }
}

impl TryFrom<&[u8]> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: &[u8]) -> Result<Self, ZmqError> {
        Self::try_from(Bytes::copy_from_slice(data))
    }
}

impl TryFrom<Vec<u8>> for PeerIdentity {
    type Error = ZmqError;

    fn try_from(data: Vec<u8>) -> Result<Self, ZmqError> {
        Self::try_from(Bytes::from(data))
    }
}

impl From<PeerIdentity> for Bytes {
    fn from(p_id: PeerIdentity) -> Self {
        p_id.0
    }
}

impl From<PeerIdentity> for Vec<u8> {
    fn from(p_id: PeerIdentity) -> Self {
        p_id.0.to_vec()
    }
}

pub(crate) struct Peer {
    pub(crate) _identity: PeerIdentity,
    pub(crate) send_queue: FramedWrite<Box<dyn FrameableWrite>, ZmqCodec>,
    pub(crate) recv_queue: FramedRead<Box<dyn FrameableRead>, ZmqCodec>,
}

/// Given the result of the greetings exchange, determines the version of the
/// ZMTP protocol that should be used for communication with the peer according
/// to https://rfc.zeromq.org/spec/23/#version-negotiation.
fn negotiate_version(greeting: Message) -> ZmqResult<ZmtpVersion> {
    let my_version = ZmqGreeting::default().version;

    match greeting {
        Message::Greeting(peer) => {
            if peer.version >= my_version {
                // A peer MUST accept higher protocol versions as valid. That is,
                // a ZMTP peer MUST accept protocol versions greater or equal to 3.0.
                // This allows future implementations to safely interoperate with
                // current implementations.
                //
                // A peer SHALL always use its own protocol (including framing)
                // when talking to an equal or higher protocol peer.
                Ok(my_version)
            } else {
                // A peer MAY downgrade its protocol to talk to a lower protocol peer.
                //
                // If a peer cannot downgrade its protocol to match its peer, it MUST
                // close the connection.
                // TODO: implement interoperability with older protocol versions
                Err(ZmqError::UnsupportedVersion(peer.version))
            }
        }
        _ => Err(ZmqError::Other("Failed Greeting exchange")),
    }
}

pub(crate) async fn greet_exchange(raw_socket: &mut FramedIo) -> ZmqResult<ZmtpVersion> {
    raw_socket
        .write_half
        .send(Message::Greeting(ZmqGreeting::default()))
        .await?;

    let greeting = match raw_socket.read_half.next().await {
        Some(message) => message?,
        None => return Err(ZmqError::Other("Failed Greeting exchange")),
    };
    negotiate_version(greeting)
}

pub(crate) async fn ready_exchange(
    raw_socket: &mut FramedIo,
    socket_type: SocketType,
    props: Option<HashMap<String, Bytes>>,
) -> ZmqResult<PeerIdentity> {
    let mut ready = ZmqCommand::ready(socket_type);
    if let Some(props) = props {
        ready.add_properties(props);
    }
    raw_socket.write_half.send(Message::Command(ready)).await?;

    let ready_repl: Option<CodecResult<Message>> = raw_socket.read_half.next().await;
    match ready_repl {
        Some(Ok(Message::Command(command))) => match command.name {
            ZmqCommandName::READY => {
                let other_sock_type = match command.properties.get("Socket-Type") {
                    Some(s) => SocketType::try_from(&s[..])?,
                    None => Err(ZmqError::Other("Failed to parse other socket type"))?,
                };

                let peer_id = command
                    .properties
                    .get("Identity")
                    .map(|x| x.clone().try_into())
                    .transpose()?
                    .unwrap_or_default();

                if socket_type.compatible(other_sock_type) {
                    Ok(peer_id)
                } else {
                    Err(ZmqError::Other(
                        "Provided sockets combination is not compatible",
                    ))
                }
            }
        },
        Some(Ok(_)) => Err(ZmqError::Other("Failed to confirm ready state")),
        Some(Err(e)) => Err(e.into()),
        None => Err(ZmqError::Other("No reply from server")),
    }
}

pub(crate) async fn peer_connected(
    mut raw_socket: FramedIo,
    backend: Arc<dyn MultiPeerBackend>,
) -> ZmqResult<PeerIdentity> {
    greet_exchange(&mut raw_socket).await?;
    let mut props = None;
    if let Some(identity) = &backend.socket_options().peer_id {
        let mut connect_ops = HashMap::new();
        connect_ops.insert("Identity".to_string(), identity.clone().into());
        props = Some(connect_ops);
    }
    let peer_id = ready_exchange(&mut raw_socket, backend.socket_type(), props).await?;
    backend.peer_connected(&peer_id, raw_socket).await;
    Ok(peer_id)
}

pub(crate) async fn connect_forever(endpoint: Endpoint) -> ZmqResult<(FramedIo, Endpoint)> {
    let mut try_num: u64 = 0;
    loop {
        match transport::connect(&endpoint).await {
            Ok(res) => return Ok(res),
            Err(ZmqError::Network(e)) if e.kind() == std::io::ErrorKind::ConnectionRefused => {
                if try_num < 5 {
                    try_num += 1;
                }
                let delay = {
                    let mut rng = rand::thread_rng();
                    std::f64::consts::E.powf(try_num as f64 / 3.0) + rng.gen_range(0.0f64..0.1f64)
                };
                async_rt::task::sleep(std::time::Duration::from_secs_f64(delay)).await;
                continue;
            }
            Err(e) => return Err(e),
        }
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use super::*;
    use crate::codec::mechanism::ZmqMechanism;

    pub async fn test_bind_to_unspecified_interface_helper(
        any: std::net::IpAddr,
        mut sock: impl Socket,
        start_port: u16,
    ) -> ZmqResult<()> {
        assert!(sock.binds().is_empty());
        assert!(any.is_unspecified());

        for i in 0..4 {
            sock.bind(
                Endpoint::Tcp(any.into(), start_port + i)
                    .to_string()
                    .as_str(),
            )
            .await?;
        }

        let bound_to = sock.binds();
        assert_eq!(bound_to.len(), 4);

        let mut port_set = std::collections::HashSet::new();
        for b in bound_to.keys() {
            if let Endpoint::Tcp(host, port) = b {
                assert_eq!(host, &any.into());
                port_set.insert(*port);
            } else {
                unreachable!()
            }
        }

        (start_port..start_port + 4).for_each(|p| assert!(port_set.contains(&p)));

        Ok(())
    }

    pub async fn test_bind_to_any_port_helper(mut sock: impl Socket) -> ZmqResult<()> {
        assert!(sock.binds().is_empty());
        for _ in 0..4 {
            sock.bind("tcp://localhost:0").await?;
        }

        let bound_to = sock.binds();
        assert_eq!(bound_to.len(), 4);
        let mut port_set = std::collections::HashSet::new();
        for b in bound_to.keys() {
            if let Endpoint::Tcp(host, port) = b {
                assert_eq!(host, &Host::Domain("localhost".to_string()));
                assert_ne!(*port, 0);
                // Insert and check that it wasn't already present
                assert!(port_set.insert(*port));
            } else {
                unreachable!()
            }
        }

        Ok(())
    }

    fn new_greeting(version: ZmtpVersion) -> Message {
        Message::Greeting(ZmqGreeting {
            version,
            mechanism: ZmqMechanism::PLAIN,
            as_server: false,
        })
    }

    #[test]
    fn negotiate_version_peer_is_using_the_same_version() {
        // if both peers are using the same protocol version, negotiation is trivial
        let peer_version = ZmqGreeting::default().version;
        let expected = ZmqGreeting::default().version;
        let actual = negotiate_version(new_greeting(peer_version)).unwrap();
        assert_eq!(actual, expected);
    }

    #[test]
    fn negotiate_version_peer_is_using_a_newer_version() {
        // if the other end is using a newer protocol version, they should adjust to us
        let peer_version = (3, 1);
        let expected = ZmqGreeting::default().version;
        let actual = negotiate_version(new_greeting(peer_version)).unwrap();
        assert_eq!(actual, expected);
    }

    #[test]
    fn negotiate_version_peer_is_using_an_older_version() {
        // if the other end is using an older protocol version, we should adjust to
        // them, but interoperability with older peers is not implemented at the
        // moment, so we just give up immediately, which is allowed by the spec
        let peer_version = (2, 1);
        let actual = negotiate_version(new_greeting(peer_version));
        match actual {
            Err(ZmqError::UnsupportedVersion(version)) => assert_eq!(version, peer_version),
            _ => panic!("Unexpected result"),
        }
    }

    #[test]
    fn negotiate_version_invalid_greeting() {
        // unexpected message during greetings exchange
        let message = Message::Message(ZmqMessage::from(""));
        let actual = negotiate_version(message);
        match actual {
            Err(ZmqError::Other(_)) => {}
            _ => panic!("Unexpected result"),
        }
    }
}
<|endoftext|>


<commit_before>use ::*;
use relm::{Relm, RemoteRelm, Widget};
use gtk::prelude::*;
use gtk::{Window, WindowType, DrawingArea, Button};
use gtk::{FileChooserDialog};
use tokio_core::reactor::Interval;
use std::time::Duration;

use map::*;

#[derive(Clone)]
pub struct MyModel {
    map: Map,
    size: Pos,
    center: Pos,
    scale: i32,
}
impl MyModel {
    fn new() -> Self {
        MyModel {
            map: Map::acorn(),
            size: pos(250, 250),
            center: pos(0, 0),
            scale: 2,
        }
    }
}

#[derive(SimpleMsg)]
pub enum MyMsg {
    Motion(((f64, f64), u32)),
    Save,
    Open,
    Tick,
    Quit,
}

#[derive(Clone)]
pub struct Win {
    hbox: gtk::Box,
    button_box: gtk::ButtonBox,
    open_button: Button,
    save_button: Button,
    area: DrawingArea,
    window: Window,
}

impl Win {
    fn draw(&mut self, cells: Vec<&Pos>, model: &MyModel, top_left: &Pos) {
        use gdk::prelude::ContextExt;
        let cr = cairo::Context::create_from_window(&self.area.get_window().unwrap());
        cr.set_source_rgb(1., 1., 1.);
        cr.paint();
        cr.scale(model.scale as f64, model.scale as f64);
        cr.set_source_rgb(0., 0., 0.);
        for pos in cells {
            cr.rectangle((pos.x - top_left.x) as f64, (pos.y - top_left.y) as f64, 1., 1.);
        }
        cr.fill();
    }
}

impl Widget for Win {
    type Root = Window;
    type Model = MyModel;
    type Msg = MyMsg;

    fn root(&self) -> &Self::Root {
        &self.window
    }

    fn model() -> MyModel {
        MyModel::new()
    }

    fn subscriptions(relm: &Relm<MyMsg>) {
        let stream = Interval::new(Duration::from_millis(30), relm.handle()).unwrap();
        relm.connect_exec_ignore_err(stream, MyMsg::Tick);
    }

    fn update(&mut self, event: MyMsg, model: &mut MyModel) {
        match event {
            MyMsg::Tick => {
                model.map.next_generation();
                let top_left = pos(model.center.x - model.size.x / 2, model.center.y - model.size.y / 2);
                let cells = model.map.get_alive_cells_in(top_left, model.size);
                self.draw(cells, model, &top_left);
            },
            MyMsg::Save => {
                let dialog = FileChooserDialog::new(
                    Some("Save File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Save);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Save", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map.save(path).unwrap();
                    }
                }
                dialog.close();
            },
            MyMsg::Open => {
                let dialog = FileChooserDialog::new(
                    Some("Open File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Open);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Open", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map = Map::open(path).unwrap();
                    }
                }
                dialog.close();
            },
            MyMsg::Motion(((x, y), t)) => {
                println!("({}, {}), {}", x, y, t);
            },
            MyMsg::Quit => gtk::main_quit(),
        }
    }

    fn view(relm: RemoteRelm<MyMsg>, model: &MyModel) -> Self {
        let window = Window::new(WindowType::Toplevel);
        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let button_box = gtk::ButtonBox::new(gtk::Orientation::Vertical);
        let open_button = Button::new_with_label("Open");
        let save_button = Button::new_with_label("Save");
        let area = DrawingArea::new();
        area.set_size_request(model.size.x * model.scale, model.size.y * model.scale);
        area.set_events(area.get_events() | gdk::POINTER_MOTION_MASK.bits() as i32);
        area.set_events(area.get_events() | gdk::BUTTON_PRESS_MASK.bits() as i32);
        button_box.set_layout(gtk::ButtonBoxStyle::Start);

        button_box.pack_start(&open_button, false, false, 0);
        button_box.pack_start(&save_button, false, false, 0);
        hbox.pack_start(&area, false, false, 0);
        hbox.pack_start(&button_box, false, false, 0);
        window.add(&hbox);
        window.set_title("Game of Life");
        window.show_all();

        connect!(relm, window, connect_delete_event(_, _) (Some(MyMsg::Quit), Inhibit(false)));
        connect!(relm, area, connect_motion_notify_event(_, ev) (Some(MyMsg::Motion((ev.get_position(), 0))), Inhibit(false)));
        connect!(relm, save_button, connect_clicked(_), MyMsg::Save);
        connect!(relm, open_button, connect_clicked(_), MyMsg::Open);

        Win {
            hbox: hbox,
            button_box: button_box,
            open_button: open_button,
            save_button: save_button,
            area: area,
            window: window,
        }
    }
}
<commit_msg>Viewarea movements<commit_after>use ::*;
use relm::{Relm, RemoteRelm, Widget};
use gtk::prelude::*;
use gtk::{Window, WindowType, DrawingArea, Button};
use gtk::{FileChooserDialog};
use tokio_core::reactor::Interval;
use std::time::Duration;

use map::*;

#[derive(Clone)]
pub struct MyModel {
    map: Map,
    size: Pos,
    center: Pos,
    scale: i32,
    mouse: Option<Pos>,
}
impl MyModel {
    fn new() -> Self {
        MyModel {
            map: Map::acorn(),
            size: pos(250, 250),
            center: pos(0, 0),
            scale: 2,
            mouse: None,
        }
    }
}

#[derive(SimpleMsg)]
pub enum MyMsg {
    Motion(((f64, f64), gdk::ModifierType)),
    Save,
    Open,
    Tick,
    Quit,
}

#[derive(Clone)]
pub struct Win {
    hbox: gtk::Box,
    button_box: gtk::ButtonBox,
    open_button: Button,
    save_button: Button,
    area: DrawingArea,
    window: Window,
}

impl Win {
    fn draw(&mut self, cells: Vec<&Pos>, model: &MyModel, top_left: &Pos) {
        use gdk::prelude::ContextExt;
        let cr = cairo::Context::create_from_window(&self.area.get_window().unwrap());
        cr.set_source_rgb(1., 1., 1.);
        cr.paint();
        cr.scale(model.scale as f64, model.scale as f64);
        cr.set_source_rgb(0., 0., 0.);
        for pos in cells {
            cr.rectangle((pos.x - top_left.x) as f64, (pos.y - top_left.y) as f64, 1., 1.);
        }
        cr.fill();
    }
}

impl Widget for Win {
    type Root = Window;
    type Model = MyModel;
    type Msg = MyMsg;

    fn root(&self) -> &Self::Root {
        &self.window
    }

    fn model() -> MyModel {
        MyModel::new()
    }

    fn subscriptions(relm: &Relm<MyMsg>) {
        let stream = Interval::new(Duration::from_millis(30), relm.handle()).unwrap();
        relm.connect_exec_ignore_err(stream, MyMsg::Tick);
    }

    fn update(&mut self, event: MyMsg, model: &mut MyModel) {
        match event {
            MyMsg::Tick => {
                model.map.next_generation();
                let top_left = pos(model.center.x - model.size.x / 2, model.center.y - model.size.y / 2);
                let cells = model.map.get_alive_cells_in(top_left, model.size);
                self.draw(cells, model, &top_left);
            },
            MyMsg::Save => {
                let dialog = FileChooserDialog::new(
                    Some("Save File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Save);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Save", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map.save(path).unwrap();
                    }
                }
                dialog.close();
            },
            MyMsg::Open => {
                let dialog = FileChooserDialog::new(
                    Some("Open File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Open);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Open", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map = Map::open(path).unwrap();
                    }
                }
                dialog.close();
            },
            MyMsg::Motion(((x, y), t)) => {
                let p = pos(x as i32, y as i32);
                if (t & gdk::BUTTON1_MASK).bits() != 0 {
                    if model.mouse != None {
                        let mut old_pos = model.mouse.unwrap();
                        let new_center = pos(
                            model.center.x + (old_pos.x - p.x) / model.scale,
                            model.center.y + (old_pos.y - p.y) / model.scale
                            );
                        if new_center.x != model.center.x {
                            old_pos.x = p.x;
                        }
                        if new_center.y != model.center.y {
                            old_pos.y = p.y;
                        }
                        model.center = new_center;
                        model.mouse = Some(old_pos);
                    } else {
                        model.mouse = Some(p);
                    }
                } else {
                    model.mouse = None;
                }
            },
            MyMsg::Quit => gtk::main_quit(),
        }
    }

    fn view(relm: RemoteRelm<MyMsg>, model: &MyModel) -> Self {
        let window = Window::new(WindowType::Toplevel);
        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let button_box = gtk::ButtonBox::new(gtk::Orientation::Vertical);
        let open_button = Button::new_with_label("Open");
        let save_button = Button::new_with_label("Save");
        let area = DrawingArea::new();
        area.set_size_request(model.size.x * model.scale, model.size.y * model.scale);
        area.set_events(area.get_events() | gdk::POINTER_MOTION_MASK.bits() as i32);
        area.set_events(area.get_events() | gdk::BUTTON_PRESS_MASK.bits() as i32);
        button_box.set_layout(gtk::ButtonBoxStyle::Start);

        button_box.pack_start(&open_button, false, false, 0);
        button_box.pack_start(&save_button, false, false, 0);
        hbox.pack_start(&area, false, false, 0);
        hbox.pack_start(&button_box, false, false, 0);
        window.add(&hbox);
        window.set_title("Game of Life");
        window.show_all();

        connect!(relm, window, connect_delete_event(_, _) (Some(MyMsg::Quit), Inhibit(false)));
        connect!(relm, area, connect_motion_notify_event(_, ev) (Some(MyMsg::Motion((ev.get_position(), ev.get_state()))), Inhibit(false)));
        connect!(relm, save_button, connect_clicked(_), MyMsg::Save);
        connect!(relm, open_button, connect_clicked(_), MyMsg::Open);

        Win {
            hbox: hbox,
            button_box: button_box,
            open_button: open_button,
            save_button: save_button,
            area: area,
            window: window,
        }
    }
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;
use std::num::Float;
use std::num::FloatMath;

#[deriving(Copy)]
pub struct SineWave(pub f64);

impl Fn<(f64, ), f64> for SineWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let SineWave(frequency) = *self;
        FloatMath::sin(t * frequency * 2.0 * PI)
    }
}

#[deriving(Copy)]
pub struct SquareWave(pub f64);

impl Fn<(f64, ), f64> for SquareWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let SquareWave(frequency) = *self;
        let sin_wave = SineWave(frequency);
        if sin_wave(t).is_positive() { 1.0 } else { -1.0 }
    }
}

#[deriving(Copy)]
pub struct SawtoothWave(pub f64);

impl Fn<(f64, ), f64> for SawtoothWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let SawtoothWave(frequency) = *self;
        let t_factor = t * frequency;
        t_factor - t_factor.floor() - 0.5
    }
}

#[deriving(Copy)]
pub struct TriangleWave(pub f64);

impl Fn<(f64, ), f64> for TriangleWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let TriangleWave(frequency) = *self;
        let sawtooth_wave = SawtoothWave(frequency);
        (sawtooth_wave(t).abs() - 0.25) * 4.0
    }
}

#[deriving(Copy)]
pub struct TangentWave(pub f64);

impl Fn<(f64, ), f64> for TangentWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let TangentWave(frequency) = *self;
        FloatMath::tan(t * frequency * PI).max(0.0).min(1.0)
    }
}

#[deriving(Copy)]
// http://computermusicresource.com/Simple.bell.tutorial.html
pub struct Bell(pub f64, pub f64, pub f64);

impl Fn<(f64, ), f64> for Bell {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let Bell(frequency, attack, decay) = *self;

        let envelope = |t: f64, f: f64| -> f64 {
            let tf = t / f;
            if tf < attack {
                (tf / attack).min(1.0)
            } else {
                (1.0 - (tf / decay)).max(0.0)
            }
        };

        let h1 = SineWave(frequency * 0.56);
        let h2 = SineWave(frequency * 0.92);
        let h3 = SineWave(frequency * 1.19);
        let h4 = SineWave(frequency * 1.71);
        let h5 = SineWave(frequency * 2.00);
        let h6 = SineWave(frequency * 2.74);
        let h7 = SineWave(frequency * 3.00);
        let h8 = SineWave(frequency * 3.76);
        let h9 = SineWave(frequency * 4.07);

        (h1(t) * 1.0 * envelope(t, 1.0) +
         h2(t) * 0.5 * envelope(t, 2.0) +
         h3(t) * 0.25 * envelope(t, 4.0) +
         h4(t) * 0.125 * envelope(t, 6.0) +
         h5(t) * 0.0625 * envelope(t, 8.4) +
         h6(t) * 0.03125 * envelope(t, 10.8) +
         h7(t) * 0.015625 * envelope(t, 13.6) +
         h8(t) * 0.0078125 * envelope(t, 16.4) +
         h9(t) * 0.00390625 * envelope(t, 19.6)) / 2.0
    }
}
<commit_msg>Scale TangentWave to [-1.0, 1.0], squash the amplitude so it sounds better<commit_after>use std::f64::consts::PI;
use std::num::Float;
use std::num::FloatMath;

#[deriving(Copy)]
pub struct SineWave(pub f64);

impl Fn<(f64, ), f64> for SineWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let SineWave(frequency) = *self;
        FloatMath::sin(t * frequency * 2.0 * PI)
    }
}

#[deriving(Copy)]
pub struct SquareWave(pub f64);

impl Fn<(f64, ), f64> for SquareWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let SquareWave(frequency) = *self;
        let sin_wave = SineWave(frequency);
        if sin_wave(t).is_positive() { 1.0 } else { -1.0 }
    }
}

#[deriving(Copy)]
pub struct SawtoothWave(pub f64);

impl Fn<(f64, ), f64> for SawtoothWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let SawtoothWave(frequency) = *self;
        let t_factor = t * frequency;
        t_factor - t_factor.floor() - 0.5
    }
}

#[deriving(Copy)]
pub struct TriangleWave(pub f64);

impl Fn<(f64, ), f64> for TriangleWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let TriangleWave(frequency) = *self;
        let sawtooth_wave = SawtoothWave(frequency);
        (sawtooth_wave(t).abs() - 0.25) * 4.0
    }
}

#[deriving(Copy)]
pub struct TangentWave(pub f64);

impl Fn<(f64, ), f64> for TangentWave {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let TangentWave(frequency) = *self;
        ((FloatMath::tan(t * frequency * PI) - 0.5) / 4.0).max(-1.0).min(1.0)
    }
}

#[deriving(Copy)]
// http://computermusicresource.com/Simple.bell.tutorial.html
pub struct Bell(pub f64, pub f64, pub f64);

impl Fn<(f64, ), f64> for Bell {
    extern "rust-call" fn call(&self, (t, ): (f64, )) -> f64 {
        let Bell(frequency, attack, decay) = *self;

        let envelope = |t: f64, f: f64| -> f64 {
            let tf = t / f;
            if tf < attack {
                (tf / attack).min(1.0)
            } else {
                (1.0 - (tf / decay)).max(0.0)
            }
        };

        let h1 = SineWave(frequency * 0.56);
        let h2 = SineWave(frequency * 0.92);
        let h3 = SineWave(frequency * 1.19);
        let h4 = SineWave(frequency * 1.71);
        let h5 = SineWave(frequency * 2.00);
        let h6 = SineWave(frequency * 2.74);
        let h7 = SineWave(frequency * 3.00);
        let h8 = SineWave(frequency * 3.76);
        let h9 = SineWave(frequency * 4.07);

        (h1(t) * 1.0 * envelope(t, 1.0) +
         h2(t) * 0.5 * envelope(t, 2.0) +
         h3(t) * 0.25 * envelope(t, 4.0) +
         h4(t) * 0.125 * envelope(t, 6.0) +
         h5(t) * 0.0625 * envelope(t, 8.4) +
         h6(t) * 0.03125 * envelope(t, 10.8) +
         h7(t) * 0.015625 * envelope(t, 13.6) +
         h8(t) * 0.0078125 * envelope(t, 16.4) +
         h9(t) * 0.00390625 * envelope(t, 19.6)) / 2.0
    }
}
<|endoftext|>