<commit_before>use crate::ssz_encode;
use hashing::hash;
use int_to_bytes::int_to_bytes32;

const BYTES_PER_CHUNK: usize = 32;
const HASHSIZE: usize = 32;
const MERKLE_HASH_CHUNCK: usize = 2 * BYTES_PER_CHUNK;

pub struct TreeHashCache {
    cache: Vec<u8>,
    chunk_modified: Vec<bool>,
}

impl Into<Vec<u8>> for TreeHashCache {
    fn into(self) -> Vec<u8> {
        self.cache
    }
}

impl TreeHashCache {
    pub fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
        if bytes.len() % BYTES_PER_CHUNK > 0 {
            return None;
        }

        Some(Self {
            chunk_modified: vec![false; bytes.len() / BYTES_PER_CHUNK],
            cache: bytes,
        })
    }

    pub fn modify_chunk(&mut self, chunk: usize, to: &[u8]) -> Option<()> {
        let start = chunk * BYTES_PER_CHUNK;
        let end = start + BYTES_PER_CHUNK;

        self.cache.get_mut(start..end)?.copy_from_slice(to);

        self.chunk_modified[chunk] = true;

        Some(())
    }

    pub fn changed(&self, chunk: usize) -> Option<bool> {
        self.chunk_modified.get(chunk).cloned()
    }

    pub fn children_modified(&self, parent_chunk: usize) -> Option<bool> {
        let children = children(parent_chunk);

        Some(self.changed(children.0)? | self.changed(children.1)?)
    }

    pub fn hash_children(&self, parent_chunk: usize) -> Option<Vec<u8>> {
        let children = children(parent_chunk);

        let start = children.0 * BYTES_PER_CHUNK;
        let end = start + BYTES_PER_CHUNK * 2;

        Some(hash(&self.cache.get(start..end)?))
    }
}

fn children(parent: usize) -> (usize, usize) {
    ((2 * parent + 1), (2 * parent + 2))
}

fn num_nodes(num_leaves: usize) -> usize {
    2 * num_leaves - 1
}

pub trait CachedTreeHash {
    fn build_cache_bytes(&self) -> Vec<u8>;

    fn num_bytes(&self) -> usize;

    fn max_num_leaves(&self) -> usize;

    fn cached_hash_tree_root(
        &self,
        other: &Self,
        cache: &mut TreeHashCache,
        chunk: usize,
    ) -> Option<usize>;
}

impl CachedTreeHash for u64 {
    fn build_cache_bytes(&self) -> Vec<u8> {
        merkleize(&int_to_bytes32(*self))
    }

    fn num_bytes(&self) -> usize {
        8
    }

    fn max_num_leaves(&self) -> usize {
        1
    }

    fn cached_hash_tree_root(
        &self,
        other: &Self,
        cache: &mut TreeHashCache,
        chunk: usize,
    ) -> Option<usize> {
        if self != other {
            cache.modify_chunk(chunk, &merkleize(&int_to_bytes32(*self)))?;
        }

        Some(chunk + 1)
    }
}

#[derive(Clone)]
pub struct Inner {
    pub a: u64,
    pub b: u64,
    pub c: u64,
    pub d: u64,
}

impl CachedTreeHash for Inner {
    fn build_cache_bytes(&self) -> Vec<u8> {
        let mut leaves = vec![];

        leaves.append(&mut self.a.build_cache_bytes());
        leaves.append(&mut self.b.build_cache_bytes());
        leaves.append(&mut self.c.build_cache_bytes());
        leaves.append(&mut self.d.build_cache_bytes());

        merkleize(&leaves)
    }

    fn max_num_leaves(&self) -> usize {
        let mut leaves = 0;
        leaves += self.a.max_num_leaves();
        leaves += self.b.max_num_leaves();
        leaves += self.c.max_num_leaves();
        leaves += self.d.max_num_leaves();
        leaves
    }

    fn num_bytes(&self) -> usize {
        let mut bytes = 0;
        bytes += self.a.num_bytes();
        bytes += self.b.num_bytes();
        bytes += self.c.num_bytes();
        bytes += self.d.num_bytes();
        bytes
    }

    fn cached_hash_tree_root(
        &self,
        other: &Self,
        cache: &mut TreeHashCache,
        chunk: usize,
    ) -> Option<usize> {
        let num_leaves = self.max_num_leaves();
        let num_nodes = num_nodes(num_leaves);
        let num_internal_nodes = num_nodes - num_leaves;

        // Skip past the internal nodes and update any changed leaf nodes.
        {
            let chunk = chunk + num_internal_nodes;
            let chunk = self.a.cached_hash_tree_root(&other.a, cache, chunk)?;
            let chunk = self.b.cached_hash_tree_root(&other.b, cache, chunk)?;
            let chunk = self.c.cached_hash_tree_root(&other.c, cache, chunk)?;
            let _chunk = self.d.cached_hash_tree_root(&other.d, cache, chunk)?;
        }

        // Iterate backwards through the internal nodes, rehashing any node where it's children
        // have changed.
        for chunk in (0..num_internal_nodes).into_iter().rev() {
            if cache.children_modified(chunk)? {
                cache.modify_chunk(chunk, &cache.hash_children(chunk)?)?;
            }
        }

        Some(chunk + num_nodes)
    }
}

/// A reference function to test against.
pub fn merkleize(values: &[u8]) -> Vec<u8> {
    let leaves = values.len() / HASHSIZE;

    if leaves == 0 {
        panic!("No full leaves");
    }

    if !leaves.is_power_of_two() {
        panic!("leaves is not power of two");
    }

    let mut o: Vec<u8> = vec![0; (num_nodes(leaves) - leaves) * HASHSIZE];
    o.append(&mut values.to_vec());

    let mut i = o.len();
    let mut j = o.len() - values.len();

    while i >= MERKLE_HASH_CHUNCK {
        i -= MERKLE_HASH_CHUNCK;
        let hash = hash(&o[i..i + MERKLE_HASH_CHUNCK]);

        j -= HASHSIZE;
        o[j..j + HASHSIZE].copy_from_slice(&hash);
    }

    o
}

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

    fn join(many: Vec<Vec<u8>>) -> Vec<u8> {
        let mut all = vec![];
        for one in many {
            all.extend_from_slice(&mut one.clone())
        }
        all
    }

    fn generic_test(index: usize) {
        let inner = Inner {
            a: 1,
            b: 2,
            c: 3,
            d: 4,
        };

        let mut cache = inner.build_cache_bytes();

        let changed_inner = match index {
            0 => Inner {
                a: 42,
                ..inner.clone()
            },
            1 => Inner {
                b: 42,
                ..inner.clone()
            },
            2 => Inner {
                c: 42,
                ..inner.clone()
            },
            3 => Inner {
                d: 42,
                ..inner.clone()
            },
            _ => panic!("bad index"),
        };

        let mut cache_struct = TreeHashCache::from_bytes(cache.clone()).unwrap();

        changed_inner
            .cached_hash_tree_root(&inner, &mut cache_struct, 0)
            .unwrap();

        // assert_eq!(*cache_struct.hash_count, 3);

        let new_cache: Vec<u8> = cache_struct.into();

        let data1 = int_to_bytes32(1);
        let data2 = int_to_bytes32(2);
        let data3 = int_to_bytes32(3);
        let data4 = int_to_bytes32(4);

        let mut data = vec![data1, data2, data3, data4];

        data[index] = int_to_bytes32(42);

        let expected = merkleize(&join(data));

        assert_eq!(expected, new_cache);
    }

    #[test]
    fn cached_hash_on_inner() {
        generic_test(0);
        generic_test(1);
        generic_test(2);
        generic_test(3);
    }

    #[test]
    fn build_cache_matches_merkelize() {
        let data1 = int_to_bytes32(1);
        let data2 = int_to_bytes32(2);
        let data3 = int_to_bytes32(3);
        let data4 = int_to_bytes32(4);

        let data = join(vec![data1, data2, data3, data4]);
        let expected = merkleize(&data);

        let inner = Inner {
            a: 1,
            b: 2,
            c: 3,
            d: 4,
        };

        let cache = inner.build_cache_bytes();

        assert_eq!(expected, cache);
    }

    #[test]
    fn merkleize_4_leaves() {
        let data1 = hash(&int_to_bytes32(1));
        let data2 = hash(&int_to_bytes32(2));
        let data3 = hash(&int_to_bytes32(3));
        let data4 = hash(&int_to_bytes32(4));

        let data = join(vec![
            data1.clone(),
            data2.clone(),
            data3.clone(),
            data4.clone(),
        ]);

        let cache = merkleize(&data);

        let hash_12 = {
            let mut joined = vec![];
            joined.append(&mut data1.clone());
            joined.append(&mut data2.clone());
            hash(&joined)
        };
        let hash_34 = {
            let mut joined = vec![];
            joined.append(&mut data3.clone());
            joined.append(&mut data4.clone());
            hash(&joined)
        };
        let hash_hash12_hash_34 = {
            let mut joined = vec![];
            joined.append(&mut hash_12.clone());
            joined.append(&mut hash_34.clone());
            hash(&joined)
        };

        for (i, chunk) in cache.chunks(HASHSIZE).enumerate().rev() {
            let expected = match i {
                0 => hash_hash12_hash_34.clone(),
                1 => hash_12.clone(),
                2 => hash_34.clone(),
                3 => data1.clone(),
                4 => data2.clone(),
                5 => data3.clone(),
                6 => data4.clone(),
                _ => vec![],
            };

            assert_eq!(chunk, &expected[..], "failed at {}", i);
        }
    }
}
<commit_msg>Sanitize for odd leaf count<commit_after>use crate::ssz_encode;
use hashing::hash;
use int_to_bytes::int_to_bytes32;

