<commit_before>use std::cmp;
use std::fmt;
use std::iter;

fn compare<T: PartialOrd>(a: &T, b: &T) -> i32 {
    match a.partial_cmp(b).unwrap() {
        cmp::Ordering::Greater => 1,
        cmp::Ordering::Less    => -1,
        _                      => 0
    }
}

pub struct Node<K,V> {
    left: Option<Box<Node<K,V>>>,
    right: Option<Box<Node<K,V>>>,
    key: K,
    val: V
}

impl<K: fmt::Debug, V: fmt::Debug> Node<K, V> {
    fn dump(&self, depth: usize, f: &mut fmt::Formatter, symbol: char) {
        if depth == 0 {
            writeln!(f, "\n{:?}[{:?}]", self.key, self.val).unwrap();
        } else {
            writeln!(f, "{}{}--{:?}[{:?}]",
                     iter::repeat("|  ").take(depth-1).collect::<Vec<&str>>().concat(),
                     symbol, self.key, self.val).unwrap();
        }
        if self.left.is_some() {
            self.left.as_ref().unwrap().dump(depth + 1, f, '+');
        }
        if self.right.is_some() {
            self.right.as_ref().unwrap().dump(depth + 1, f, '`');
        }
    }
}

impl<K: PartialOrd, V> Node<K, V> {
    fn new(key: K, val: V) -> Node<K,V> {
        Node {
            left: None,
            right: None,
            key: key,
            val: val
        }
    }

    fn height(x: Option<&Box<Node<K,V>>>) -> usize {
        if let Some(ref node) = x {
            let lh = Node::height(node.left.as_ref());
            let rh = Node::height(node.left.as_ref());
            if lh <= rh { rh + 1 }
            else { lh + 1 }
        } else {
            0
        }
    }

    fn size(x: Option<&Box<Node<K,V>>>) -> usize {
        if let Some(ref node) = x {
            1 + Node::size(node.left.as_ref()) + Node::size(node.right.as_ref())
        } else {
            0
        }
    }

    fn splay(mut h: Option<Box<Node<K,V>>>, key: &K) -> Option<Box<Node<K,V>>> {
        if h.is_none() {
            return None;
        }
        let cmp1 = h.as_ref().map(|n| compare(key, &n.key)).unwrap();

        if cmp1 < 0 {
            // key not in tree, done
            if h.as_ref().unwrap().left.is_none() {
                return h;
            }
            let cmp2 = compare(key, &h.as_ref().unwrap().left.as_ref().unwrap().key);
            if cmp2 < 0 {
                h.as_mut().map(|n| {
                    n.left.as_mut().map(|n| {
                        n.left = Node::splay(n.left.take(), key);
                    })
                });
                h = Node::rotate_right(h);
            } else if cmp2 > 0 {
                h.as_mut().map(|n| {
                    if n.left.as_mut().map_or(false, |n| {
                        n.right = Node::splay(n.right.take(), key);
                        n.right.is_some()
                    }) {
                        n.left = Node::rotate_left(n.left.take());
                    }
                });
            }
            // key not in tree
            if h.as_ref().unwrap().left.is_none() {
                return h;
            } else {
                return Node::rotate_right(h);
            }
        } else if cmp1 > 0 {
            // key not in tree, done
            if h.as_ref().unwrap().right.is_none() {
                return h;
            }
            let cmp2 = compare(key, &h.as_ref().unwrap().right.as_ref().unwrap().key);
            if cmp2 < 0 {
                h.as_mut().map(|n| {
                    if n.right.as_mut().map_or(false, |n| {
                        n.left = Node::splay(n.left.take(), key);
                        n.left.is_some()
                    }) {
                        n.right = Node::rotate_right(n.right.take());
                    }
                });
            } else if cmp2 > 0 {
                h.as_mut().map(|n| {
                    n.right.as_mut().map(|n| {
                        n.right = Node::splay(n.right.take(), key);
                    })
                });
                h = Node::rotate_left(h);
            }
            // key not in tree
            if h.as_ref().unwrap().right.is_none() {
                return h;
            } else {
                return Node::rotate_left(h);
            }
        }
        h
    }

    fn rotate_right(mut h: Option<Box<Node<K,V>>>) -> Option<Box<Node<K,V>>> {
        let mut x = h.as_mut().map_or(None, |n| n.left.take());
        h.as_mut().map(|n| n.left = x.as_mut().map_or(None, |n| n.right.take()));
        x.as_mut().map(|n| n.right = h);
        x
    }

    fn rotate_left(mut h: Option<Box<Node<K,V>>>) -> Option<Box<Node<K,V>>> {
        let mut x = h.as_mut().map_or(None, |n| n.right.take());
        h.as_mut().map(|n| n.right = x.as_mut().map_or(None, |n| n.left.take()));
        x.as_mut().map(|n| n.left = h);
        x
    }
}

pub struct SplayTree<K,V> {
    root: Option<Box<Node<K,V>>>,
    // size: usize
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SplayTree<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.root.is_none() {
            write!(f, "<empty tree>")
        } else {
            self.root.as_ref().unwrap().dump(0, f, ' ');
            Ok(())
        }
    }
}

impl<K: PartialOrd, V> SplayTree<K,V> {
    pub fn new() -> SplayTree<K,V> {
        SplayTree {
            root: None,
            // size: 0
        }
    }

    pub fn size(&self) -> usize {
        Node::size(self.root.as_ref())
    }

    pub fn height(&self) -> usize {
        Node::height(self.root.as_ref())
    }

    pub fn clear(&mut self) {
        self.root = None;
    }

    // get() needs to update tree structure
    pub fn get(&mut self, key: &K) -> Option<&V> {
        self.root = Node::splay(self.root.take(), key);
        self.root.as_ref().map_or(None, |n| {
            if n.key == *key {
                Some(&n.val)
            } else {
                None
            }
        })
    }

    pub fn contains_key(&mut self, key: &K) -> bool {
        self.get(key).is_some()
    }

    pub fn get_mut<'t>(&'t mut self, key: &K) -> Option<&'t mut V> {
        self.root = Node::splay(self.root.take(), key);
        self.root.as_mut().map_or(None, |n| {
            if n.key == *key {
                Some(&mut n.val)
            } else {
                None
            }
        })
    }

    pub fn insert(&mut self, key: K, val: V) {
        if self.root.is_none() {
            self.root = Some(Box::new(Node::new(key, val)));
            return;
        }

        let mut root = Node::splay(self.root.take(), &key);

        let cmp = compare(&key, &root.as_ref().unwrap().key);
        if cmp < 0 {
            let mut n = Node::new(key, val);
            n.left = root.as_mut().unwrap().left.take();
            n.right = root;
            self.root = Some(Box::new(n));
        } else if cmp > 0 {
            let mut n = Node::new(key, val);
            n.right = root.as_mut().unwrap().right.take();
            n.left = root;
            self.root = Some(Box::new(n));
        } else if cmp == 0{
            root.as_mut().map(|n| n.val = val);
            self.root = root;
        } else {
            unreachable!();
        }
    }

    pub fn remove(&mut self, key: &K) -> Option<V> {
        if self.root.is_none() {
            return None;
        }

        let mut root = Node::splay(self.root.take(), key);

        if *key == root.as_ref().unwrap().key {
            if root.as_ref().unwrap().left.is_none() {
                self.root = root.as_mut().unwrap().right.take();
            } else {
                let x = root.as_mut().unwrap().right.take();
                self.root = Node::splay(root.as_mut().unwrap().left.take(), key);
                self.root.as_mut().map(|n| n.right = x);
            }
            root.map(|n| n.val)
        } else {
            None
        }
    }
}

#[test]
fn test_splay_tree() {
    let mut st1 = SplayTree::new();
    st1.insert(5, 5);
    st1.insert(9, 9);
    st1.insert(13, 13);
    st1.insert(11, 11);
    st1.insert(1, 1);

    assert_eq!(5, st1.size());
    assert!(st1.height() < 5);
    for i in [5, 9, 13, 11, 1].iter() {
        assert_eq!(st1.get(i), Some(i));
    }

    st1.get_mut(&1).map(|val| *val = 1000);
    assert_eq!(st1.get(&1), Some(&1000));

    assert!(st1.remove(&9).is_some());
    assert!(st1.remove(&9).is_none());
    assert!(!st1.contains_key(&9));
}
<commit_msg>spaly_tree: add is_empty()<commit_after>use std::cmp;
use std::fmt;
use std::iter;

fn compare<T: PartialOrd>(a: &T, b: &T) -> i32 {
    match a.partial_cmp(b).unwrap() {
        cmp::Ordering::Greater => 1,
        cmp::Ordering::Less    => -1,
        _                      => 0
    }
}

pub struct Node<K,V> {
    left: Option<Box<Node<K,V>>>,
    right: Option<Box<Node<K,V>>>,
    key: K,
    val: V
}

impl<K: fmt::Debug, V: fmt::Debug> Node<K, V> {
    fn dump(&self, depth: usize, f: &mut fmt::Formatter, symbol: char) {
        if depth == 0 {
            writeln!(f, "\n{:?}[{:?}]", self.key, self.val).unwrap();
        } else {
            writeln!(f, "{}{}--{:?}[{:?}]",
                     iter::repeat("|  ").take(depth-1).collect::<Vec<&str>>().concat(),
                     symbol, self.key, self.val).unwrap();
        }
        if self.left.is_some() {
            self.left.as_ref().unwrap().dump(depth + 1, f, '+');
        }
        if self.right.is_some() {
            self.right.as_ref().unwrap().dump(depth + 1, f, '`');
        }
    }
}

impl<K: PartialOrd, V> Node<K, V> {
    fn new(key: K, val: V) -> Node<K,V> {
        Node {
            left: None,
            right: None,
            key: key,
            val: val
        }
    }

    fn height(x: Option<&Box<Node<K,V>>>) -> usize {
        if let Some(ref node) = x {
            let lh = Node::height(node.left.as_ref());
            let rh = Node::height(node.left.as_ref());
            if lh <= rh { rh + 1 }
            else { lh + 1 }
        } else {
            0
        }
    }

    fn size(x: Option<&Box<Node<K,V>>>) -> usize {
        if let Some(ref node) = x {
            1 + Node::size(node.left.as_ref()) + Node::size(node.right.as_ref())
        } else {
            0
        }
    }

    fn splay(mut h: Option<Box<Node<K,V>>>, key: &K) -> Option<Box<Node<K,V>>> {
        if h.is_none() {
            return None;
        }
        let cmp1 = h.as_ref().map(|n| compare(key, &n.key)).unwrap();

        if cmp1 < 0 {
            // key not in tree, done
            if h.as_ref().unwrap().left.is_none() {
                return h;
            }
            let cmp2 = compare(key, &h.as_ref().unwrap().left.as_ref().unwrap().key);
            if cmp2 < 0 {
                h.as_mut().map(|n| {
                    n.left.as_mut().map(|n| {
                        n.left = Node::splay(n.left.take(), key);
                    })
                });
                h = Node::rotate_right(h);
            } else if cmp2 > 0 {
                h.as_mut().map(|n| {
                    if n.left.as_mut().map_or(false, |n| {
                        n.right = Node::splay(n.right.take(), key);
                        n.right.is_some()
                    }) {
                        n.left = Node::rotate_left(n.left.take());
                    }
                });
            }
            // key not in tree
            if h.as_ref().unwrap().left.is_none() {
                return h;
            } else {
                return Node::rotate_right(h);
            }
        } else if cmp1 > 0 {
            // key not in tree, done
            if h.as_ref().unwrap().right.is_none() {
                return h;
            }
            let cmp2 = compare(key, &h.as_ref().unwrap().right.as_ref().unwrap().key);
            if cmp2 < 0 {
                h.as_mut().map(|n| {
                    if n.right.as_mut().map_or(false, |n| {
                        n.left = Node::splay(n.left.take(), key);
                        n.left.is_some()
                    }) {
                        n.right = Node::rotate_right(n.right.take());
                    }
                });
            } else if cmp2 > 0 {
                h.as_mut().map(|n| {
                    n.right.as_mut().map(|n| {
                        n.right = Node::splay(n.right.take(), key);
                    })
                });
                h = Node::rotate_left(h);
            }
            // key not in tree
            if h.as_ref().unwrap().right.is_none() {
                return h;
            } else {
                return Node::rotate_left(h);
            }
        }
        h
    }

    fn rotate_right(mut h: Option<Box<Node<K,V>>>) -> Option<Box<Node<K,V>>> {
        let mut x = h.as_mut().map_or(None, |n| n.left.take());
        h.as_mut().map(|n| n.left = x.as_mut().map_or(None, |n| n.right.take()));
        x.as_mut().map(|n| n.right = h);
        x
    }

    fn rotate_left(mut h: Option<Box<Node<K,V>>>) -> Option<Box<Node<K,V>>> {
        let mut x = h.as_mut().map_or(None, |n| n.right.take());
        h.as_mut().map(|n| n.right = x.as_mut().map_or(None, |n| n.left.take()));
        x.as_mut().map(|n| n.left = h);
        x
    }
}

/// Splay tree. Supports splay-insert, -search, and -delete.
pub struct SplayTree<K,V> {
    root: Option<Box<Node<K,V>>>,
    // size: usize
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SplayTree<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.root.is_none() {
            write!(f, "<empty tree>")
        } else {
            self.root.as_ref().unwrap().dump(0, f, ' ');
            Ok(())
        }
    }
}

impl<K: PartialOrd, V> SplayTree<K,V> {
    pub fn new() -> SplayTree<K,V> {
        SplayTree {
            root: None,
            // size: 0
        }
    }

    pub fn is_empty(&self) -> bool {
        self.root.is_none()
    }

    pub fn size(&self) -> usize {
        Node::size(self.root.as_ref())
    }

    pub fn height(&self) -> usize {
        Node::height(self.root.as_ref())
    }

    pub fn clear(&mut self) {
        self.root = None;
    }

    // get() needs to update tree structure
    pub fn get(&mut self, key: &K) -> Option<&V> {
        self.root = Node::splay(self.root.take(), key);
        self.root.as_ref().map_or(None, |n| {
            if n.key == *key {
                Some(&n.val)
            } else {
                None
            }
        })
    }

    pub fn contains_key(&mut self, key: &K) -> bool {
        self.get(key).is_some()
    }

    pub fn get_mut<'t>(&'t mut self, key: &K) -> Option<&'t mut V> {
        self.root = Node::splay(self.root.take(), key);
        self.root.as_mut().map_or(None, |n| {
            if n.key == *key {
                Some(&mut n.val)
            } else {
                None
            }
        })
    }

    /// Splay tree insertion.
    pub fn insert(&mut self, key: K, val: V) {
        if self.root.is_none() {
            self.root = Some(Box::new(Node::new(key, val)));
            return;
        }

        let mut root = Node::splay(self.root.take(), &key);

        let cmp = compare(&key, &root.as_ref().unwrap().key);
        if cmp < 0 {
            let mut n = Node::new(key, val);
            n.left = root.as_mut().unwrap().left.take();
            n.right = root;
            self.root = Some(Box::new(n));
        } else if cmp > 0 {
            let mut n = Node::new(key, val);
            n.right = root.as_mut().unwrap().right.take();
            n.left = root;
            self.root = Some(Box::new(n));
        } else if cmp == 0{
            root.as_mut().map(|n| n.val = val);
            self.root = root;
        } else {
            unreachable!();
        }
    }

    /// Splay tree deletion.
    // use Algs4 approach
    pub fn remove(&mut self, key: &K) -> Option<V> {
        if self.root.is_none() {
            return None;
        }

        let mut root = Node::splay(self.root.take(), key);

        if *key == root.as_ref().unwrap().key {
            if root.as_ref().unwrap().left.is_none() {
                self.root = root.as_mut().unwrap().right.take();
            } else {
                let x = root.as_mut().unwrap().right.take();
                self.root = Node::splay(root.as_mut().unwrap().left.take(), key);
                self.root.as_mut().map(|n| n.right = x);
            }
            root.map(|n| n.val)
        } else {
            None
        }
    }
}

#[test]
fn test_splay_tree() {
    let mut st1 = SplayTree::new();
    assert!(st1.is_empty());
    st1.insert(5, 5);
    st1.insert(9, 9);
    st1.insert(13, 13);
    st1.insert(11, 11);
    st1.insert(1, 1);

    assert_eq!(5, st1.size());
    assert!(st1.height() < 5);
    for i in [5, 9, 13, 11, 1].iter() {
        assert_eq!(st1.get(i), Some(i));
    }

    st1.get_mut(&1).map(|val| *val = 1000);
    assert_eq!(st1.get(&1), Some(&1000));

    assert!(st1.remove(&9).is_some());
    assert!(st1.remove(&9).is_none());
    assert!(!st1.contains_key(&9));
}
<|endoftext|>


<commit_before>#![allow(unsafe_code)]

#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::io;
#[cfg(any(target_os = "linux"))]
use {std::fs::File, std::io::Read};

use std::convert::TryFrom;

/// See the Kernel's documentation for more information about this subsystem,
/// found at:  [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
///
/// If there's no memory limit specified on the container this may return
/// 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to 4k which is a common page size).
/// So we know we are not running in a memory restricted environment.
#[cfg(target_os = "linux")]
fn get_cgroup_memory_limit() -> io::Result<u64> {
    File::open("/sys/fs/cgroup/memory/memory.limit_in_bytes")
        .and_then(read_u64_from)
}

#[cfg(target_os = "linux")]
fn read_u64_from(mut file: File) -> io::Result<u64> {
    let mut s = String::new();
    file.read_to_string(&mut s).and_then(|_| {
        s.trim()
            .parse()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
    })
}