const BYTES_PER_CHUNK: usize = 32;
const HASHSIZE: usize = 32;
const MERKLE_HASH_CHUNCK: usize = 2 * BYTES_PER_CHUNK;

pub struct TreeHashCache {
    cache: Vec<u8>,
    chunk_modified: Vec<bool>,
}

impl Into<Vec<u8>> for TreeHashCache {
    fn into(self) -> Vec<u8> {
        self.cache
    }
}

impl TreeHashCache {
    pub fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
        if bytes.len() % BYTES_PER_CHUNK > 0 {
            return None;
        }

        Some(Self {
            chunk_modified: vec![false; bytes.len() / BYTES_PER_CHUNK],
            cache: bytes,
        })
    }

    pub fn modify_chunk(&mut self, chunk: usize, to: &[u8]) -> Option<()> {
        let start = chunk * BYTES_PER_CHUNK;
        let end = start + BYTES_PER_CHUNK;

        self.cache.get_mut(start..end)?.copy_from_slice(to);

        self.chunk_modified[chunk] = true;

        Some(())
    }

    pub fn changed(&self, chunk: usize) -> Option<bool> {
        self.chunk_modified.get(chunk).cloned()
    }

    pub fn children_modified(&self, parent_chunk: usize) -> Option<bool> {
        let children = children(parent_chunk);

        Some(self.changed(children.0)? | self.changed(children.1)?)
    }

    pub fn hash_children(&self, parent_chunk: usize) -> Option<Vec<u8>> {
        let children = children(parent_chunk);

        let start = children.0 * BYTES_PER_CHUNK;
        let end = start + BYTES_PER_CHUNK * 2;

        Some(hash(&self.cache.get(start..end)?))
    }
}

fn children(parent: usize) -> (usize, usize) {
    ((2 * parent + 1), (2 * parent + 2))
}

fn num_nodes(num_leaves: usize) -> usize {
    2 * num_leaves - 1
}

pub trait CachedTreeHash {
    fn build_cache_bytes(&self) -> Vec<u8>;

    fn num_bytes(&self) -> usize;

    fn max_num_leaves(&self) -> usize;

    fn cached_hash_tree_root(
        &self,
        other: &Self,
        cache: &mut TreeHashCache,
        chunk: usize,
    ) -> Option<usize>;
}

impl CachedTreeHash for u64 {
    fn build_cache_bytes(&self) -> Vec<u8> {
        merkleize(&int_to_bytes32(*self))
    }

    fn num_bytes(&self) -> usize {
        8
    }

    fn max_num_leaves(&self) -> usize {
        1
    }

    fn cached_hash_tree_root(
        &self,
        other: &Self,
        cache: &mut TreeHashCache,
        chunk: usize,
    ) -> Option<usize> {
        if self != other {
            cache.modify_chunk(chunk, &merkleize(&int_to_bytes32(*self)))?;
        }

        Some(chunk + 1)
    }
}

#[derive(Clone)]
pub struct Inner {
    pub a: u64,
    pub b: u64,
    pub c: u64,
    pub d: u64,
}

impl CachedTreeHash for Inner {
    fn build_cache_bytes(&self) -> Vec<u8> {
        let mut leaves = vec![];

        leaves.append(&mut self.a.build_cache_bytes());
        leaves.append(&mut self.b.build_cache_bytes());
        leaves.append(&mut self.c.build_cache_bytes());
        leaves.append(&mut self.d.build_cache_bytes());

        merkleize(&leaves)
    }

    fn max_num_leaves(&self) -> usize {
        let mut leaves = 0;
        leaves += self.a.max_num_leaves();
        leaves += self.b.max_num_leaves();
        leaves += self.c.max_num_leaves();
        leaves += self.d.max_num_leaves();
        leaves
    }

    fn num_bytes(&self) -> usize {
        let mut bytes = 0;
        bytes += self.a.num_bytes();
        bytes += self.b.num_bytes();
        bytes += self.c.num_bytes();
        bytes += self.d.num_bytes();
        bytes
    }

    fn cached_hash_tree_root(
        &self,
        other: &Self,
        cache: &mut TreeHashCache,
        chunk: usize,
    ) -> Option<usize> {
        let num_leaves = self.max_num_leaves();
        let num_nodes = num_nodes(num_leaves);
        let num_internal_nodes = num_nodes - num_leaves;

        // Skip past the internal nodes and update any changed leaf nodes.
        {
            let chunk = chunk + num_internal_nodes;
            let chunk = self.a.cached_hash_tree_root(&other.a, cache, chunk)?;
            let chunk = self.b.cached_hash_tree_root(&other.b, cache, chunk)?;
            let chunk = self.c.cached_hash_tree_root(&other.c, cache, chunk)?;
            let _chunk = self.d.cached_hash_tree_root(&other.d, cache, chunk)?;
        }

        // Iterate backwards through the internal nodes, rehashing any node where it's children
        // have changed.
        for chunk in (0..num_internal_nodes).into_iter().rev() {
            if cache.children_modified(chunk)? {
                cache.modify_chunk(chunk, &cache.hash_children(chunk)?)?;
            }
        }

        Some(chunk + num_nodes)
    }
}

fn last_leaf_needs_padding(num_bytes: usize) -> bool {
    num_bytes % HASHSIZE != 0
}

fn num_leaves(num_bytes: usize) -> usize {
    num_bytes / HASHSIZE
}

fn num_bytes(num_leaves: usize) -> usize {
    num_leaves * HASHSIZE
}

pub fn sanitise_bytes(mut bytes: Vec<u8>) -> Vec<u8> {
    let present_leaves = num_leaves(bytes.len());
    let required_leaves = present_leaves.next_power_of_two();

    if (present_leaves != required_leaves) | last_leaf_needs_padding(bytes.len()) {
        bytes.resize(num_bytes(required_leaves), 0);
    }

    bytes
}

/// A reference function to test against.
pub fn merkleize(values: &[u8]) -> Vec<u8> {
    let leaves = values.len() / HASHSIZE;

    if leaves == 0 {
        panic!("No full leaves");
    }

    if !leaves.is_power_of_two() {
        panic!("leaves is not power of two");
    }

    let mut o: Vec<u8> = vec![0; (num_nodes(leaves) - leaves) * HASHSIZE];
    o.append(&mut values.to_vec());

    let mut i = o.len();
    let mut j = o.len() - values.len();

    while i >= MERKLE_HASH_CHUNCK {
        i -= MERKLE_HASH_CHUNCK;
        let hash = hash(&o[i..i + MERKLE_HASH_CHUNCK]);

        j -= HASHSIZE;
        o[j..j + HASHSIZE].copy_from_slice(&hash);
    }

    o
}

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

    fn join(many: Vec<Vec<u8>>) -> Vec<u8> {
        let mut all = vec![];
        for one in many {
            all.extend_from_slice(&mut one.clone())
        }
        all
    }

    #[test]
    fn merkleize_odd() {
        let data = join(vec![
            int_to_bytes32(1),
            int_to_bytes32(2),
            int_to_bytes32(3),
            int_to_bytes32(4),
            int_to_bytes32(5),
        ]);

        merkleize(&sanitise_bytes(data));
    }

    fn generic_test(index: usize) {
        let inner = Inner {
            a: 1,
            b: 2,
            c: 3,
            d: 4,
        };

        let cache = inner.build_cache_bytes();

        let changed_inner = match index {
            0 => Inner {
                a: 42,
                ..inner.clone()
            },
            1 => Inner {
                b: 42,
                ..inner.clone()
            },
            2 => Inner {
                c: 42,
                ..inner.clone()
            },
            3 => Inner {
                d: 42,
                ..inner.clone()
            },
            _ => panic!("bad index"),
        };

        let mut cache_struct = TreeHashCache::from_bytes(cache.clone()).unwrap();

        changed_inner
            .cached_hash_tree_root(&inner, &mut cache_struct, 0)
            .unwrap();

        // assert_eq!(*cache_struct.hash_count, 3);

        let new_cache: Vec<u8> = cache_struct.into();

        let data1 = int_to_bytes32(1);
        let data2 = int_to_bytes32(2);
        let data3 = int_to_bytes32(3);
        let data4 = int_to_bytes32(4);

        let mut data = vec![data1, data2, data3, data4];

        data[index] = int_to_bytes32(42);

        let expected = merkleize(&join(data));

        assert_eq!(expected, new_cache);
    }

    #[test]
    fn cached_hash_on_inner() {
        generic_test(0);
        generic_test(1);
        generic_test(2);
        generic_test(3);
    }

    #[test]
    fn build_cache_matches_merkelize() {
        let data1 = int_to_bytes32(1);
        let data2 = int_to_bytes32(2);
        let data3 = int_to_bytes32(3);
        let data4 = int_to_bytes32(4);

        let data = join(vec![data1, data2, data3, data4]);
        let expected = merkleize(&data);

        let inner = Inner {
            a: 1,
            b: 2,
            c: 3,
            d: 4,
        };

        let cache = inner.build_cache_bytes();

        assert_eq!(expected, cache);
    }

    #[test]
    fn merkleize_4_leaves() {
        let data1 = hash(&int_to_bytes32(1));
        let data2 = hash(&int_to_bytes32(2));
        let data3 = hash(&int_to_bytes32(3));
        let data4 = hash(&int_to_bytes32(4));

        let data = join(vec![
            data1.clone(),
            data2.clone(),
            data3.clone(),
            data4.clone(),
        ]);

        let cache = merkleize(&data);

        let hash_12 = {
            let mut joined = vec![];
            joined.append(&mut data1.clone());
            joined.append(&mut data2.clone());
            hash(&joined)
        };
        let hash_34 = {
            let mut joined = vec![];
            joined.append(&mut data3.clone());
            joined.append(&mut data4.clone());
            hash(&joined)
        };
        let hash_hash12_hash_34 = {
            let mut joined = vec![];
            joined.append(&mut hash_12.clone());
            joined.append(&mut hash_34.clone());
            hash(&joined)
        };

        for (i, chunk) in cache.chunks(HASHSIZE).enumerate().rev() {
            let expected = match i {
                0 => hash_hash12_hash_34.clone(),
                1 => hash_12.clone(),
                2 => hash_34.clone(),
                3 => data1.clone(),
                4 => data2.clone(),
                5 => data3.clone(),
                6 => data4.clone(),
                _ => vec![],
            };

            assert_eq!(chunk, &expected[..], "failed at {}", i);
        }
    }
}
<|endoftext|>