/// Returns the maximum size of total available memory of the process, in bytes.
/// If this limit is exceeded, the malloc() and mmap() functions shall fail with
/// errno set to [ENOMEM].
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_rlimit_as() -> io::Result<libc::rlimit> {
    let mut limit = std::mem::MaybeUninit::<libc::rlimit>::uninit();

    let ret = unsafe { libc::getrlimit(libc::RLIMIT_AS, limit.as_mut_ptr()) };

    if ret == 0 {
        Ok(unsafe { limit.assume_init() })
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn get_available_memory() -> io::Result<usize> {
    let pages = unsafe { libc::sysconf(libc::_SC_PHYS_PAGES) };
    if pages == -1 {
        return Err(io::Error::last_os_error());
    }

    let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
    if page_size == -1 {
        return Err(io::Error::last_os_error());
    }

    Ok(usize::try_from(pages).unwrap() * usize::try_from(page_size).unwrap())
}

pub fn get_memory_limit() -> Option<usize> {
    let mut max: u64 = 0;

    #[cfg(target_os = "linux")]
    {
        if let Ok(mem) = get_cgroup_memory_limit() {
            max = mem;
        }

        // If there's no memory limit specified on the container this
        // actually returns 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to
        // 4k which is a common page size). So we know we are not
        // running in a memory restricted environment.
        // src: https://github.com/dotnet/coreclr/blob/master/src/pal/src/misc/cgroup.cpp#L385-L428
        if max > 0x7FFF_FFFF_0000_0000 {
            return None;
        }
    }

    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        if let Ok(rlim) = get_rlimit_as() {
            let rlim_cur = rlim.rlim_cur;
            if max == 0 || rlim_cur < max {
                max = rlim_cur;
            }
        }

        if let Ok(available) = get_available_memory() {
            if max == 0 || (available as u64) < max {
                max = available as u64;
            }
        }
    }

    #[cfg(miri)]
    {
        // Miri has a significant memory consumption overhead. During a small
        // test run, a memory amplification of ~35x was observed. Certain
        // memory overheads may increase asymptotically with longer test runs,
        // such as the interpreter's dead_alloc_map. Memory overhead is
        // dominated by stacked borrows tags; the asymptotic behavior of this
        // overhead needs further investigation.
        max /= 40;
    }

    let ret = usize::try_from(max).expect("cache limit not representable");
    if ret == 0 {
        None
    } else {
        Some(ret)
    }
}
<commit_msg>Fix cross compilation<commit_after>#![allow(unsafe_code)]

#[cfg(any(target_os = "linux", target_os = "macos"))]
use std::io;
#[cfg(any(target_os = "linux"))]
use {std::fs::File, std::io::Read};

use std::convert::TryFrom;

/// See the Kernel's documentation for more information about this subsystem,
/// found at:  [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
///
/// If there's no memory limit specified on the container this may return
/// 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to 4k which is a common page size).
/// So we know we are not running in a memory restricted environment.
#[cfg(target_os = "linux")]
fn get_cgroup_memory_limit() -> io::Result<u64> {
    File::open("/sys/fs/cgroup/memory/memory.limit_in_bytes")
        .and_then(read_u64_from)
}

#[cfg(target_os = "linux")]
fn read_u64_from(mut file: File) -> io::Result<u64> {
    let mut s = String::new();
    file.read_to_string(&mut s).and_then(|_| {
        s.trim()
            .parse()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
    })
}

/// Returns the maximum size of total available memory of the process, in bytes.
/// If this limit is exceeded, the malloc() and mmap() functions shall fail with
/// errno set to [ENOMEM].
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_rlimit_as() -> io::Result<libc::rlimit> {
    let mut limit = std::mem::MaybeUninit::<libc::rlimit>::uninit();

    let ret = unsafe { libc::getrlimit(libc::RLIMIT_AS, limit.as_mut_ptr()) };

    if ret == 0 {
        Ok(unsafe { limit.assume_init() })
    } else {
        Err(io::Error::last_os_error())
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn get_available_memory() -> io::Result<usize> {
    let pages = unsafe { libc::sysconf(libc::_SC_PHYS_PAGES) };
    if pages == -1 {
        return Err(io::Error::last_os_error());
    }

    let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
    if page_size == -1 {
        return Err(io::Error::last_os_error());
    }

    Ok(usize::try_from(pages).unwrap() * usize::try_from(page_size).unwrap())
}

pub fn get_memory_limit() -> Option<usize> {
    let mut max: u64 = 0;

    #[cfg(target_os = "linux")]
    {
        if let Ok(mem) = get_cgroup_memory_limit() {
            max = mem;
        }

        // If there's no memory limit specified on the container this
        // actually returns 0x7FFFFFFFFFFFF000 (2^63-1 rounded down to
        // 4k which is a common page size). So we know we are not
        // running in a memory restricted environment.
        // src: https://github.com/dotnet/coreclr/blob/master/src/pal/src/misc/cgroup.cpp#L385-L428
        if max > 0x7FFF_FFFF_0000_0000 {
            return None;
        }
    }

    #[allow(clippy::useless_conversion)]
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        if let Ok(rlim) = get_rlimit_as() {
            let rlim_cur = u64::try_from(rlim.rlim_cur).unwrap();
            if max == 0 || rlim_cur < max {
                max = rlim_cur;
            }
        }

        if let Ok(available) = get_available_memory() {
            if max == 0 || (available as u64) < max {
                max = available as u64;
            }
        }
    }

    #[cfg(miri)]
    {
        // Miri has a significant memory consumption overhead. During a small
        // test run, a memory amplification of ~35x was observed. Certain
        // memory overheads may increase asymptotically with longer test runs,
        // such as the interpreter's dead_alloc_map. Memory overhead is
        // dominated by stacked borrows tags; the asymptotic behavior of this
        // overhead needs further investigation.
        max /= 40;
    }

    let ret = usize::try_from(max).expect("cache limit not representable");
    if ret == 0 {
        None
    } else {
        Some(ret)
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use BindServer;
use futures::stream::Stream;
use net2;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_service::NewService;

// TODO: Add more options, e.g.:
// - max concurrent requests
// - request timeout
// - read timeout
// - write timeout
// - max idle time
// - max lifetime

/// A builder for TCP servers.
///
/// Setting up a server needs, at minimum:
///
/// - A server protocol implementation
/// - An address
/// - A service to provide
///
/// In addition to those basics, the builder provides some additional
/// configuration, which is expected to grow over time.
///
/// See the crate docs for an example.
pub struct TcpServer<Kind, P> {
    _kind: PhantomData<Kind>,
    proto: Arc<P>,
    threads: usize,
    addr: SocketAddr,
}

impl<Kind, P> TcpServer<Kind, P> where
    P: BindServer<Kind, TcpStream> + Send + Sync + 'static
{
    /// Starts building a server for the given protocol and address, with
    /// default configuration.
    ///
    /// Generally, a protocol is implemented *not* by implementing the
    /// `BindServer` trait directly, but instead by implementing one of the
    /// protocol traits:
    ///
    /// - `pipeline::ServerProto`
    /// - `multiplex::ServerProto`
    /// - `streaming::pipeline::ServerProto`
    /// - `streaming::multiplex::ServerProto`
    ///
    /// See the crate documentation for more details on those traits.
    pub fn new(protocol: P, addr: SocketAddr) -> TcpServer<Kind, P> {
        TcpServer {
            _kind: PhantomData,
            proto: Arc::new(protocol),
            threads: 1,
            addr: addr,
        }
    }

    /// Set the address for the server.
    pub fn addr(&mut self, addr: SocketAddr) {
        self.addr = addr;
    }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService<Request = P::ServiceRequest,
                      Response = P::ServiceResponse,
                      Error = P::ServiceError> + Send + Sync + 'static,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService<Request = P::ServiceRequest,
                      Response = P::ServiceResponse,
                      Error = P::ServiceError> + Send + Sync + 'static,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService<Request = P::ServiceRequest,
                        Response = P::ServiceResponse,
                        Error = P::ServiceError> + 'static,
{
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, service);

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

#[cfg(unix)]
fn configure_tcp(workers: usize, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(workers: usize, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}
<commit_msg>Generalize TcpServer::serve's service a bit<commit_after>use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use BindServer;
use futures::stream::Stream;
use futures::future::{Then, Future};
use net2;
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_service::{NewService, Service};

// TODO: Add more options, e.g.:
// - max concurrent requests
// - request timeout
// - read timeout
// - write timeout
// - max idle time
// - max lifetime

/// A builder for TCP servers.
///
/// Setting up a server needs, at minimum:
///
/// - A server protocol implementation
/// - An address
/// - A service to provide
///
/// In addition to those basics, the builder provides some additional
/// configuration, which is expected to grow over time.
///
/// See the crate docs for an example.
pub struct TcpServer<Kind, P> {
    _kind: PhantomData<Kind>,
    proto: Arc<P>,
    threads: usize,
    addr: SocketAddr,
}

impl<Kind, P> TcpServer<Kind, P> where
    P: BindServer<Kind, TcpStream> + Send + Sync + 'static
{
    /// Starts building a server for the given protocol and address, with
    /// default configuration.
    ///
    /// Generally, a protocol is implemented *not* by implementing the
    /// `BindServer` trait directly, but instead by implementing one of the
    /// protocol traits:
    ///
    /// - `pipeline::ServerProto`
    /// - `multiplex::ServerProto`
    /// - `streaming::pipeline::ServerProto`
    /// - `streaming::multiplex::ServerProto`
    ///
    /// See the crate documentation for more details on those traits.
    pub fn new(protocol: P, addr: SocketAddr) -> TcpServer<Kind, P> {
        TcpServer {
            _kind: PhantomData,
            proto: Arc::new(protocol),
            threads: 1,
            addr: addr,
        }
    }

    /// Set the address for the server.
    pub fn addr(&mut self, addr: SocketAddr) {
        self.addr = addr;
    }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService + Send + Sync + 'static,
        S::Instance: 'static,
        P::ServiceError: 'static,
        P::ServiceResponse: 'static,
        P::ServiceRequest: 'static,
        S::Request: From<P::ServiceRequest>,
        S::Response: Into<P::ServiceResponse>,
        S::Error: Into<P::ServiceError>,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService + Send + Sync,
          S::Instance: 'static,
          P::ServiceError: 'static,
          P::ServiceResponse: 'static,
          P::ServiceRequest: 'static,
          S::Request: From<P::ServiceRequest>,
          S::Response: Into<P::ServiceResponse>,
          S::Error: Into<P::ServiceError>,
{
    struct WrapService<S, Request, Response, Error> {
        inner: S,
        _marker: PhantomData<fn() -> (Request, Response, Error)>,
    }

    impl<S, Request, Response, Error> Service for WrapService<S, Request, Response, Error>
        where S: Service,
              S::Request: From<Request>,
              S::Response: Into<Response>,
              S::Error: Into<Error>,
    {
        type Request = Request;
        type Response = Response;
        type Error = Error;
        type Future = Then<S::Future,
                           Result<Response, Error>,
                           fn(Result<S::Response, S::Error>) -> Result<Response, Error>>;

        fn call(&self, req: Request) -> Self::Future {
            fn change_types<A, B, C, D>(r: Result<A, B>) -> Result<C, D>
                where A: Into<C>,
                      B: Into<D>,
            {
                match r {
                    Ok(e) => Ok(e.into()),
                    Err(e) => Err(e.into()),
                }
            }

            self.inner.call(S::Request::from(req)).then(change_types)
        }
    }

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, WrapService {
            inner: service,
            _marker: PhantomData,
        });

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

#[cfg(unix)]
fn configure_tcp(workers: usize, tcp: &net2::TcpBuilder) -> io::Result<()> {
    use net2::unix::*;

    if workers > 1 {
        try!(tcp.reuse_port(true));
    }

    Ok(())
}

#[cfg(windows)]
fn configure_tcp(workers: usize, _tcp: &net2::TcpBuilder) -> io::Result<()> {
    Ok(())
}
<|endoftext|>


<commit_before>//! [GET /_matrix/federation/v1/publicRooms](https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-publicrooms)

use std::fmt;

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::{RoomAliasId, RoomId};
use serde::{
    de::{Error as _, MapAccess, Visitor},
    ser::SerializeStruct,
    Deserialize, Deserializer, Serialize, Serializer,
};

ruma_api! {
    metadata: {
        description: "Gets all the public rooms for the homeserver.",
        method: GET,
        name: "get_public_rooms",
        path: "/_matrix/federation/v1/publicRooms",
        rate_limited: false,
        requires_authentication: true,
    }

    request: {
        /// The maximum number of rooms to return. Default is no limit.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub limit: Option<UInt>,
        /// Pagination token from a previous request.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub since: Option<String>,
        /// Network to fetch the public room lists from.
        #[serde(flatten, skip_serializing_if = "ruma_serde::is_default")]
        #[ruma_api(query)]
        pub room_network: RoomNetwork,
    }

    response: {
        /// A paginated chunk of public rooms.
        pub chunk: Vec<PublicRoomsChunk>,
        /// A pagination token for the response.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub next_batch: Option<String>,
        /// A pagination token that allows fetching previous results.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub prev_batch: Option<String>,
        /// An estimate on the total number of public rooms, if the server has an estimate.
        pub total_room_count_estimate: Option<UInt>,
    }
}

/// A chunk of a room list response, describing one room
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PublicRoomsChunk {
    /// Aliases of the room.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub aliases: Vec<RoomAliasId>,
    /// The canonical alias of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub canonical_alias: Option<String>,
    /// The name of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// The number of members joined to the room.
    pub num_joined_members: UInt,
    /// The ID of the room.
    pub room_id: RoomId,
    /// The topic of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,
    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,
    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,
    /// The URL for the room's avatar, if one is set.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub avatar_url: Option<String>,
}

/// Information about which networks/protocols from application services on the
/// homeserver from which to request rooms.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RoomNetwork {
    /// Return rooms from the Matrix network.
    Matrix,
    /// Return rooms from all the networks/protocols the homeserver knows about.
    All,
    /// Return rooms from a specific third party network/protocol.
    ThirdParty(String),
}

impl Default for RoomNetwork {
    fn default() -> Self {
        RoomNetwork::Matrix
    }
}

impl Serialize for RoomNetwork {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state;
        match self {
            Self::Matrix => {
                state = serializer.serialize_struct("RoomNetwork", 0)?;
            }
            Self::All => {
                state = serializer.serialize_struct("RoomNetwork", 1)?;
                state.serialize_field("include_all_networks", &true)?;
            }
            Self::ThirdParty(network) => {
                state = serializer.serialize_struct("RoomNetwork", 1)?;
                state.serialize_field("third_party_instance_id", network)?;
            }
        }
        state.end()
    }
}

impl<'de> Deserialize<'de> for RoomNetwork {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_map(RoomNetworkVisitor)
    }
}

struct RoomNetworkVisitor;
impl<'de> Visitor<'de> for RoomNetworkVisitor {
    type Value = RoomNetwork;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Network selection")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut include_all_networks = false;
        let mut third_party_instance_id = None;
        while let Some((key, value)) = access.next_entry::<String, serde_json::Value>()? {
            match key.as_str() {
                "include_all_networks" => {
                    include_all_networks = match value.as_bool() {
                        Some(b) => b,
                        _ => false,
                    }
                }
                "third_party_instance_id" => {
                    third_party_instance_id = value.as_str().map(|v| v.to_owned())
                }
                _ => {}
            };
        }

        if include_all_networks {
            if third_party_instance_id.is_none() {
                Ok(RoomNetwork::All)
            } else {
                Err(M::Error::custom(
                    "`include_all_networks = true` and `third_party_instance_id` are mutually \
                     exclusive.",
                ))
            }
        } else {
            Ok(match third_party_instance_id {
                Some(network) => RoomNetwork::ThirdParty(network),
                None => RoomNetwork::Matrix,
            })
        }
    }
}
<commit_msg>Fix canonical alias type<commit_after>//! [GET /_matrix/federation/v1/publicRooms](https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-publicrooms)

use std::fmt;

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::{RoomAliasId, RoomId};
use serde::{
    de::{Error as _, MapAccess, Visitor},
    ser::SerializeStruct,
    Deserialize, Deserializer, Serialize, Serializer,
};

ruma_api! {
    metadata: {
        description: "Gets all the public rooms for the homeserver.",
        method: GET,
        name: "get_public_rooms",
        path: "/_matrix/federation/v1/publicRooms",
        rate_limited: false,
        requires_authentication: true,
    }

    request: {
        /// The maximum number of rooms to return. Default is no limit.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub limit: Option<UInt>,
        /// Pagination token from a previous request.
        #[serde(skip_serializing_if = "Option::is_none")]
        #[ruma_api(query)]
        pub since: Option<String>,
        /// Network to fetch the public room lists from.
        #[serde(flatten, skip_serializing_if = "ruma_serde::is_default")]
        #[ruma_api(query)]
        pub room_network: RoomNetwork,
    }

    response: {
        /// A paginated chunk of public rooms.
        pub chunk: Vec<PublicRoomsChunk>,
        /// A pagination token for the response.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub next_batch: Option<String>,
        /// A pagination token that allows fetching previous results.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub prev_batch: Option<String>,
        /// An estimate on the total number of public rooms, if the server has an estimate.
        pub total_room_count_estimate: Option<UInt>,
    }
}

/// A chunk of a room list response, describing one room
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PublicRoomsChunk {
    /// Aliases of the room.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub aliases: Vec<RoomAliasId>,
    /// The canonical alias of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub canonical_alias: Option<RoomAliasId>,
    /// The name of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// The number of members joined to the room.
    pub num_joined_members: UInt,
    /// The ID of the room.
    pub room_id: RoomId,
    /// The topic of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,
    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,
    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,
    /// The URL for the room's avatar, if one is set.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub avatar_url: Option<String>,
}

/// Information about which networks/protocols from application services on the
/// homeserver from which to request rooms.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RoomNetwork {
    /// Return rooms from the Matrix network.
    Matrix,
    /// Return rooms from all the networks/protocols the homeserver knows about.
    All,
    /// Return rooms from a specific third party network/protocol.
    ThirdParty(String),
}

impl Default for RoomNetwork {
    fn default() -> Self {
        RoomNetwork::Matrix
    }
}

impl Serialize for RoomNetwork {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state;
        match self {
            Self::Matrix => {
                state = serializer.serialize_struct("RoomNetwork", 0)?;
            }
            Self::All => {
                state = serializer.serialize_struct("RoomNetwork", 1)?;
                state.serialize_field("include_all_networks", &true)?;
            }
            Self::ThirdParty(network) => {
                state = serializer.serialize_struct("RoomNetwork", 1)?;
                state.serialize_field("third_party_instance_id", network)?;
            }
        }
        state.end()
    }
}

impl<'de> Deserialize<'de> for RoomNetwork {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_map(RoomNetworkVisitor)
    }
}

struct RoomNetworkVisitor;
impl<'de> Visitor<'de> for RoomNetworkVisitor {
    type Value = RoomNetwork;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Network selection")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut include_all_networks = false;
        let mut third_party_instance_id = None;
        while let Some((key, value)) = access.next_entry::<String, serde_json::Value>()? {
            match key.as_str() {
                "include_all_networks" => {
                    include_all_networks = match value.as_bool() {
                        Some(b) => b,
                        _ => false,
                    }
                }
                "third_party_instance_id" => {
                    third_party_instance_id = value.as_str().map(|v| v.to_owned())
                }
                _ => {}
            };
        }

        if include_all_networks {
            if third_party_instance_id.is_none() {
                Ok(RoomNetwork::All)
            } else {
                Err(M::Error::custom(
                    "`include_all_networks = true` and `third_party_instance_id` are mutually \
                     exclusive.",
                ))
            }
        } else {
            Ok(match third_party_instance_id {
                Some(network) => RoomNetwork::ThirdParty(network),
                None => RoomNetwork::Matrix,
            })
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate serde;
extern crate regex;
extern crate docopt;
extern crate rustc_serialize;
extern crate env_logger;
extern crate ansi_term;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[macro_use]
extern crate sonicd;
extern crate rpassword;
extern crate pbr;

mod util {
    #[cfg(feature = "serde_macros")]
    include!("util.rs.in");

    #[cfg(not(feature = "serde_macros"))]
    include!(concat!(env!("OUT_DIR"), "/util.rs"));
}

use std::path::PathBuf;
use std::process;
use std::io::{Write, stderr, stdout};
use std::cell::RefCell;

use docopt::Docopt;
use pbr::ProgressBar;
use sonicd::SonicMessage;
use rpassword::read_password;

#[cfg_attr(rustfmt, rustfmt_skip)]
const USAGE: &'static str = "
.
                           d8b
                           Y8P

.d8888b   .d88b.  88888b.  888  .d8888b
88K      d88\"\"88b 888 \"88b 888 d88P\"
\"Y8888b. 888  888 888  888 888 888
     X88 Y88..88P 888  888 888 Y88b.
 88888P'  \"Y88P\"  888  888 888  \"Y8888P

Usage:
  sonic <source> [-d <foo=bar>...] [options] -e <query>
  sonic <source> [-d <foo=bar>...] [options] -f <file>
  sonic login [options]
  sonic -h | --help
  sonic --version

Options:
  -e, --execute         Run command literal
  -f, --file            Run command from file
  -c <config>           Use a different configuration file (default: $HOME/.sonicrc)
  -d <foo=bar>          Replace variable in query in the form of `${foo}` with value `var`
  -r, --rows-only       Skip printing column names
  -S, --silent          Skip printing query progress bar
  -v, --verbose         Enable debug logging
  -h, --help            Print this message
  --version             Print version
";

static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static COMMIT: Option<&'static str> = option_env!("SONIC_COMMIT");

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_file: String,
    arg_query: String,
    flag_silent: bool,
    flag_rows_only: bool,
    flag_d: Vec<String>,
    flag_file: bool,
    flag_c: String,
    flag_verbose: bool,
    arg_source: String,
    cmd_login: bool,
    flag_execute: bool,
    flag_version: bool,
    flag_help: bool,
}

error_chain! {
    types {
        Error, ErrorKind, ChainErr, Result;
    }

    links {
        sonicd::Error, sonicd::ErrorKind, SonicdError;
    }

    foreign_links {
        ::std::io::Error, IoError, "I/O operation failed";
        ::serde_json::Error, Json, "JSON serialization/deserialization error";
        ::std::sync::mpsc::RecvError, RecvError, "Channel receive error";
    }

    errors {
        InvalidFormat(co: String, msg: String) {
            description("invalid format error")
                display("invalid format {}: {}", co, msg)
        }
    }
}

fn hide<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = false;
    pb.show_speed = false;
    pb.show_percent = false;
    pb.show_counter = false;
    pb.show_time_left = false;
    pb.show_tick = false;
    pb.show_message = false;
}