<commit_before>extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate tokio_process;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::env;
use std::io;
use std::process::{Stdio, ExitStatus, Command};

use futures::{Future, BoxFuture};
use futures::stream::{self, Stream};
use tokio_core::io::{read_until, write_all, read_to_end};
use tokio_core::reactor::Core;
use tokio_process::{CommandExt, Child};

fn cat() -> Command {
    let mut path = env::current_exe().unwrap();
    path.pop();
    if path.ends_with("deps") {
        path.pop();
    }
    path.push("cat");
    let mut cmd = Command::new(path);
    cmd.stdin(Stdio::piped())
       .stdout(Stdio::piped());
    cmd
}

fn feed_cat(mut cat: Child, n: usize) -> BoxFuture<ExitStatus, io::Error> {
    let stdin = cat.stdin().take().unwrap();
    let stdout = cat.stdout().take().unwrap();

    debug!("starting to feed");
    // Produce n lines on the child's stdout.
    let numbers = stream::iter((0..n).into_iter().map(Ok));
    let write = numbers.fold(stdin, |stdin, i| {
        debug!("sending line {} to child", i);
        write_all(stdin, format!("line {}\n", i).into_bytes()).map(|p| p.0)
    }).map(|_| ());

    // Try to read `n + 1` lines, ensuring the last one is empty
    // (i.e. EOF is reached after `n` lines.
    let reader = io::BufReader::new(stdout);
    let expected_numbers = stream::iter((0..n + 1).map(Ok));
    let read = expected_numbers.fold((reader, 0), move |(reader, i), _| {
        let done = i >= n;
        debug!("starting read from child");
        read_until(reader, b'\n', Vec::new()).and_then(move |(reader, vec)| {
            debug!("read line {} from child ({} bytes, done: {})",
                   i, vec.len(), done);
            match (done, vec.len()) {
                (false, 0) => {
                    Err(io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"))
                },
                (true, n) if n != 0 => {
                    Err(io::Error::new(io::ErrorKind::Other, "extraneous data"))
                },
                _ => {
                    let s = std::str::from_utf8(&vec).unwrap();
                    let expected = format!("line {}\n", i);
                    if done || s == expected {
                        Ok((reader, i + 1))
                    } else {
                        Err(io::Error::new(io::ErrorKind::Other, "unexpected data"))
                    }
                }
            }
        })
    });

    // Compose reading and writing concurrently.
    write.join(read).and_then(|_| cat).boxed()
}

#[test]
/// Check for the following properties when feeding stdin and
/// consuming stdout of a cat-like process:
///
/// - A number of lines that amounts to a number of bytes exceeding a
///   typical OS buffer size can be fed to the child without
///   deadlock. This tests that we also consume the stdout
///   concurrently; otherwise this would deadlock.
///
/// - We read the same lines from the child that we fed it.
///
/// - The child does produce EOF on stdout after the last line.
fn feed_a_lot() {
    let _ = ::env_logger::init();

    let mut lp = Core::new().unwrap();
    let child = cat().spawn_async(&lp.handle()).unwrap();
    let status = lp.run(feed_cat(child, 10000)).unwrap();
    assert_eq!(status.code(), Some(0));
}

#[test]
fn drop_kills() {
    let _ = ::env_logger::init();

    let mut lp = Core::new().unwrap();
    let mut child = cat().spawn_async(&lp.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let stdout = child.stdout().take().unwrap();
    drop(child);

    let (_, output) = lp.run(read_to_end(stdout, Vec::new())).unwrap();
    assert_eq!(output.len(), 0);
    let err = lp.run(write_all(stdin, b"1234")).err().unwrap();
    assert_eq!(err.kind(), io::ErrorKind::BrokenPipe);
}
<commit_msg>process: Add a simple `wait_with_output` test<commit_after>extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate tokio_process;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::env;
use std::io;
use std::process::{Stdio, ExitStatus, Command};

use futures::{Future, BoxFuture};
use futures::stream::{self, Stream};
use tokio_core::io::{read_until, write_all, read_to_end};
use tokio_core::reactor::Core;
use tokio_process::{CommandExt, Child};

fn cat() -> Command {
    let mut path = env::current_exe().unwrap();
    path.pop();
    if path.ends_with("deps") {
        path.pop();
    }
    path.push("cat");
    let mut cmd = Command::new(path);
    cmd.stdin(Stdio::piped())
       .stdout(Stdio::piped());
    cmd
}

fn feed_cat(mut cat: Child, n: usize) -> BoxFuture<ExitStatus, io::Error> {
    let stdin = cat.stdin().take().unwrap();
    let stdout = cat.stdout().take().unwrap();

    debug!("starting to feed");
    // Produce n lines on the child's stdout.
    let numbers = stream::iter((0..n).into_iter().map(Ok));
    let write = numbers.fold(stdin, |stdin, i| {
        debug!("sending line {} to child", i);
        write_all(stdin, format!("line {}\n", i).into_bytes()).map(|p| p.0)
    }).map(|_| ());

    // Try to read `n + 1` lines, ensuring the last one is empty
    // (i.e. EOF is reached after `n` lines.
    let reader = io::BufReader::new(stdout);
    let expected_numbers = stream::iter((0..n + 1).map(Ok));
    let read = expected_numbers.fold((reader, 0), move |(reader, i), _| {
        let done = i >= n;
        debug!("starting read from child");
        read_until(reader, b'\n', Vec::new()).and_then(move |(reader, vec)| {
            debug!("read line {} from child ({} bytes, done: {})",
                   i, vec.len(), done);
            match (done, vec.len()) {
                (false, 0) => {
                    Err(io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"))
                },
                (true, n) if n != 0 => {
                    Err(io::Error::new(io::ErrorKind::Other, "extraneous data"))
                },
                _ => {
                    let s = std::str::from_utf8(&vec).unwrap();
                    let expected = format!("line {}\n", i);
                    if done || s == expected {
                        Ok((reader, i + 1))
                    } else {
                        Err(io::Error::new(io::ErrorKind::Other, "unexpected data"))
                    }
                }
            }
        })
    });

    // Compose reading and writing concurrently.
    write.join(read).and_then(|_| cat).boxed()
}

#[test]
/// Check for the following properties when feeding stdin and
/// consuming stdout of a cat-like process:
///
/// - A number of lines that amounts to a number of bytes exceeding a
///   typical OS buffer size can be fed to the child without
///   deadlock. This tests that we also consume the stdout
///   concurrently; otherwise this would deadlock.
///
/// - We read the same lines from the child that we fed it.
///
/// - The child does produce EOF on stdout after the last line.
fn feed_a_lot() {
    let _ = ::env_logger::init();

    let mut lp = Core::new().unwrap();
    let child = cat().spawn_async(&lp.handle()).unwrap();
    let status = lp.run(feed_cat(child, 10000)).unwrap();
    assert_eq!(status.code(), Some(0));
}

#[test]
fn drop_kills() {
    let _ = ::env_logger::init();

    let mut lp = Core::new().unwrap();
    let mut child = cat().spawn_async(&lp.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let stdout = child.stdout().take().unwrap();
    drop(child);

    let (_, output) = lp.run(read_to_end(stdout, Vec::new())).unwrap();
    assert_eq!(output.len(), 0);
    let err = lp.run(write_all(stdin, b"1234")).err().unwrap();
    assert_eq!(err.kind(), io::ErrorKind::BrokenPipe);
}

#[test]
fn wait_with_output_captures() {
    let _ = ::env_logger::init();

    let mut core = Core::new().unwrap();

    let mut child = cat().spawn_async(&core.handle()).unwrap();
    let stdin = child.stdin().take().unwrap();
    let out = child.wait_with_output();

    let ret = core.run(write_all(stdin, b"1234").map(|p| p.1).join(out)).unwrap();
    let (written, output) = ret;

    assert!(output.status.success());
    assert_eq!(output.stdout, written);
    assert_eq!(output.stderr.len(), 0);
}
<|endoftext|>


<commit_before>use std::env;
use std::io::BufWriter;
use std::io::{self, Write};

fn main() {
    let os_args = env::args();
    let args: Vec<_> = os_args.collect();

    if args.len() != 4 {
        println!("usage : {} start numline width", args[0]);
        return;
    }

    let start_num = args[1].trim_end().parse::<u64>().unwrap_or(0);
    let stop_num = args[2].trim_end().parse::<u64>().unwrap_or(0);
    let width_num = args[3].trim_end().parse::<u64>().unwrap_or(0);

    gen_lines(start_num, stop_num, width_num);
}

fn gen_lines(start: u64, stop: u64, linewidth: u64)  {
    let string = gen_line(linewidth);

    let stdout = io::stdout();
    let mut buff = BufWriter::new(stdout);
    for x in start..start + stop {
        buff.write_fmt(format_args!("{:012} {}", x, string)).unwrap();
    }
}

fn gen_line(linewidth: u64) -> String {
    let mut string = String::new();

    let table = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                 'w', 'x', 'y', 'z'];

    for x in 0..linewidth {
        string.push(table[x as usize % table.len()]);
    }
    string.push('\n');

    string
}
<commit_msg>gen_line: more docs, cleanups<commit_after>use std::env;
use std::io::BufWriter;
use std::io::{self, Write};

/// Simple line generator to test very large file indexing/line numbering
/// each line starts with a line number and is followed by an abitrary number of characters.
fn main() {
    let os_args = env::args();
    let args: Vec<_> = os_args.collect();

    if args.len() != 4 {
        println!("usage : {} [start] [number of line] [width]", args[0]);
        return;
    }

    let start_num = args[1].trim_end().parse::<u64>().unwrap_or(0);
    let stop_num = args[2].trim_end().parse::<u64>().unwrap_or(0);
    let width_num = args[3].trim_end().parse::<u64>().unwrap_or(0);

    gen_lines(start_num, stop_num, width_num);
}

fn gen_lines(start: u64, stop: u64, line_width: u64)  {
    let string = gen_line(line_width);

    let stdout = io::stdout();
    let mut buff = BufWriter::new(stdout);
    for x in start..start + stop {
        buff.write_fmt(format_args!("{:012} {}", x, string)).unwrap();
    }
}

fn gen_line(line_width: u64) -> String {
    let mut string = String::new();

    let table = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                 'w', 'x', 'y', 'z'];

    for x in 0..line_width {
        string.push(table[x as usize % table.len()]);
    }
    string.push('\n');

    string
}
<|endoftext|>


<commit_before>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Broadcast packet types.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

// Game state changes
const GAMEEXITED : u16 = 2;

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::sync::{Arc, Mutex};

extern crate time;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::HeartbeatPacket;

fn get_ip(addr: SocketAddr) -> String {
    match addr {
        V4(ipv4) => ipv4.ip().to_string(),
        V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = match UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)) {
        Err(_) => {
            println!("Error creating a UDP socket at {}:{}.",ip,BROADCAST_PORT_UDP);
            return;
        },
        Ok(halo_socket) => halo_socket
    };

    let client_socket = match TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)) {
        Err(_) => {
            println!("Error listening to TCP at {}:{}.",ip,SERVER_LIST_PORT_TCP);
            return;
        },
        Ok(client_socket) => client_socket
    };

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    thread::spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = time::now().to_timespec().sec;
            servers.retain(|x| x.last_alive + DROP_TIME > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Vec<String> = Vec::new();
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    thread::spawn(move || {
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                match File::open(BLACKLIST_FILE) {
                    Ok(file) => {
                        let reader = BufReader::new(&file);
                        match reader.lines().collect() {
                            Err(_) => {
                                blacklist_ref.clear();
                            },
                            Ok(t) => {
                                *blacklist_ref = t;
                            }
                        }
                    },
                    Err(_) => {}
                };
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    thread::spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = match stream {
                    Err(_) => continue,
                    Ok(the_stream) => the_stream
                };
                // Unwrap the IP.
                let ip = match client.peer_addr() {
                    Err(_) => continue,
                    Ok(ip) => get_ip(ip)
                };

                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips = ips + &(j.to_string()) + "\n";
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips = ips + &ip + ":49149:3425";

                // We may be here a while. Just in case...
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    // These are the allowed game versions. HaloMD and Halo PC 1.09 uses 01.00.09.0620, while Halo PC servers on 1.10 use 01.00.10.0621 (these are also joinable).
    let game_versions = [ "01.00.09.0620".to_string(), "01.00.10.0621".to_string() ];

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = match halo_socket.recv_from(&mut buffer) {
            Err(_) => continue,
            Ok(x) => x
        };
        if length == 0 {
            continue;
        }

        let client_ip = get_ip(source);

        if buffer[0] == KEEPALIVE || buffer[0] == HEARTBEAT {
            let blacklist_ref = blacklist_udp.lock().unwrap();
            if blacklist_ref.contains(&client_ip) {
                continue;
            }

            // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
            if buffer[0] == HEARTBEAT && length > 5 {

                let mut servers = servers_mut_udp.lock().unwrap();

                let packet = HeartbeatPacket::from_buffer(&buffer[5..length]);

                if packet.localport != 0 {
                    let updatetime = time::now().to_timespec().sec;
                    match servers.iter_mut().position(|x| x.ip == client_ip && x.port == packet.localport) {
                        None => {
                            if game_versions.contains(&packet.gamever) && &packet.gamename == "halor" {
                                let serverness = HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime };
                                (*servers).push(serverness);
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            }

            // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
            else if buffer[0] == KEEPALIVE {
                let mut servers_ref = servers_mut_udp.lock().unwrap();
                let servers = (*servers_ref).iter_mut();

                for i in servers {
                    if i.ip == client_ip && i.port == source.port() {
                        i.last_alive = time::now().to_timespec().sec;
                        break;
                    }
                }
            }
        }
    }
}
<commit_msg>Add opcode/game constants, restructure opcode checking<commit_after>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Broadcast packet types.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

// Game state changes
const GAMEEXITED : u16 = 2;

// Opcode info
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcasted game name
const HALO_RETAIL : &'static str = "halor";

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::sync::{Arc, Mutex};

extern crate time;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::HeartbeatPacket;

fn get_ip(addr: SocketAddr) -> String {
    match addr {
        V4(ipv4) => ipv4.ip().to_string(),
        V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = match UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)) {
        Err(_) => {
            println!("Error creating a UDP socket at {}:{}.",ip,BROADCAST_PORT_UDP);
            return;
        },
        Ok(halo_socket) => halo_socket
    };

    let client_socket = match TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)) {
        Err(_) => {
            println!("Error listening to TCP at {}:{}.",ip,SERVER_LIST_PORT_TCP);
            return;
        },
        Ok(client_socket) => client_socket
    };

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    thread::spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = time::now().to_timespec().sec;
            servers.retain(|x| x.last_alive + DROP_TIME > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Vec<String> = Vec::new();
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    thread::spawn(move || {
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                match File::open(BLACKLIST_FILE) {
                    Ok(file) => {
                        let reader = BufReader::new(&file);
                        match reader.lines().collect() {
                            Err(_) => {
                                blacklist_ref.clear();
                            },
                            Ok(t) => {
                                *blacklist_ref = t;
                            }
                        }
                    },
                    Err(_) => {}
                };
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    thread::spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = match stream {
                    Err(_) => continue,
                    Ok(the_stream) => the_stream
                };
                // Unwrap the IP.
                let ip = match client.peer_addr() {
                    Err(_) => continue,
                    Ok(ip) => get_ip(ip)
                };

                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips = ips + &(j.to_string()) + "\n";
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips = ips + &ip + ":49149:3425";

                // We may be here a while. Just in case...
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    // These are the allowed game versions. HaloMD and Halo PC 1.09 uses 01.00.09.0620, while Halo PC servers on 1.10 use 01.00.10.0621 (these are also joinable).
    let game_versions = [ "01.00.09.0620".to_string(), "01.00.10.0621".to_string() ];

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = match halo_socket.recv_from(&mut buffer) {
            Err(_) => continue,
            Ok(x) => x
        };
        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = get_ip(source);

        let blacklist_ref = blacklist_udp.lock().unwrap();
        if blacklist_ref.contains(&client_ip) {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {

            let mut servers = servers_mut_udp.lock().unwrap();

            let packet = HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]);

            if packet.localport != 0 {
                let updatetime = time::now().to_timespec().sec;
                match servers.iter_mut().position(|x| x.ip == client_ip && x.port == packet.localport) {
                    None => {
                        if game_versions.contains(&packet.gamever) && &packet.gamename == HALO_RETAIL {
                            let serverness = HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime };
                            (*servers).push(serverness);
                        }
                    }
                    Some(k) => {
                        servers[k].last_alive = updatetime;
                        if packet.statechanged == GAMEEXITED {
                            servers.remove(k);
                        }
                    }
                };
            }
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if i.ip == client_ip && i.port == source.port() {
                    i.last_alive = time::now().to_timespec().sec;
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Print all available cards in different colors.<commit_after><|endoftext|>


<commit_before>fn main() {
    // All have type `Option<i32>`
    let number   = Some(7);
    let letter: Option<i32> = None;
    let emoticon: Option<i32> = None;

    // The `if let` construct reads: "if `let` destructures `number` into
    // `Some(i)`, evaluate the block (`{}`). Else do nothing.
    if let Some(i) = number {
        println!("Matched {:?}!", i);
    }

    // If you need to specify a failure, use an else:
    if let Some(i) = letter {
        println!("Matched {:?}!", i);
    } else {
        // Destructure failed. Change the failure case.
        println!("Didn't match a number. Let's go with a letter!");
    };

    // Provide an altered failing condition.
    let i_like_letters = false;

    if let Some(i) = emoticon {
        println!("Matched {:?}!", i);
    // Destructure failed. Evaluated the condition to see if this branch
    // should be taken.
    } else if i_like_letters {
        println!("Didn't match a number. Let's go with a letter!");
    // The condition evaluated false. This branch is the default.
    } else {
        println!("I don't like letters. Let's go with an emoticon :)!");
    };
}
<commit_msg>Removed redundancies and added clarification<commit_after>fn main() {
    // All have type `Option<i32>`
    let number = Some(7);
    let letter: Option<i32> = None;
    let emoticon: Option<i32> = None;

    // The `if let` construct reads: "if `let` destructures `number` into
    // `Some(i)`, evaluate the block (`{}`).
    if let Some(i) = number {
        println!("Matched {:?}!", i);
    }

    // If you need to specify a failure, use an else:
    if let Some(i) = letter {
        println!("Matched {:?}!", i);
    } else {
        // Destructure failed. Change to the failure case.
        println!("Didn't match a number. Let's go with a letter!");
    };

    // Provide an altered failing condition.
    let i_like_letters = false;

    if let Some(i) = emoticon {
        println!("Matched {:?}!", i);
    // Destructure failed. Evaluate an `else if` condition to see if the
    // alternate failure branch should be taken:
    } else if i_like_letters {
        println!("Didn't match a number. Let's go with a letter!");
    } else {
        // The condition evaluated false. This branch is the default:
        println!("I don't like letters. Let's go with an emoticon :)!");
    };
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// 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.

extern crate syntax;
extern crate syntax_pos;

use self::syntax::ast::{
    AttrStyle, Attribute, Expr, ExprKind, Ident, ImplItem, ImplItemKind, Item, ItemKind, Mac,
    MetaItem, MetaItemKind, MethodSig, NestedMetaItem, NestedMetaItemKind, TraitItem,
    TraitItemKind, Visibility, WhereClause,
};
use self::syntax::codemap::{self, Spanned};
use self::syntax::fold::{self, Folder};
use self::syntax::parse::lexer::comments;
use self::syntax::parse::token::{DelimToken, Lit, Token};
use self::syntax::ptr::P;
use self::syntax::symbol::Symbol;
use self::syntax::tokenstream::{Delimited, TokenStream, TokenTree};
use self::syntax::util::move_map::MoveMap;
use self::syntax::util::small_vector::SmallVector;

use self::syntax::ast;
use self::syntax_pos::{Span, DUMMY_SP};

struct Respanner;

impl Respanner {
    fn fold_spanned<T>(&mut self, spanned: Spanned<T>) -> Spanned<T> {
        codemap::respan(self.new_span(spanned.span), spanned.node)
    }

    fn fold_lit(&mut self, l: Lit) -> Lit {
        // Give up on comparing literals inside of macros because there are
        // so many equivalent representations of the same literal; they are
        // tested elsewhere
        match l {
            Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
            Lit::Char(_) => Lit::Char(Symbol::intern("")),
            Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
            Lit::Float(_) => Lit::Float(Symbol::intern("")),
            Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
            Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
            _ => l,
        }
    }
}

impl Folder for Respanner {
    fn new_span(&mut self, _: Span) -> Span {
        DUMMY_SP
    }

    fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
        let i = i.map(|mut i| {
            i.tokens = None;
            i
        });
        fold::noop_fold_item(i, self)
    }

    fn fold_item_kind(&mut self, i: ItemKind) -> ItemKind {
        match i {
            ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
                let generics = self.fold_generics(generics);
                let decl = self.fold_fn_decl(decl);
                let body = self.fold_block(body);
                // default fold_item_kind does not fold this span
                let constness = self.fold_spanned(constness);
                ItemKind::Fn(decl, unsafety, constness, abi, generics, body)
            }
            _ => fold::noop_fold_item_kind(i, self),
        }
    }

    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        e.map(|e| {
            let folded = fold::noop_fold_expr(e, self);
            Expr {
                node: match folded.node {
                    ExprKind::Lit(l) => {
                        // default fold_expr does not fold lits
                        ExprKind::Lit(l.map(|l| self.fold_spanned(l)))
                    }
                    ExprKind::Binary(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::Binary(self.fold_spanned(op), lhs, rhs)
                    }
                    ExprKind::AssignOp(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::AssignOp(self.fold_spanned(op), lhs, rhs)
                    }
                    other => other,
                },
                ..folded
            }
        })
    }

    fn fold_trait_item(&mut self, mut i: TraitItem) -> SmallVector<TraitItem> {
        i.tokens = None;
        let noop = fold::noop_fold_trait_item(i, self).expect_one("");
        SmallVector::one(TraitItem {
            node: match noop.node {
                TraitItemKind::Method(sig, body) => TraitItemKind::Method(
                    MethodSig {
                        // default fold_trait_item does not fold this span
                        constness: self.fold_spanned(sig.constness),
                        ..sig
                    },
                    body,
                ),
                node => node,
            },
            ..noop
        })
    }

    fn fold_impl_item(&mut self, mut i: ImplItem) -> SmallVector<ImplItem> {
        i.tokens = None;
        let noop = fold::noop_fold_impl_item(i, self).expect_one("");
        SmallVector::one(ImplItem {
            node: match noop.node {
                ImplItemKind::Method(sig, body) => ImplItemKind::Method(
                    MethodSig {
                        // default fold_impl_item does not fold this span
                        constness: self.fold_spanned(sig.constness),
                        ..sig
                    },
                    body,
                ),
                node => node,
            },
            ..noop
        })
    }

    fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
        at.id.0 = 0;
        at.is_sugared_doc = false;
        fold::noop_fold_attribute(at, self)
    }

    fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
        let MetaItem { ident, node, span } = meta_item;
        MetaItem {
            ident,
            node: match node {
                MetaItemKind::Word => MetaItemKind::Word,
                MetaItemKind::List(nested) => {
                    MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
                }
                // default fold_meta_item does not fold the value span
                MetaItemKind::NameValue(lit) => MetaItemKind::NameValue(self.fold_spanned(lit)),
            },
            span: self.new_span(span),
        }
    }

    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
        Spanned {
            node: match list_item.node {
                NestedMetaItemKind::MetaItem(mi) => {
                    NestedMetaItemKind::MetaItem(self.fold_meta_item(mi))
                }
                // default fold_meta_list_item does not fold the span
                NestedMetaItemKind::Literal(lit) => {
                    NestedMetaItemKind::Literal(self.fold_spanned(lit))
                }
            },
            span: self.new_span(list_item.span),
        }
    }

    // This folder is disabled by default.
    fn fold_mac(&mut self, mac: Mac) -> Mac {
        fold::noop_fold_mac(mac, self)
    }

    fn fold_token(&mut self, t: Token) -> Token {
        fold::noop_fold_token(
            match t {
                // default fold_token does not fold literals
                Token::Literal(lit, repr) => Token::Literal(self.fold_lit(lit), repr),
                _ => t,
            },
            self,
        )
    }

    fn fold_vis(&mut self, vis: Visibility) -> Visibility {
        fold::noop_fold_vis(self.fold_spanned(vis), self)
    }

    fn fold_where_clause(&mut self, mut clause: WhereClause) -> WhereClause {
        // default fold_where_clause does not fold the span
        clause.span = self.new_span(clause.span);
        fold::noop_fold_where_clause(clause, self)
    }

    fn fold_tts(&mut self, tts: TokenStream) -> TokenStream {
        let mut tokens = Vec::new();
        for tt in tts.into_trees() {
            let c = match tt {
                TokenTree::Token(_, Token::DocComment(c)) => c,
                _ => {
                    tokens.push(tt);
                    continue;
                }
            };
            let contents = comments::strip_doc_comment_decoration(&c.as_str());
            let style = comments::doc_comment_style(&c.as_str());
            tokens.push(TokenTree::Token(DUMMY_SP, Token::Pound));
            if style == AttrStyle::Inner {
                tokens.push(TokenTree::Token(DUMMY_SP, Token::Not));
            }
            let lit = Lit::Str_(Symbol::intern(&contents));
            let mut tts = vec![
                TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)),
                TokenTree::Token(DUMMY_SP, Token::Eq),
                TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)),
            ];
            tokens.push(TokenTree::Delimited(
                DUMMY_SP,
                Delimited {
                    delim: DelimToken::Bracket,
                    tts: tts.into_iter().collect::<TokenStream>().into(),
                },
            ));
        }
        tokens.into_iter().map(|tt| self.fold_tt(tt)).collect()
    }
}