fn show<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = true;
    pb.show_speed = false;
    pb.show_percent = true;
    pb.show_counter = true;
    pb.show_time_left = true;
    pb.show_tick = true;
    pb.show_message = true;
}

fn exec(host: &str, port: &u16, query: SonicMessage, rows_only: bool, silent: bool) -> Result<()> {

    let out = RefCell::new(stdout());
    let mut buf: Vec<SonicMessage> = Vec::new();
    let mut pb = ProgressBar::on(stderr(), 0);
    pb.format("╢░░_╟");
    pb.tick_format("▀▐▄▌");
    show(&mut pb);

    let (tx, rx) = ::std::sync::mpsc::channel();

    try!(sonicd::stream((host, *port), query, tx));

    let draw = |b: &mut Vec<SonicMessage>| {
        let len = b.len();
        for msg in b.drain(..len) {
            let cols = match msg {
                SonicMessage::OutputChunk(data) => {
                    data.iter().fold(String::new(), |acc, val| format!("{}{:?}\t", acc, val))
                }
                SonicMessage::TypeMetadata(data) => {
                    data.iter().fold(String::new(), |acc, col| format!("{}{:?}\t", acc, col.0))
                }
                _ => panic!("not possible!"),
            };
            let row = format!("{}\n", cols.trim_right());
            let mut bout = out.borrow_mut();
            bout.write_all(row.as_bytes()).unwrap();
            bout.flush().unwrap();
        }
    };

    let res: Result<()>;

    loop {
        match try!(rx.recv()) {
            Ok(msg @ SonicMessage::TypeMetadata(_)) => {
                if !rows_only {
                    buf.push(msg);
                }
            }
            Ok(msg @ SonicMessage::OutputChunk(_)) => {
                buf.push(msg);
                if !silent && !pb.is_finish {
                    // tick format breaks suffix length
                    // so we need to disable it before finishing bar
                    hide(&mut pb);
                    pb.tick();
                    pb.finish();
                }
                draw(&mut buf);
            }
            Ok(SonicMessage::QueryProgress { status, progress, total, .. }) => {
                if !silent && !pb.is_finish {

                    pb.message(&format!("{:?} ", status));
                    debug!("{:?}: {:?}/{:?}", status, progress, total);

                    if let Some(total) = total {
                        pb.total = total as u64;
                    }

                    if progress >= 1.0 {
                        pb.add(progress as u64);
                    } else {
                        pb.tick();
                    };
                }
            }
            Ok(SonicMessage::Done(None)) => {
                res = Ok(());
                break;
            }
            Ok(SonicMessage::Done(Some(e))) => {
                res = Err(e.into());
                break;
            }
            Err(e) => {
                res = Err(e.into());
                break;
            }
            Ok(a) => debug!("ignoring msg {:?}", a),
        }
    }

    draw(&mut buf);

    res
}

pub fn login(host: &str, tcp_port: &u16) -> Result<()> {

    let user = std::env::var("USER")
        .unwrap_or("unknown".to_owned());

    try!(stdout().write(b"Enter key: "));
    try!(stdout().flush());

    let key = try!(read_password());

    let (tx, rx) = ::std::sync::mpsc::channel();

    let cmd = SonicMessage::Authenticate {
        key: key,
        user: user.to_owned(),
        trace_id: None,
    };

    try!(sonicd::stream((host, *tcp_port), cmd, tx));

    let token: String;

    loop {
        match try!(rx.recv()) {
            Ok(SonicMessage::OutputChunk(data)) => {
                token = try!(util::parse_token(data));
                break;
            }
            Ok(_) => {},
            Err(e) => {
                return Err(e.into())
            }
        };
    }

    debug!("generated token for user {:?}: {:?}", &user, &token);

    let path = util::get_config_path();
    let config = try!(util::read_config(&path));

    let new_config = util::ClientConfig { auth: Some(token), ..config };

    try!(util::write_config(&new_config, &path));

    println!("OK");
    Ok(())
}

fn _main(args: Args) -> Result<()> {

    let Args { arg_file,
               arg_query,
               flag_silent,
               flag_rows_only,
               flag_d,
               flag_file,
               flag_c,
               arg_source,
               cmd_login,
               flag_execute,
               flag_version,
               .. } = args;

    let util::ClientConfig { sonicd, tcp_port, sources, auth } = if flag_c != "" {
        debug!("sourcing passed config in path '{:?}'", &flag_c);
        try!(util::read_config(&PathBuf::from(flag_c)))
    } else {
        debug!("sourcing default config in path '$HOME/.sonicrc'");
        try!(util::get_default_config())
    };

    if flag_file {

        let query_str = try!(util::read_file_contents(&PathBuf::from(&arg_file)));
        let split = try!(util::split_key_value(&flag_d));
        let injected = try!(util::inject_vars(&query_str, &split));
        let query = try!(util::build(arg_source, sources, auth, injected));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if flag_execute {

        let query = try!(util::build(arg_source, sources, auth, arg_query));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if cmd_login {

        login(&sonicd, &tcp_port)

    } else if flag_version {

        println!("Sonic CLI version {} ({})",
                 VERSION,
                 COMMIT.unwrap_or_else(|| "dev"));

        Ok(())

    } else {

        panic!("unexpected args");

    }
}

fn main() {

    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let verbose: bool = args.flag_verbose;

    if verbose {
        let mut builder = env_logger::LogBuilder::new();
        builder.parse("debug");
        builder.init().unwrap();
    } else {
        env_logger::init().unwrap();
    }

    debug!("parsed args {:?}", args);

    match _main(args) {
        Ok(_) => {}
        Err(e) => {
            util::report_error(&e, verbose);
            process::exit(1)
        }
    }
}
<commit_msg>cli: fixed done handling on authenticate cmd<commit_after>extern crate serde_json;
extern crate serde;
extern crate regex;
extern crate docopt;
extern crate rustc_serialize;
extern crate env_logger;
extern crate ansi_term;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[macro_use]
extern crate sonicd;
extern crate rpassword;
extern crate pbr;

mod util {
    #[cfg(feature = "serde_macros")]
    include!("util.rs.in");

    #[cfg(not(feature = "serde_macros"))]
    include!(concat!(env!("OUT_DIR"), "/util.rs"));
}

use std::path::PathBuf;
use std::process;
use std::io::{Write, stderr, stdout};
use std::cell::RefCell;

use docopt::Docopt;
use pbr::ProgressBar;
use sonicd::SonicMessage;
use rpassword::read_password;

#[cfg_attr(rustfmt, rustfmt_skip)]
const USAGE: &'static str = "
.
                           d8b
                           Y8P

.d8888b   .d88b.  88888b.  888  .d8888b
88K      d88\"\"88b 888 \"88b 888 d88P\"
\"Y8888b. 888  888 888  888 888 888
     X88 Y88..88P 888  888 888 Y88b.
 88888P'  \"Y88P\"  888  888 888  \"Y8888P

Usage:
  sonic <source> [-d <foo=bar>...] [options] -e <query>
  sonic <source> [-d <foo=bar>...] [options] -f <file>
  sonic login [options]
  sonic -h | --help
  sonic --version

Options:
  -e, --execute         Run command literal
  -f, --file            Run command from file
  -c <config>           Use a different configuration file (default: $HOME/.sonicrc)
  -d <foo=bar>          Replace variable in query in the form of `${foo}` with value `var`
  -r, --rows-only       Skip printing column names
  -S, --silent          Skip printing query progress bar
  -v, --verbose         Enable debug logging
  -h, --help            Print this message
  --version             Print version
";

static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static COMMIT: Option<&'static str> = option_env!("SONIC_COMMIT");

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_file: String,
    arg_query: String,
    flag_silent: bool,
    flag_rows_only: bool,
    flag_d: Vec<String>,
    flag_file: bool,
    flag_c: String,
    flag_verbose: bool,
    arg_source: String,
    cmd_login: bool,
    flag_execute: bool,
    flag_version: bool,
    flag_help: bool,
}

error_chain! {
    types {
        Error, ErrorKind, ChainErr, Result;
    }

    links {
        sonicd::Error, sonicd::ErrorKind, SonicdError;
    }

    foreign_links {
        ::std::io::Error, IoError, "I/O operation failed";
        ::serde_json::Error, Json, "JSON serialization/deserialization error";
        ::std::sync::mpsc::RecvError, RecvError, "Channel receive error";
    }

    errors {
        InvalidFormat(co: String, msg: String) {
            description("invalid format error")
                display("invalid format {}: {}", co, msg)
        }
    }
}

fn hide<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = false;
    pb.show_speed = false;
    pb.show_percent = false;
    pb.show_counter = false;
    pb.show_time_left = false;
    pb.show_tick = false;
    pb.show_message = false;
}

fn show<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = true;
    pb.show_speed = false;
    pb.show_percent = true;
    pb.show_counter = true;
    pb.show_time_left = true;
    pb.show_tick = true;
    pb.show_message = true;
}

fn exec(host: &str, port: &u16, query: SonicMessage, rows_only: bool, silent: bool) -> Result<()> {

    let out = RefCell::new(stdout());
    let mut buf: Vec<SonicMessage> = Vec::new();
    let mut pb = ProgressBar::on(stderr(), 0);
    pb.format("╢░░_╟");
    pb.tick_format("▀▐▄▌");
    show(&mut pb);

    let (tx, rx) = ::std::sync::mpsc::channel();

    try!(sonicd::stream((host, *port), query, tx));

    let draw = |b: &mut Vec<SonicMessage>| {
        let len = b.len();
        for msg in b.drain(..len) {
            let cols = match msg {
                SonicMessage::OutputChunk(data) => {
                    data.iter().fold(String::new(), |acc, val| format!("{}{:?}\t", acc, val))
                }
                SonicMessage::TypeMetadata(data) => {
                    data.iter().fold(String::new(), |acc, col| format!("{}{:?}\t", acc, col.0))
                }
                _ => panic!("not possible!"),
            };
            let row = format!("{}\n", cols.trim_right());
            let mut bout = out.borrow_mut();
            bout.write_all(row.as_bytes()).unwrap();
            bout.flush().unwrap();
        }
    };

    let res: Result<()>;

    loop {
        match try!(rx.recv()) {
            Ok(msg @ SonicMessage::TypeMetadata(_)) => {
                if !rows_only {
                    buf.push(msg);
                }
            }
            Ok(msg @ SonicMessage::OutputChunk(_)) => {
                buf.push(msg);
                if !silent && !pb.is_finish {
                    // tick format breaks suffix length
                    // so we need to disable it before finishing bar
                    hide(&mut pb);
                    pb.tick();
                    pb.finish();
                }
                draw(&mut buf);
            }
            Ok(SonicMessage::QueryProgress { status, progress, total, .. }) => {
                if !silent && !pb.is_finish {

                    pb.message(&format!("{:?} ", status));
                    debug!("{:?}: {:?}/{:?}", status, progress, total);

                    if let Some(total) = total {
                        pb.total = total as u64;
                    }

                    if progress >= 1.0 {
                        pb.add(progress as u64);
                    } else {
                        pb.tick();
                    };
                }
            }
            Ok(SonicMessage::Done(None)) => {
                res = Ok(());
                break;
            }
            Ok(SonicMessage::Done(Some(e))) => {
                res = Err(e.into());
                break;
            }
            Err(e) => {
                res = Err(e.into());
                break;
            }
            Ok(a) => debug!("ignoring msg {:?}", a),
        }
    }

    draw(&mut buf);

    res
}

pub fn login(host: &str, tcp_port: &u16) -> Result<()> {

    let user = std::env::var("USER")
        .unwrap_or("unknown".to_owned());

    try!(stdout().write(b"Enter key: "));
    try!(stdout().flush());

    let key = try!(read_password());

    let (tx, rx) = ::std::sync::mpsc::channel();

    let cmd = SonicMessage::Authenticate {
        key: key,
        user: user.to_owned(),
        trace_id: None,
    };

    try!(sonicd::stream((host, *tcp_port), cmd, tx));

    let token: String;

    loop {
        match try!(rx.recv()) {
            Ok(SonicMessage::OutputChunk(data)) => {
                token = try!(util::parse_token(data));
                break;
            }
            Ok(SonicMessage::Done(None)) => {
                return Err("protocol error: no data returned from the server".into());
            },
            Ok(SonicMessage::Done(Some(e))) => {
                return Err(e.into());
            },
            Ok(_) => {},
            Err(e) => {
                return Err(e.into())
            }
        };
    }

    debug!("generated token for user {:?}: {:?}", &user, &token);

    let path = util::get_config_path();
    let config = try!(util::read_config(&path));

    let new_config = util::ClientConfig { auth: Some(token), ..config };

    try!(util::write_config(&new_config, &path));

    println!("OK");
    Ok(())
}

fn _main(args: Args) -> Result<()> {

    let Args { arg_file,
               arg_query,
               flag_silent,
               flag_rows_only,
               flag_d,
               flag_file,
               flag_c,
               arg_source,
               cmd_login,
               flag_execute,
               flag_version,
               .. } = args;

    let util::ClientConfig { sonicd, tcp_port, sources, auth } = if flag_c != "" {
        debug!("sourcing passed config in path '{:?}'", &flag_c);
        try!(util::read_config(&PathBuf::from(flag_c)))
    } else {
        debug!("sourcing default config in path '$HOME/.sonicrc'");
        try!(util::get_default_config())
    };

    if flag_file {

        let query_str = try!(util::read_file_contents(&PathBuf::from(&arg_file)));
        let split = try!(util::split_key_value(&flag_d));
        let injected = try!(util::inject_vars(&query_str, &split));
        let query = try!(util::build(arg_source, sources, auth, injected));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if flag_execute {

        let query = try!(util::build(arg_source, sources, auth, arg_query));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if cmd_login {

        login(&sonicd, &tcp_port)

    } else if flag_version {

        println!("Sonic CLI version {} ({})",
                 VERSION,
                 COMMIT.unwrap_or_else(|| "dev"));

        Ok(())

    } else {

        panic!("unexpected args");

    }
}

fn main() {

    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let verbose: bool = args.flag_verbose;

    if verbose {
        let mut builder = env_logger::LogBuilder::new();
        builder.parse("debug");
        builder.init().unwrap();
    } else {
        env_logger::init().unwrap();
    }

    debug!("parsed args {:?}", args);

    match _main(args) {
        Ok(_) => {}
        Err(e) => {
            util::report_error(&e, verbose);
            process::exit(1)
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
#[macro_use]
extern crate meta;

#[cfg_attr(feature="clippy", allow(needless_range_loop))]
fn pancake_sort<T: Ord>(mut v: &mut [T]) {
    let len = v.len();
    // trivial case -- no flips
    if len < 2 {
        return;
    }
    for i in (1..len + 1).rev() {
        // find index of maximum from 0 to i
        let mut max_index = 0;
        for j in 0..i {
            if v[max_index] < v[j] {
                max_index = j;
            }
        }
        // if max_index is not where it's supposed to be
        // do two flips to move it to i - 1
        if max_index != i - 1 {
            flip(&mut v, max_index);
            flip(&mut v, i - 1);
        }
    }
}

// function to flip a section of a mutable collection from 0..num
fn flip<E: PartialOrd>(v: &mut [E], num: usize) {
    for i in 0..(num + 1) / 2 {
        v.swap(i, num - i);
    }
}

fn main() {
    // Sort numbers
    let mut numbers = [4i32, 65, 2, -31, 0, 99, 2, 83, 782, 1];
    println!("Before: {:?}", numbers);
    pancake_sort(&mut numbers);
    println!("After: {:?}", numbers);
    // Sort strings
    let mut strings = ["beach", "hotel", "airplane", "car", "house", "art"];
    println!("Before: {:?}", strings);
    pancake_sort(&mut strings);
    println!("After: {:?}", strings);
}

#[cfg(test)]
mod tests {
    test_sort!(super::pancake_sort);
}
<commit_msg>Update pancake sort<commit_after>#[cfg(test)]
#[macro_use]
extern crate meta;

fn pancake_sort<T: Ord>(v: &mut [T]) {
    let len = v.len();
    // trivial case -- no flips
    if len < 2 {
        return;
    }
    for i in (0..len).rev() {
        // find index of the maximum element within `v[0..i]` (inclusive)
        let max_index = v.iter()
            .take(i + 1)
            .enumerate()
            .max_by_key(|&(_, elem)| elem)
            .map(|(idx, _)| idx)
            // safe because we already checked if `v` is empty
            .unwrap();
        // if `max_index` is not where it's supposed to be
        // do two flips to move it to `i`
        if max_index != i {
            flip(v, max_index);
            flip(v, i);
        }
    }
}

// function to flip a section of a mutable collection from 0..num (inclusive)
fn flip<E: PartialOrd>(v: &mut [E], num: usize) {
    v[0..num + 1].reverse();
}

fn main() {
    // Sort numbers
    let mut numbers = [4, 65, 2, -31, 0, 99, 2, 83, 782, 1];
    println!("Before: {:?}", numbers);
    pancake_sort(&mut numbers);
    println!("After: {:?}", numbers);

    // Sort strings
    let mut strings = ["beach", "hotel", "airplane", "car", "house", "art"];
    println!("Before: {:?}", strings);
    pancake_sort(&mut strings);
    println!("After: {:?}", strings);
}

#[cfg(test)]
mod tests {
    test_sort!(super::pancake_sort);
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::{FloatTy, Lit, LitKind};
use crate::syntax::symbol;
use crate::utils::span_lint;
use std::f64::consts as f64;

/// **What it does:** Checks for floating point literals that approximate
/// constants which are defined in
/// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
/// or
/// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
/// respectively, suggesting to use the predefined constant.
///
/// **Why is this bad?** Usually, the definition in the standard library is more
/// precise than what people come up with. If you find that your definition is
/// actually more precise, please [file a Rust
/// issue](https://github.com/rust-lang/rust/issues).
///
/// **Known problems:** If you happen to have a value that is within 1/8192 of a
/// known constant, but is not *and should not* be the same, this lint will
/// report your value anyway. We have not yet noticed any false positives in
/// code we tested clippy with (this includes servo), but YMMV.
///
/// **Example:**
/// ```rust
/// let x = 3.14;
/// ```
declare_clippy_lint! {
    pub APPROX_CONSTANT,
    correctness,
    "the approximate of a known float constant (in `std::fXX::consts`)"
}

// Tuples are of the form (constant, name, min_digits)
const KNOWN_CONSTS: &[(f64, &str, usize)] = &[
    (f64::E, "E", 4),
    (f64::FRAC_1_PI, "FRAC_1_PI", 4),
    (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5),
    (f64::FRAC_2_PI, "FRAC_2_PI", 5),
    (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5),
    (f64::FRAC_PI_2, "FRAC_PI_2", 5),
    (f64::FRAC_PI_3, "FRAC_PI_3", 5),
    (f64::FRAC_PI_4, "FRAC_PI_4", 5),
    (f64::FRAC_PI_6, "FRAC_PI_6", 5),
    (f64::FRAC_PI_8, "FRAC_PI_8", 5),
    (f64::LN_10, "LN_10", 5),
    (f64::LN_2, "LN_2", 5),
    (f64::LOG10_E, "LOG10_E", 5),
    (f64::LOG2_E, "LOG2_E", 5),
    (f64::PI, "PI", 3),
    (f64::SQRT_2, "SQRT_2", 5),
];

#[derive(Copy, Clone)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(APPROX_CONSTANT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprKind::Lit(ref lit) = e.node {
            check_lit(cx, lit, e);
        }
    }
}

fn check_lit(cx: &LateContext<'_, '_>, lit: &Lit, e: &Expr) {
    match lit.node {
        LitKind::Float(s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"),
        LitKind::Float(s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"),
        LitKind::FloatUnsuffixed(s) => check_known_consts(cx, e, s, "f{32, 64}"),
        _ => (),
    }
}

fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, module: &str) {
    let s = s.as_str();
    if s.parse::<f64>().is_ok() {
        for &(constant, name, min_digits) in KNOWN_CONSTS {
            if is_approx_const(constant, &s, min_digits) {
                span_lint(
                    cx,
                    APPROX_CONSTANT,
                    e.span,
                    &format!(
                        "approximate value of `{}::consts::{}` found. \
                         Consider using it directly",
                        module, &name
                    ),
                );
                return;
            }
        }
    }
}

/// Returns false if the number of significant figures in `value` are
/// less than `min_digits`; otherwise, returns true if `value` is equal
/// to `constant`, rounded to the number of digits present in `value`.
fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
    if value.len() <= min_digits {
        false
    } else {
        let round_const = format!("{:.*}", value.len() - 2, constant);

        let mut trunc_const = constant.to_string();
        if trunc_const.len() > value.len() {
            trunc_const.truncate(value.len());
        }

        (value == round_const) || (value == trunc_const)
    }
}
<commit_msg>Use match ergonomics for approx_const lint<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::{FloatTy, Lit, LitKind};
use crate::syntax::symbol;
use crate::utils::span_lint;
use std::f64::consts as f64;

/// **What it does:** Checks for floating point literals that approximate
/// constants which are defined in
/// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
/// or
/// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
/// respectively, suggesting to use the predefined constant.
///
/// **Why is this bad?** Usually, the definition in the standard library is more
/// precise than what people come up with. If you find that your definition is
/// actually more precise, please [file a Rust
/// issue](https://github.com/rust-lang/rust/issues).
///
/// **Known problems:** If you happen to have a value that is within 1/8192 of a
/// known constant, but is not *and should not* be the same, this lint will
/// report your value anyway. We have not yet noticed any false positives in
/// code we tested clippy with (this includes servo), but YMMV.
///
/// **Example:**
/// ```rust
/// let x = 3.14;
/// ```
declare_clippy_lint! {
    pub APPROX_CONSTANT,
    correctness,
    "the approximate of a known float constant (in `std::fXX::consts`)"
}

// Tuples are of the form (constant, name, min_digits)
const KNOWN_CONSTS: &[(f64, &str, usize)] = &[
    (f64::E, "E", 4),
    (f64::FRAC_1_PI, "FRAC_1_PI", 4),
    (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5),
    (f64::FRAC_2_PI, "FRAC_2_PI", 5),
    (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5),
    (f64::FRAC_PI_2, "FRAC_PI_2", 5),
    (f64::FRAC_PI_3, "FRAC_PI_3", 5),
    (f64::FRAC_PI_4, "FRAC_PI_4", 5),
    (f64::FRAC_PI_6, "FRAC_PI_6", 5),
    (f64::FRAC_PI_8, "FRAC_PI_8", 5),
    (f64::LN_10, "LN_10", 5),
    (f64::LN_2, "LN_2", 5),
    (f64::LOG10_E, "LOG10_E", 5),
    (f64::LOG2_E, "LOG2_E", 5),
    (f64::PI, "PI", 3),
    (f64::SQRT_2, "SQRT_2", 5),
];

#[derive(Copy, Clone)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(APPROX_CONSTANT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprKind::Lit(lit) = &e.node {
            check_lit(cx, lit, e);
        }
    }
}