#[allow(dead_code)]
pub fn respan_crate(krate: ast::Crate) -> ast::Crate {
    Respanner.fold_crate(krate)
}

#[allow(dead_code)]
pub fn respan_expr(expr: P<ast::Expr>) -> P<ast::Expr> {
    Respanner.fold_expr(expr)
}
<commit_msg>Update test suite to nightly-2018-06-26<commit_after>// Copyright 2018 Syn Developers
//
// 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.

extern crate syntax;
extern crate syntax_pos;

use self::syntax::ast::{
    AttrStyle, Attribute, Expr, ExprKind, FnHeader, Ident, ImplItem, Item, Mac, MetaItem,
    MetaItemKind, NestedMetaItem, NestedMetaItemKind, TraitItem, Visibility, WhereClause,
};
use self::syntax::codemap::{self, Spanned};
use self::syntax::fold::{self, Folder};
use self::syntax::parse::lexer::comments;
use self::syntax::parse::token::{DelimToken, Lit, Token};
use self::syntax::ptr::P;
use self::syntax::symbol::Symbol;
use self::syntax::tokenstream::{Delimited, TokenStream, TokenTree};
use self::syntax::util::move_map::MoveMap;
use self::syntax::util::small_vector::SmallVector;

use self::syntax::ast;
use self::syntax_pos::{Span, DUMMY_SP};