fn check_lit(cx: &LateContext<'_, '_>, lit: &Lit, e: &Expr) {
    match lit.node {
        LitKind::Float(s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"),
        LitKind::Float(s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"),
        LitKind::FloatUnsuffixed(s) => check_known_consts(cx, e, s, "f{32, 64}"),
        _ => (),
    }
}

fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, module: &str) {
    let s = s.as_str();
    if s.parse::<f64>().is_ok() {
        for &(constant, name, min_digits) in KNOWN_CONSTS {
            if is_approx_const(constant, &s, min_digits) {
                span_lint(
                    cx,
                    APPROX_CONSTANT,
                    e.span,
                    &format!(
                        "approximate value of `{}::consts::{}` found. \
                         Consider using it directly",
                        module, &name
                    ),
                );
                return;
            }
        }
    }
}

/// Returns false if the number of significant figures in `value` are
/// less than `min_digits`; otherwise, returns true if `value` is equal
/// to `constant`, rounded to the number of digits present in `value`.
fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
    if value.len() <= min_digits {
        false
    } else {
        let round_const = format!("{:.*}", value.len() - 2, constant);

        let mut trunc_const = constant.to_string();
        if trunc_const.len() > value.len() {
            trunc_const.truncate(value.len());
        }

        (value == round_const) || (value == trunc_const)
    }
}
<|endoftext|>


<commit_before>#![feature(env)]
#![feature(old_io)]
#![feature(old_path)]
#![feature(collections)]

#![allow(dead_code)]

use std::env;
use std::mem;
use std::old_io::File;

static FILE_HEADER_SIZE : usize = 4*4;
static PAGE_HEADER_SIZE : usize = 3;

static PAGE_USER_DATA : usize = 0;
static PAGE_LINKS : usize = 1;
static PAGE_BID_LINKS : usize = 2;

struct Graph<'a> {
    data : &'a mut [u32],
}

impl<'a> Graph<'a> {
    fn first_page(&self) -> usize {
        FILE_HEADER_SIZE
    }

    fn find_next_unmarked(&self,start : usize) -> Option<usize> {
        let mut page = start;
        while self.user_data(page) != 0 {
            page = page + (PAGE_HEADER_SIZE+self.link_count(page))*4;
            if page >= self.data.len() * 4 { return None;}
        }
        Some(page)
    }

    fn page_count(&self) -> u32 {
        self.data[1]
    }

    fn link_count(&self, page : usize) -> usize {
        self.data[page/4+PAGE_LINKS] as usize
    }

    fn bid_link_count(&self, page : usize) -> usize {
        self.data[page/4+PAGE_BID_LINKS] as usize
    }

    fn links(&'a self, page : usize) -> &'a [u32] {
        let start = page/4+PAGE_HEADER_SIZE;
        let end = start+self.link_count(page);
        &self.data[start..end]
    }

    fn set_user_data(&mut self, page : usize, data : u32) {
        self.data[page/4+PAGE_USER_DATA] = data;
    }

    fn user_data(&self, page : usize) -> u32 {
        self.data[page/4+PAGE_USER_DATA]
    }
}

fn flood_fill(graph : &mut Graph, start_page : usize, mark : u32) -> u32 {
    assert!(mark != 0);
    let mut stack = vec![start_page];
    let mut marked_count = 0;
    while !stack.is_empty() {
        let page = stack.pop().unwrap();

        if graph.user_data(page) != 0 {continue;}
        graph.set_user_data(page,mark); // mark visited
        // println!("Visiting {} with {} links",page,graph.link_count(page));
        marked_count += 1;

        for linked in graph.links(page) {
            // println!("Pushing link to {}", linked);
            stack.push(*linked as usize);
        }
    }
    marked_count
}

fn main() {
    let args: Vec<String> = env::args().map(|x| x.to_string()).collect();

    if args.len() != 2 {
        println!("Usage: ./strong_conn path/to/indexbi.bin");
        env::set_exit_status(1);
        return;
    }

    let bin_path = Path::new(&args[1]);
    println!("Analyzing {}...",bin_path.display());

    let mut file = File::open(&bin_path).ok().expect("Could not open graph file.");

    let mut graph_data : Vec<u32>;
    {
        let mut buf : Vec<u8> = file.read_to_end().ok().expect("Could not read file.");
        let len = buf.len();
        println!("Read {} bytes of file!", len);
        if len % 4 != 0 {
            println!("Invalid file size!");
            return;
        }
        let data_ptr : *mut u32 = unsafe {mem::transmute(buf.as_mut_ptr())};
        graph_data = unsafe { Vec::from_raw_buf(data_ptr, len / 4)};
    }
    let mut graph = Graph { data: graph_data.as_mut_slice() };
    println!("Read {} words of file!", graph.data.len());

    let mut start_page = graph.first_page();
    let mut comp_count = 0;
    loop {
        let count = flood_fill(&mut graph, start_page,1);
        if count > 100 {
            println!("Found a connected component of {} nodes out of {} pages = {}.",
                     count,graph.page_count(),(count as f32 / graph.page_count() as f32));
        }
        comp_count += 1;

        let next_page = graph.find_next_unmarked(start_page);
        match next_page {
            Some(page) => start_page = page,
            None => break,
        }
    }
    println!("Found {} components.",comp_count);
}
<commit_msg>Incoming link analyzer<commit_after>#![feature(env)]
#![feature(old_io)]
#![feature(old_path)]
#![feature(collections)]

#![allow(dead_code)]

use std::env;
use std::mem;
use std::old_io::File;

static FILE_HEADER_SIZE : usize = 4*4;
static PAGE_HEADER_SIZE : usize = 3;

static PAGE_USER_DATA : usize = 0;
static PAGE_LINKS : usize = 1;
static PAGE_BID_LINKS : usize = 2;

struct Graph<'a> {
    data : &'a mut [u32],
}

struct PageIter<'a> {
    g : &'a Graph<'a>,
    cur : usize,
}

impl<'a> Iterator for PageIter<'a> {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        let next_page = self.cur + (PAGE_HEADER_SIZE+self.g.link_count(self.cur))*4;
        self.cur = next_page;
        if next_page >= self.g.data.len() * 4 { None } else { Some(next_page) }
    }
}

impl<'a> Graph<'a> {
    fn first_page(&self) -> usize {
        FILE_HEADER_SIZE
    }

    fn find_next(&self, page : usize) -> Option<usize> {
        let next_page = page + (PAGE_HEADER_SIZE+self.link_count(page))*4;
        if next_page >= self.data.len() * 4 { None } else { Some(next_page) }
    }

    fn find_next_unmarked(&self,start : usize) -> Option<usize> {
        let mut page = start;
        while self.user_data(page) != 0 {
            page = page + (PAGE_HEADER_SIZE+self.link_count(page))*4;
            if page >= self.data.len() * 4 { return None;}
        }
        Some(page)
    }