struct Respanner;

impl Respanner {
    fn fold_spanned<T>(&mut self, spanned: Spanned<T>) -> Spanned<T> {
        codemap::respan(self.new_span(spanned.span), spanned.node)
    }

    fn fold_lit(&mut self, l: Lit) -> Lit {
        // Give up on comparing literals inside of macros because there are
        // so many equivalent representations of the same literal; they are
        // tested elsewhere
        match l {
            Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
            Lit::Char(_) => Lit::Char(Symbol::intern("")),
            Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
            Lit::Float(_) => Lit::Float(Symbol::intern("")),
            Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
            Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
            _ => l,
        }
    }
}

impl Folder for Respanner {
    fn new_span(&mut self, _: Span) -> Span {
        DUMMY_SP
    }

    fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
        let i = i.map(|mut i| {
            i.tokens = None;
            i
        });
        fold::noop_fold_item(i, self)
    }

    fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
        FnHeader {
            // default fold_item_kind does not fold this span
            constness: self.fold_spanned(header.constness),
            ..fold::noop_fold_fn_header(header, self)
        }
    }

    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        e.map(|e| {
            let folded = fold::noop_fold_expr(e, self);
            Expr {
                node: match folded.node {
                    ExprKind::Lit(l) => {
                        // default fold_expr does not fold lits
                        ExprKind::Lit(l.map(|l| self.fold_spanned(l)))
                    }
                    ExprKind::Binary(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::Binary(self.fold_spanned(op), lhs, rhs)
                    }
                    ExprKind::AssignOp(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::AssignOp(self.fold_spanned(op), lhs, rhs)
                    }
                    other => other,
                },
                ..folded
            }
        })
    }

    fn fold_trait_item(&mut self, mut i: TraitItem) -> SmallVector<TraitItem> {
        i.tokens = None;
        fold::noop_fold_trait_item(i, self)
    }

    fn fold_impl_item(&mut self, mut i: ImplItem) -> SmallVector<ImplItem> {
        i.tokens = None;
        fold::noop_fold_impl_item(i, self)
    }

    fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
        at.id.0 = 0;
        at.is_sugared_doc = false;
        fold::noop_fold_attribute(at, self)
    }

    fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
        let MetaItem { ident, node, span } = meta_item;
        MetaItem {
            ident,
            node: match node {
                MetaItemKind::Word => MetaItemKind::Word,
                MetaItemKind::List(nested) => {
                    MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
                }
                // default fold_meta_item does not fold the value span
                MetaItemKind::NameValue(lit) => MetaItemKind::NameValue(self.fold_spanned(lit)),
            },
            span: self.new_span(span),
        }
    }

    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
        Spanned {
            node: match list_item.node {
                NestedMetaItemKind::MetaItem(mi) => {
                    NestedMetaItemKind::MetaItem(self.fold_meta_item(mi))
                }
                // default fold_meta_list_item does not fold the span
                NestedMetaItemKind::Literal(lit) => {
                    NestedMetaItemKind::Literal(self.fold_spanned(lit))
                }
            },
            span: self.new_span(list_item.span),
        }
    }

    // This folder is disabled by default.
    fn fold_mac(&mut self, mac: Mac) -> Mac {
        fold::noop_fold_mac(mac, self)
    }

    fn fold_token(&mut self, t: Token) -> Token {
        fold::noop_fold_token(
            match t {
                // default fold_token does not fold literals
                Token::Literal(lit, repr) => Token::Literal(self.fold_lit(lit), repr),
                _ => t,
            },
            self,
        )
    }

    fn fold_vis(&mut self, vis: Visibility) -> Visibility {
        fold::noop_fold_vis(self.fold_spanned(vis), self)
    }

    fn fold_where_clause(&mut self, mut clause: WhereClause) -> WhereClause {
        // default fold_where_clause does not fold the span
        clause.span = self.new_span(clause.span);
        fold::noop_fold_where_clause(clause, self)
    }

    fn fold_tts(&mut self, tts: TokenStream) -> TokenStream {
        let mut tokens = Vec::new();
        for tt in tts.into_trees() {
            let c = match tt {
                TokenTree::Token(_, Token::DocComment(c)) => c,
                _ => {
                    tokens.push(tt);
                    continue;
                }
            };
            let contents = comments::strip_doc_comment_decoration(&c.as_str());
            let style = comments::doc_comment_style(&c.as_str());
            tokens.push(TokenTree::Token(DUMMY_SP, Token::Pound));
            if style == AttrStyle::Inner {
                tokens.push(TokenTree::Token(DUMMY_SP, Token::Not));
            }
            let lit = Lit::Str_(Symbol::intern(&contents));
            let mut tts = vec![
                TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)),
                TokenTree::Token(DUMMY_SP, Token::Eq),
                TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)),
            ];
            tokens.push(TokenTree::Delimited(
                DUMMY_SP,
                Delimited {
                    delim: DelimToken::Bracket,
                    tts: tts.into_iter().collect::<TokenStream>().into(),
                },
            ));
        }
        tokens.into_iter().map(|tt| self.fold_tt(tt)).collect()
    }
}

#[allow(dead_code)]
pub fn respan_crate(krate: ast::Crate) -> ast::Crate {
    Respanner.fold_crate(krate)
}

#[allow(dead_code)]
pub fn respan_expr(expr: P<ast::Expr>) -> P<ast::Expr> {
    Respanner.fold_expr(expr)
}
<|endoftext|>


<commit_before>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate regex;
extern crate rustc_serialize;
extern crate semver;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::env;
use std::io;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use core::shell::ColorConfig::{Auto};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub fn execute_main_without_stdin<T, V>(
                                      exec: fn(T, &Config) -> CliResult<Option<V>>,
                                      options_first: bool,
                                      usage: &str)
    where V: Encodable, T: Decodable
{
    process::<V, _>(|rest, config| {
        call_main_without_stdin(exec, config, usage, rest, options_first)
    });
}

pub fn call_main_without_stdin<T, V>(
            exec: fn(T, &Config) -> CliResult<Option<V>>,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable
{
    let flags = flags_from_args::<T>(usage, args, options_first)?;
    exec(flags, config)
}

fn process<V, F>(mut callback: F)
    where F: FnMut(&[String], &Config) -> CliResult<Option<V>>,
          V: Encodable
{
    let mut config = None;
    let result = (|| {
        config = Some(Config::default()?);
        let args: Vec<_> = try!(env::args_os().map(|s| {
            s.into_string().map_err(|s| {
                human(format!("invalid unicode in argument: {:?}", s))
            })
        }).collect());
        callback(&args, config.as_ref().unwrap())
    })();
    let mut verbose_shell = shell(Verbose, Auto);
    let mut shell = config.as_ref().map(|s| s.shell());
    let shell = shell.as_mut().map(|s| &mut **s).unwrap_or(&mut verbose_shell);
    process_executed(result, shell)
}

pub fn process_executed<T>(result: CliResult<Option<T>>, shell: &mut MultiShell)
    where T: Encodable
{
    match result {
        Err(e) => handle_cli_error(e, shell),
        Ok(Some(encodable)) => {
            let encoded = json::encode(&encodable).unwrap();
            println!("{}", encoded);
        }
        Ok(None) => {}
    }
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn handle_cli_error(err: CliError, shell: &mut MultiShell) {
    debug!("handle_cli_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code);
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}\n", error), BLACK);
    }
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<T>(usage: &str, args: &[String], options_first: bool) -> CliResult<T>
    where T: Decodable
{
    let docopt = Docopt::new(usage).unwrap()
                                   .options_first(options_first)
                                   .argv(args.iter().map(|s| &s[..]))
                                   .help(true);
    docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })
}
<commit_msg>remove newline after stacktrace<commit_after>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate regex;
extern crate rustc_serialize;
extern crate semver;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::env;
use std::io;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use core::shell::ColorConfig::{Auto};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub fn execute_main_without_stdin<T, V>(
                                      exec: fn(T, &Config) -> CliResult<Option<V>>,
                                      options_first: bool,
                                      usage: &str)
    where V: Encodable, T: Decodable
{
    process::<V, _>(|rest, config| {
        call_main_without_stdin(exec, config, usage, rest, options_first)
    });
}