    fn pages(&self) -> PageIter {
        PageIter {g: self, cur: self.first_page()}
    }

    fn page_count(&self) -> u32 {
        self.data[1]
    }

    fn link_count(&self, page : usize) -> usize {
        self.data[page/4+PAGE_LINKS] as usize
    }

    fn bid_link_count(&self, page : usize) -> usize {
        self.data[page/4+PAGE_BID_LINKS] as usize
    }

    fn links(&'a self, page : usize) -> Vec<usize> {
        let start = page/4+PAGE_HEADER_SIZE;
        let end = start+self.link_count(page);
        let link_range = &self.data[start..end];
        link_range.iter().map(|x| *x as usize).collect::<Vec<usize>>()
    }

    fn set_user_data(&mut self, page : usize, data : u32) {
        self.data[page/4+PAGE_USER_DATA] = data;
    }

    fn user_data(&self, page : usize) -> u32 {
        self.data[page/4+PAGE_USER_DATA]
    }
}

fn flood_fill(graph : &mut Graph, start_page : usize, mark : u32) -> u32 {
    assert!(mark != 0);
    let mut stack = vec![start_page];
    let mut marked_count = 0;
    while !stack.is_empty() {
        let page = stack.pop().unwrap();

        if graph.user_data(page) != 0 {continue;}
        graph.set_user_data(page,mark); // mark visited
        // println!("Visiting {} with {} links",page,graph.link_count(page));
        marked_count += 1;

        for linked in graph.links(page) {
            // println!("Pushing link to {}", linked);
            stack.push(linked);
        }
    }
    marked_count
}

fn find_conn_components(graph : &mut Graph) {
    let mut start_page = graph.first_page();
    let mut comp_count = 0;
    loop {
        let count = flood_fill(graph, start_page,1);
        if count > 100 {
            println!("Found a connected component of {} nodes out of {} pages = {}.",
                     count,graph.page_count(),(count as f32 / graph.page_count() as f32));
        }
        comp_count += 1;

        let next_page = graph.find_next_unmarked(start_page);
        match next_page {
            Some(page) => start_page = page,
            None => break,
        }
    }
    println!("Found {} components.",comp_count);
}

fn fill_incoming_links(graph : &mut Graph) {
    let mut page = graph.first_page();
    // Increment link count on all linked to pages, then move to next
    loop {
        for linked in graph.links(page) {
            let incd = graph.user_data(linked)+1;
            graph.set_user_data(linked, incd);
        }

        match graph.find_next(page) {
            None => break,
            Some(new_page) => page = new_page,
        }
    }
}

static DATA_HIST_MAX : usize = 50;
fn analyze_user_data(graph : &Graph) {
    let mut hist : Vec<u32> = vec![0; DATA_HIST_MAX];
    for page in graph.pages() {
        let count = graph.user_data(page);
        if (count as usize) < DATA_HIST_MAX {
            hist[count as usize] += 1;
        }
    }
    println!("Incoming links:");
    for c in 0..hist.len() {
        println!("{}: {}",c, hist[c]);
    }
}

fn main() {
    let args: Vec<String> = env::args().map(|x| x.to_string()).collect();

    if args.len() != 2 {
        println!("Usage: ./strong_conn path/to/indexbi.bin");
        env::set_exit_status(1);
        return;
    }

    let bin_path = Path::new(&args[1]);
    println!("Analyzing {}...",bin_path.display());

    let mut file = File::open(&bin_path).ok().expect("Could not open graph file.");

    let mut graph_data : Vec<u32>;
    {
        let mut buf : Vec<u8> = file.read_to_end().ok().expect("Could not read file.");
        let len = buf.len();
        println!("Read {} bytes of file!", len);
        if len % 4 != 0 {
            println!("Invalid file size!");
            return;
        }
        let data_ptr : *mut u32 = unsafe {mem::transmute(buf.as_mut_ptr())};
        graph_data = unsafe { Vec::from_raw_buf(data_ptr, len / 4)};
    }
    let mut graph = Graph { data: graph_data.as_mut_slice() };
    println!("Read {} words of file!", graph.data.len());
    println!("Total pages: {}", graph.page_count());

    find_conn_components(&mut graph);

    // println!("Finding incoming links...");
    // fill_incoming_links(&mut graph);
    // println!("Analyzing incoming links...");
    // analyze_user_data(&graph);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::StylePropertyMapReadOnlyBinding::StylePropertyMapReadOnlyMethods;
use dom::bindings::codegen::Bindings::StylePropertyMapReadOnlyBinding::Wrap;
use dom::bindings::js::JS;
use dom::bindings::js::Root;
use dom::bindings::reflector::Reflector;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssstylevalue::CSSStyleValue;
use dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use servo_atoms::Atom;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::iter::Iterator;

#[dom_struct]
pub struct StylePropertyMapReadOnly {
    reflector: Reflector,
    entries: HashMap<Atom, JS<CSSStyleValue>>,
}

impl StylePropertyMapReadOnly {
    fn new_inherited<Entries>(entries: Entries) -> StylePropertyMapReadOnly where
        Entries: IntoIterator<Item=(Atom, JS<CSSStyleValue>)>
    {
        StylePropertyMapReadOnly {
            reflector: Reflector::new(),
            entries: entries.into_iter().collect(),
        }
    }

    pub fn from_iter<Entries>(global: &GlobalScope, entries: Entries) -> Root<StylePropertyMapReadOnly> where
        Entries: IntoIterator<Item=(Atom, String)>,
    {
        let mut keys = Vec::new();
        rooted_vec!(let mut values);
        let iter = entries.into_iter();
        let (lo, _) = iter.size_hint();
        keys.reserve(lo);
        values.reserve(lo);
        for (key, value) in iter {
            let value = CSSStyleValue::new(global, value);
            keys.push(key);
            values.push(JS::from_ref(&*value));
        }
        let iter = keys.drain(..).zip(values.iter().cloned());
        reflect_dom_object(box StylePropertyMapReadOnly::new_inherited(iter), global, Wrap)
    }
}

impl StylePropertyMapReadOnlyMethods for StylePropertyMapReadOnly {
    /// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-get
    fn Get(&self, property: DOMString) -> Option<Root<CSSStyleValue>> {
        // TODO: avoid constructing an Atom
        self.entries.get(&Atom::from(property)).map(|value| Root::from_ref(&**value))
    }

    /// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-has
    fn Has(&self, property: DOMString) -> bool {
        // TODO: avoid constructing an Atom
        self.entries.contains_key(&Atom::from(property))
    }

    /// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getproperties
    fn GetProperties(&self) -> Vec<DOMString> {
        let mut result: Vec<DOMString> = self.entries.keys()
            .map(|key| DOMString::from(&**key))
            .collect();
        // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-getproperties
        // requires this sort order
        result.sort_by(|key1, key2| {
            if key1.starts_with("-") {
                if key2.starts_with("-") {
                    key1.cmp(key2)
                } else {
                    Ordering::Greater
                }
            } else {
                if key2.starts_with("-") {
                    Ordering::Less
                } else {
                    key1.cmp(key2)
                }
            }
        });
        result
    }
}
<commit_msg>Used custom_properties::parse_name<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::StylePropertyMapReadOnlyBinding::StylePropertyMapReadOnlyMethods;
use dom::bindings::codegen::Bindings::StylePropertyMapReadOnlyBinding::Wrap;
use dom::bindings::js::JS;
use dom::bindings::js::Root;
use dom::bindings::reflector::Reflector;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssstylevalue::CSSStyleValue;
use dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use servo_atoms::Atom;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::iter::Iterator;
use style::custom_properties;

#[dom_struct]
pub struct StylePropertyMapReadOnly {
    reflector: Reflector,
    entries: HashMap<Atom, JS<CSSStyleValue>>,
}

impl StylePropertyMapReadOnly {
    fn new_inherited<Entries>(entries: Entries) -> StylePropertyMapReadOnly where
        Entries: IntoIterator<Item=(Atom, JS<CSSStyleValue>)>
    {
        StylePropertyMapReadOnly {
            reflector: Reflector::new(),
            entries: entries.into_iter().collect(),
        }
    }

    pub fn from_iter<Entries>(global: &GlobalScope, entries: Entries) -> Root<StylePropertyMapReadOnly> where
        Entries: IntoIterator<Item=(Atom, String)>,
    {
        let mut keys = Vec::new();
        rooted_vec!(let mut values);
        let iter = entries.into_iter();
        let (lo, _) = iter.size_hint();
        keys.reserve(lo);
        values.reserve(lo);
        for (key, value) in iter {
            let value = CSSStyleValue::new(global, value);
            keys.push(key);
            values.push(JS::from_ref(&*value));
        }
        let iter = keys.drain(..).zip(values.iter().cloned());
        reflect_dom_object(box StylePropertyMapReadOnly::new_inherited(iter), global, Wrap)
    }
}

impl StylePropertyMapReadOnlyMethods for StylePropertyMapReadOnly {
    /// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-get
    fn Get(&self, property: DOMString) -> Option<Root<CSSStyleValue>> {
        // TODO: avoid constructing an Atom
        self.entries.get(&Atom::from(property)).map(|value| Root::from_ref(&**value))
    }

    /// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-has
    fn Has(&self, property: DOMString) -> bool {
        // TODO: avoid constructing an Atom
        self.entries.contains_key(&Atom::from(property))
    }

    /// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getproperties
    fn GetProperties(&self) -> Vec<DOMString> {
        let mut result: Vec<DOMString> = self.entries.keys()
            .map(|key| DOMString::from(&**key))
            .collect();
        // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-getproperties
        // requires this sort order
        result.sort_by(|key1, key2| {
            if let Ok(key1) = custom_properties::parse_name(key1) {
                if let Ok(key2) = custom_properties::parse_name(key2) {
                    key1.cmp(key2)
                } else {
                    Ordering::Greater
                }
            } else {
                if let Ok(_) = custom_properties::parse_name(key2) {
                    Ordering::Less
                } else {
                    key1.cmp(key2)
                }
            }
        });
        result
    }
}
<|endoftext|>