pub fn call_main_without_stdin<T, V>(
            exec: fn(T, &Config) -> CliResult<Option<V>>,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable
{
    let flags = flags_from_args::<T>(usage, args, options_first)?;
    exec(flags, config)
}

fn process<V, F>(mut callback: F)
    where F: FnMut(&[String], &Config) -> CliResult<Option<V>>,
          V: Encodable
{
    let mut config = None;
    let result = (|| {
        config = Some(Config::default()?);
        let args: Vec<_> = try!(env::args_os().map(|s| {
            s.into_string().map_err(|s| {
                human(format!("invalid unicode in argument: {:?}", s))
            })
        }).collect());
        callback(&args, config.as_ref().unwrap())
    })();
    let mut verbose_shell = shell(Verbose, Auto);
    let mut shell = config.as_ref().map(|s| s.shell());
    let shell = shell.as_mut().map(|s| &mut **s).unwrap_or(&mut verbose_shell);
    process_executed(result, shell)
}

pub fn process_executed<T>(result: CliResult<Option<T>>, shell: &mut MultiShell)
    where T: Encodable
{
    match result {
        Err(e) => handle_cli_error(e, shell),
        Ok(Some(encodable)) => {
            let encoded = json::encode(&encodable).unwrap();
            println!("{}", encoded);
        }
        Ok(None) => {}
    }
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn handle_cli_error(err: CliError, shell: &mut MultiShell) {
    debug!("handle_cli_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code);
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<T>(usage: &str, args: &[String], options_first: bool) -> CliResult<T>
    where T: Decodable
{
    let docopt = Docopt::new(usage).unwrap()
                                   .options_first(options_first)
                                   .argv(args.iter().map(|s| &s[..]))
                                   .help(true);
    docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })
}
<|endoftext|>


<commit_before>#![crate_type="dylib"]
#![feature(type_ascription, proc_macro, try_from)]

extern crate intercom;
use intercom::*;
use std::convert::TryFrom;
extern crate winapi;

// Declare available COM classes.
#[com_library( AUTO_GUID,
    RefCountOperations,
    PrimitiveOperations,
    StatefulOperations,
    ResultOperations,
    ClassCreator,
    CreatedClass,
    SharedImplementation,
    ErrorSource,
    AllocTests,
    StringTests,
)]

#[com_interface( AUTO_GUID )]
trait IRefCount
{
    fn get_ref_count( &self ) -> u32;
}

macro_rules! impl_irefcount {
    ( $t:ty ) => {
        #[com_impl]
        impl IRefCount for $t {
            fn get_ref_count( &self ) -> u32
            {
                let combox = unsafe { ComBox::of( self ) };
                combox.get_ref_count()
            }
        }
    }
}

#[com_class("{12341234-1234-1234-1234-123412340001}", PrimitiveOperations )]
pub struct PrimitiveOperations { }

#[com_interface("{12341234-1234-1234-1234-123412340002}")]
#[com_impl]
impl PrimitiveOperations
{
    pub fn new() -> PrimitiveOperations {
        PrimitiveOperations { }
    }

    pub fn i8( &self, v : i8 ) -> i8 { !( v.wrapping_add( 1 ) ) }
    pub fn u8( &self, v : u8 ) -> u8 { !( v.wrapping_add( 1 ) ) }

    pub fn u16( &self, v : u16 ) -> u16 { !( v.wrapping_add( 1 ) ) }
    pub fn i16( &self, v : i16 ) -> i16 { !( v.wrapping_add( 1 ) ) }

    pub fn i32( &self, v : i32 ) -> i32 { !( v.wrapping_add( 1 ) ) }
    pub fn u32( &self, v : u32 ) -> u32 { !( v.wrapping_add( 1 ) ) }

    pub fn i64( &self, v : i64 ) -> i64 { !( v.wrapping_add( 1 ) ) }
    pub fn u64( &self, v : u64 ) -> u64 { !( v.wrapping_add( 1 ) ) }

    pub fn f64( &self, v : f64 ) -> f64 { 1f64 / v }
    pub fn f32( &self, v : f32 ) -> f32 { 1f32 / v }
}

#[com_class( AUTO_GUID, StatefulOperations )]
pub struct StatefulOperations {
    state : i32
}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl StatefulOperations {
    pub fn new() -> StatefulOperations { StatefulOperations { state : 0xABBACD } }
    pub fn put_value( &mut self, v : i32 ) {
        self.state = v;
    }
    pub fn get_value( &mut self ) -> i32 { self.state }
}

#[com_class( AUTO_GUID, ResultOperations )]
pub struct ResultOperations { }

#[com_interface( AUTO_GUID )]
#[com_impl]
impl ResultOperations {
    pub fn new() -> ResultOperations { ResultOperations {} }

    pub fn s_ok( &mut self ) -> HRESULT {
        S_OK
    }

    pub fn not_impl( &mut self ) -> HRESULT {
        E_NOTIMPL
    }

    pub fn sqrt( &mut self, value : f64 ) -> ComResult<f64> {
        if value < 0.0 { return Err( E_INVALIDARG ) }
        Ok( value.sqrt() )
    }

    pub fn tuple( &self, value : u32 ) -> ComResult<( u16, u16 )> {
        let first = u16::try_from( ( value & 0xffff_0000 ) >> 16 ).unwrap();
        let second = u16::try_from( value & 0xffff ).unwrap();

        Ok( ( first, second ) )
    }
}

#[com_class( AUTO_GUID, ClassCreator )]
pub struct ClassCreator { }

#[com_interface( AUTO_GUID )]
#[com_impl]
impl ClassCreator {
    pub fn new() -> ClassCreator { ClassCreator {} }

    pub fn create_root( &self, id : i32 ) -> ComResult<ComItf<CreatedClass>> {
        Ok( ComStruct::new( CreatedClass::new_with_id( id ) ).into() )
    }

    pub fn create_child(
        &self,
        id : i32,
        parent : ComItf<IParent>
    ) -> ComResult<ComItf<CreatedClass>>
    {
        Ok( ComStruct::new(
            CreatedClass::new_child( id, parent.get_id() )
        ).into() )
    }
}

#[com_class( AUTO_GUID, CreatedClass, IParent, IRefCount )]
pub struct CreatedClass { id : i32, parent: i32 }

#[com_interface( AUTO_GUID )]
#[com_impl]
impl CreatedClass {
    pub fn new() -> CreatedClass { unreachable!() }
    pub fn new_with_id( id : i32 ) -> CreatedClass { CreatedClass { id, parent: 0 } }
    pub fn new_child( id : i32, parent : i32 ) -> CreatedClass { CreatedClass { id, parent } }

    pub fn get_id( &self ) -> ComResult<i32> { Ok( self.id ) }
    pub fn get_parent_id( &self ) -> ComResult<i32> { Ok( self.parent ) }
}
impl_irefcount!( CreatedClass );

#[com_interface( AUTO_GUID )]
pub trait IParent {
    fn get_id( &self ) -> i32;
}

#[com_impl]
impl IParent for CreatedClass {
    fn get_id( &self ) -> i32 { self.id }
}

#[com_class( AUTO_GUID, RefCountOperations )]
pub struct RefCountOperations {}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl RefCountOperations {
    pub fn new() -> RefCountOperations { RefCountOperations { } }

    pub fn get_new( &self ) -> ComResult<ComItf<RefCountOperations>> {
        Ok( ComStruct::new( RefCountOperations::new() ).into() )
    }

    pub fn get_ref_count( &self ) -> u32 {
        let combox = unsafe { ComBox::of( self ) };
        combox.get_ref_count()
    }
}

#[com_interface( AUTO_GUID )]
pub trait ISharedInterface {
    fn get_value( &self ) -> u32;
    fn set_value( &mut self, v : u32 );
    fn divide_by( &self, divisor: ComItf<ISharedInterface> ) -> ComResult<u32>;
}

#[com_class( AUTO_GUID, ISharedInterface)]
pub struct SharedImplementation { value: u32 }

impl SharedImplementation {
    pub fn new() -> SharedImplementation { SharedImplementation { value: 0 } }
}

#[com_impl]
impl ISharedInterface for SharedImplementation {
    fn get_value( &self ) -> u32 { self.value }
    fn set_value( &mut self, v : u32 ) { self.value = v }
    fn divide_by( &self, other: ComItf<ISharedInterface> ) -> ComResult<u32> {
        let divisor = other.get_value();
        match divisor {
            0 => Err( intercom::E_INVALIDARG ),
            _ => Ok( self.value / divisor ),
        }
    }
}

#[com_class( AUTO_GUID, ErrorSource)]
pub struct ErrorSource;

#[derive(Debug)]
pub struct TestError( HRESULT, String );
impl std::error::Error for TestError {
    fn description( &self ) -> &str { &self.1 }
    fn cause( &self ) -> Option<&std::error::Error> { None }
}
impl std::fmt::Display for TestError {
    fn fmt( &self, f : &mut std::fmt::Formatter ) -> std::fmt::Result
    {
        write!( f, "{}", self.1 )
    }
}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl ErrorSource
{
    pub fn new() -> ErrorSource { ErrorSource }

    pub fn store_error( &self, hr : HRESULT, desc : String ) -> Result<(), TestError>
    {
        Err( TestError( hr, desc ) )
    }
}

impl From<TestError> for intercom::ComError
{
    fn from( source : TestError ) -> intercom::ComError {
        intercom::ComError::new_message( source.0, source.1 )
    }
}

impl From<intercom::ComError> for TestError
{
    fn from( source : intercom::ComError ) -> TestError {
        TestError(
            source.hresult,
            source.description().unwrap_or( "" ).to_owned() )
    }
}

#[com_class( AUTO_GUID, AllocTests)]
pub struct AllocTests;

#[com_interface( AUTO_GUID )]
#[com_impl]
impl AllocTests
{
    pub fn new() -> AllocTests { AllocTests }

    pub fn get_bstr( &self, value: u32 ) -> String {
        format!( "{}", value )
    }

    pub fn get_bstr_result( &self, value: u32 ) -> ComResult<String> {
        Ok( format!( "{}", value ) )
    }
}

#[com_class( AUTO_GUID, StringTests)]
pub struct StringTests
{
     value: String
}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl StringTests
{
    pub fn new() -> StringTests { StringTests { value: "".to_owned() } }

    pub fn get_value( &self ) -> ComResult<String> {
        Ok( self.value.clone() )
    }

    pub fn put_value( &mut self, value: &str ) {
        self.value = value.to_owned();
    }
}<commit_msg>Add string conversion test methods<commit_after>#![crate_type="dylib"]
#![feature(type_ascription, proc_macro, try_from)]

extern crate intercom;
use intercom::*;
use std::convert::TryFrom;
extern crate winapi;

// Declare available COM classes.
#[com_library( AUTO_GUID,
    RefCountOperations,
    PrimitiveOperations,
    StatefulOperations,
    ResultOperations,
    ClassCreator,
    CreatedClass,
    SharedImplementation,
    ErrorSource,
    AllocTests,
    StringTests,
)]

#[com_interface( AUTO_GUID )]
trait IRefCount
{
    fn get_ref_count( &self ) -> u32;
}

macro_rules! impl_irefcount {
    ( $t:ty ) => {
        #[com_impl]
        impl IRefCount for $t {
            fn get_ref_count( &self ) -> u32
            {
                let combox = unsafe { ComBox::of( self ) };
                combox.get_ref_count()
            }
        }
    }
}

#[com_class("{12341234-1234-1234-1234-123412340001}", PrimitiveOperations )]
pub struct PrimitiveOperations { }

#[com_interface("{12341234-1234-1234-1234-123412340002}")]
#[com_impl]
impl PrimitiveOperations
{
    pub fn new() -> PrimitiveOperations {
        PrimitiveOperations { }
    }

    pub fn i8( &self, v : i8 ) -> i8 { !( v.wrapping_add( 1 ) ) }
    pub fn u8( &self, v : u8 ) -> u8 { !( v.wrapping_add( 1 ) ) }

    pub fn u16( &self, v : u16 ) -> u16 { !( v.wrapping_add( 1 ) ) }
    pub fn i16( &self, v : i16 ) -> i16 { !( v.wrapping_add( 1 ) ) }

    pub fn i32( &self, v : i32 ) -> i32 { !( v.wrapping_add( 1 ) ) }
    pub fn u32( &self, v : u32 ) -> u32 { !( v.wrapping_add( 1 ) ) }

    pub fn i64( &self, v : i64 ) -> i64 { !( v.wrapping_add( 1 ) ) }
    pub fn u64( &self, v : u64 ) -> u64 { !( v.wrapping_add( 1 ) ) }

    pub fn f64( &self, v : f64 ) -> f64 { 1f64 / v }
    pub fn f32( &self, v : f32 ) -> f32 { 1f32 / v }
}

#[com_class( AUTO_GUID, StatefulOperations )]
pub struct StatefulOperations {
    state : i32
}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl StatefulOperations {
    pub fn new() -> StatefulOperations { StatefulOperations { state : 0xABBACD } }
    pub fn put_value( &mut self, v : i32 ) {
        self.state = v;
    }
    pub fn get_value( &mut self ) -> i32 { self.state }
}

#[com_class( AUTO_GUID, ResultOperations )]
pub struct ResultOperations { }

#[com_interface( AUTO_GUID )]
#[com_impl]
impl ResultOperations {
    pub fn new() -> ResultOperations { ResultOperations {} }

    pub fn s_ok( &mut self ) -> HRESULT {
        S_OK
    }

    pub fn not_impl( &mut self ) -> HRESULT {
        E_NOTIMPL
    }

    pub fn sqrt( &mut self, value : f64 ) -> ComResult<f64> {
        if value < 0.0 { return Err( E_INVALIDARG ) }
        Ok( value.sqrt() )
    }

    pub fn tuple( &self, value : u32 ) -> ComResult<( u16, u16 )> {
        let first = u16::try_from( ( value & 0xffff_0000 ) >> 16 ).unwrap();
        let second = u16::try_from( value & 0xffff ).unwrap();

        Ok( ( first, second ) )
    }
}

#[com_class( AUTO_GUID, ClassCreator )]
pub struct ClassCreator { }

#[com_interface( AUTO_GUID )]
#[com_impl]
impl ClassCreator {
    pub fn new() -> ClassCreator { ClassCreator {} }

    pub fn create_root( &self, id : i32 ) -> ComResult<ComItf<CreatedClass>> {
        Ok( ComStruct::new( CreatedClass::new_with_id( id ) ).into() )
    }

    pub fn create_child(
        &self,
        id : i32,
        parent : ComItf<IParent>
    ) -> ComResult<ComItf<CreatedClass>>
    {
        Ok( ComStruct::new(
            CreatedClass::new_child( id, parent.get_id() )
        ).into() )
    }
}

#[com_class( AUTO_GUID, CreatedClass, IParent, IRefCount )]
pub struct CreatedClass { id : i32, parent: i32 }

#[com_interface( AUTO_GUID )]
#[com_impl]
impl CreatedClass {
    pub fn new() -> CreatedClass { unreachable!() }
    pub fn new_with_id( id : i32 ) -> CreatedClass { CreatedClass { id, parent: 0 } }
    pub fn new_child( id : i32, parent : i32 ) -> CreatedClass { CreatedClass { id, parent } }

    pub fn get_id( &self ) -> ComResult<i32> { Ok( self.id ) }
    pub fn get_parent_id( &self ) -> ComResult<i32> { Ok( self.parent ) }
}
impl_irefcount!( CreatedClass );

#[com_interface( AUTO_GUID )]
pub trait IParent {
    fn get_id( &self ) -> i32;
}

#[com_impl]
impl IParent for CreatedClass {
    fn get_id( &self ) -> i32 { self.id }
}

#[com_class( AUTO_GUID, RefCountOperations )]
pub struct RefCountOperations {}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl RefCountOperations {
    pub fn new() -> RefCountOperations { RefCountOperations { } }

    pub fn get_new( &self ) -> ComResult<ComItf<RefCountOperations>> {
        Ok( ComStruct::new( RefCountOperations::new() ).into() )
    }

    pub fn get_ref_count( &self ) -> u32 {
        let combox = unsafe { ComBox::of( self ) };
        combox.get_ref_count()
    }
}

#[com_interface( AUTO_GUID )]
pub trait ISharedInterface {
    fn get_value( &self ) -> u32;
    fn set_value( &mut self, v : u32 );
    fn divide_by( &self, divisor: ComItf<ISharedInterface> ) -> ComResult<u32>;
}

#[com_class( AUTO_GUID, ISharedInterface)]
pub struct SharedImplementation { value: u32 }

impl SharedImplementation {
    pub fn new() -> SharedImplementation { SharedImplementation { value: 0 } }
}

#[com_impl]
impl ISharedInterface for SharedImplementation {
    fn get_value( &self ) -> u32 { self.value }
    fn set_value( &mut self, v : u32 ) { self.value = v }
    fn divide_by( &self, other: ComItf<ISharedInterface> ) -> ComResult<u32> {
        let divisor = other.get_value();
        match divisor {
            0 => Err( intercom::E_INVALIDARG ),
            _ => Ok( self.value / divisor ),
        }
    }
}

#[com_class( AUTO_GUID, ErrorSource)]
pub struct ErrorSource;

#[derive(Debug)]
pub struct TestError( HRESULT, String );
impl std::error::Error for TestError {
    fn description( &self ) -> &str { &self.1 }
    fn cause( &self ) -> Option<&std::error::Error> { None }
}
impl std::fmt::Display for TestError {
    fn fmt( &self, f : &mut std::fmt::Formatter ) -> std::fmt::Result
    {
        write!( f, "{}", self.1 )
    }
}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl ErrorSource
{
    pub fn new() -> ErrorSource { ErrorSource }

    pub fn store_error( &self, hr : HRESULT, desc : String ) -> Result<(), TestError>
    {
        Err( TestError( hr, desc ) )
    }
}

impl From<TestError> for intercom::ComError
{
    fn from( source : TestError ) -> intercom::ComError {
        intercom::ComError::new_message( source.0, source.1 )
    }
}

impl From<intercom::ComError> for TestError
{
    fn from( source : intercom::ComError ) -> TestError {
        TestError(
            source.hresult,
            source.description().unwrap_or( "" ).to_owned() )
    }
}

#[com_class( AUTO_GUID, AllocTests)]
pub struct AllocTests;

#[com_interface( AUTO_GUID )]
#[com_impl]
impl AllocTests
{
    pub fn new() -> AllocTests { AllocTests }

    pub fn get_bstr( &self, value: u32 ) -> String {
        format!( "{}", value )
    }

    pub fn get_bstr_result( &self, value: u32 ) -> ComResult<String> {
        Ok( format!( "{}", value ) )
    }
}

#[com_class( AUTO_GUID, StringTests)]
pub struct StringTests
{
     value: String
}

#[com_interface( AUTO_GUID )]
#[com_impl]
impl StringTests
{
    pub fn new() -> StringTests { StringTests { value: "".to_owned() } }

    pub fn get_value( &self ) -> ComResult<String> {
        Ok( self.value.clone() )
    }

    pub fn put_value( &mut self, value: &str ) {
        self.value = value.to_owned();
    }

    pub fn roundtrip_str<'a>( &self, value: &str ) -> ComResult<String> {
        Ok( value.to_owned() )
    }

    pub fn roundtrip_string( &self, value: String ) -> ComResult<String> {
        Ok( value )
    }

    pub fn roundtrip_bstr( &self, value: &BStr ) -> ComResult<BString> {
        Ok( value.to_owned() )
    }

    pub fn roundtrip_bstring( &self, value: BString ) -> ComResult<BString> {
        Ok( value )
    }
}
<|endoftext|>