<commit_before>use std::sync::{Arc, RwLock};
use subject::{
    self, Subject, Source, Mapper, Receiver, WrapArc, Snapper, Merger,
    WeakSnapperWrapper,
};
use behaviour::{Behaviour, Hold};

pub trait HasSource {
    type Source: Subject;

    fn source(&self) -> &Arc<RwLock<Self::Source>>;
}

pub trait Event: HasSource + Sized {
    fn map(&self, f: F) -> Map
        where B: Send + Sync + Clone,
              F: Fn(A) -> B + Send + Sync,
    {
        Map::new(self, f)
    }

    fn filter<F>(&self, f: F) -> Filter
        where F: Fn(&A) -> bool + Send + Sync,
    {
        Filter::new(self, f)
    }

    fn merge<E: Event>(&self, other: &E) -> Merge {
        Merge::new(self, other)
    }

    fn iter(&self) -> Iter {
        Iter::new(self)
    }

    fn hold(&self, initial: A) -> Hold {
        Hold::new(initial, self)
    }
}

impl<A: Send + Sync + Clone, T: HasSource> Event for T {}

pub struct Sink {
    source: Arc<RwLock<Source>>,
}

impl Sink {
    pub fn new() -> Sink {
        Sink { source: Arc::new(RwLock::new(Source::new())) }
    }
}

impl Sink {
    pub fn send(&self, a: A) {
        self.source.write().unwrap().send(a);
    }
}

impl HasSource for Sink {
    type Source = subject::Source;

    fn source(&self) -> &Arc<RwLock<subject::Source>> {
        &self.source
    }
}

pub struct Map {
    mapper: Arc<RwLock<Mapper>>,
}

impl Map
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    pub fn new<E: Event>(event: &E, f: F) -> Map {
        let map = Map { mapper: Arc::new(RwLock::new(
            Mapper::new(f, event.source().wrap_as_subject())
        )) };
        event.source().write().unwrap().listen(map.mapper.wrap_as_listener());
        map
    }
}

impl HasSource for Map
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    type Source = Mapper;

    fn source(&self) -> &Arc<RwLock<Mapper>> {
        &self.mapper
    }
}

pub struct Filter {
    filter: Arc<RwLock<subject::Filter>>,
}

impl Filter
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    pub fn new<E: Event>(event: &E, f: F) -> Filter {
        let filter = Filter {
            filter: Arc::new(RwLock::new(subject::Filter::new(f, event.source().wrap_as_subject()))),
        };
        event.source().write().unwrap().listen(filter.filter.wrap_as_listener());
        filter
    }
}

impl HasSource for Filter
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    type Source = subject::Filter;

    fn source(&self) -> &Arc<RwLock<subject::Filter>> {
        &self.filter
    }
}

pub struct Merge {
    source: Arc<RwLock<Merger>>,
}

impl Merge
    where A: Send + Sync + Clone,
{
    pub fn new<E1: Event, E2: Event>(event1: &E1, event2: &E2) -> Merge {
        let merge = Merge {
            source: Arc::new(RwLock::new(Merger::new([
                event1.source().wrap_as_subject(),
                event2.source().wrap_as_subject(),
            ]))),
        };
        event1.source().write().unwrap().listen(merge.source.wrap_as_listener());
        event2.source().write().unwrap().listen(merge.source.wrap_as_listener());
        merge
    }
}

impl HasSource for Merge
    where A: Send + Sync + Clone,
{
    type Source = Merger;

    fn source(&self) -> &Arc<RwLock<Merger>> {
        &self.source
    }
}

pub struct Snapshot {
    source: Arc<RwLock<Snapper>>,
}

impl Snapshot
    where A: Send + Sync + Clone, B: Send + Sync + Clone
{
    pub fn new<Be: Behaviour, Ev: Event>(behaviour: &Be, event: &Ev) -> Snapshot {
        let snap = Snapshot {
            source: Arc::new(RwLock::new(Snapper::new(
                behaviour.sample(),
                (behaviour.source().wrap_as_subject(), event.source().wrap_as_subject())
            )))
        };
        behaviour.source().write().unwrap()
            .listen(WeakSnapperWrapper::boxed(&snap.source));
        event.source().write().unwrap().listen(snap.source.wrap_as_listener());
        snap
    }
}

impl HasSource<(A, B)> for Snapshot
    where A: Send + Sync, B: Send + Sync
{
    type Source = Snapper;

    fn source(&self) -> &Arc<RwLock<Snapper>> { &self.source }
}

pub struct Iter {
    recv: Arc<RwLock<Receiver>>,
}

impl Iter {
    fn new<E: Event>(event: &E) -> Iter {
        let iter = Iter {
            recv: Arc::new(RwLock::new(Receiver::new(
                event.source().wrap_as_subject()
            ))),
        };
        event.source().write().unwrap().listen(iter.recv.wrap_as_listener());
        iter
    }
}

impl Iterator for Iter {
    type Item = A;
    fn next(&mut self) -> Option {
        self.recv.write().unwrap().next()
    }
}

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

    #[test]
    fn sink() {
        let sink = Sink::new();
        let mut iter = sink.iter();
        sink.send(1);
        sink.send(2);
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn map() {
        let sink = Sink::new();
        let triple = sink.map(|x| 3 * x);
        let mut iter = triple.iter();
        sink.send(1);
        assert_eq!(iter.next(), Some(3));
    }

    #[test]
    fn filter() {
        let sink = Sink::new();
        let small = sink.filter(|&x: &i32| x < 11);
        let mut iter = small.iter();
        sink.send(12);
        sink.send(9);
        assert_eq!(iter.next(), Some(9));
    }

    #[test]
    fn merge() {
        let sink1 = Sink::new();
        let sink2 = Sink::new();
        let mut iter = sink1.merge(&sink2).iter();
        sink1.send(12);
        sink2.send(9);
        assert_eq!(iter.next(), Some(12));
        assert_eq!(iter.next(), Some(9));
    }

    #[test]
    fn chain_1() {
        let sink = Sink::new();
        let chain = sink.filter(|&x: &i32| x < 20).map(|x| x / 2);
        let mut iter = chain.iter();
        sink.send(4);
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn chain_2() {
        let sink: Sink<i32> = Sink::new();
        let chain = sink.map(|x| x / 2).filter(|&x| x < 3);
        let mut iter = chain.iter();
        sink.send(4);
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn chain_3() {
        let sink1: Sink<i32> = Sink::new();
        let sink2: Sink<i32> = Sink::new();
        let mut iter = sink1.map(|x| x + 4)
            .merge(&sink2.filter(|&x| x < 4).map(|x| x * 5))
            .iter();
        sink1.send(12);
        sink2.send(3);
        assert_eq!(iter.next(), Some(16));
        assert_eq!(iter.next(), Some(15));
    }
}
<commit_msg>Test snapshot<commit_after>use std::sync::{Arc, RwLock};
use subject::{
    self, Subject, Source, Mapper, Receiver, WrapArc, Snapper, Merger,
    WeakSnapperWrapper,
};
use behaviour::{Behaviour, Hold};

pub trait HasSource {
    type Source: Subject;

    fn source(&self) -> &Arc<RwLock<Self::Source>>;
}

pub trait Event: HasSource + Sized {
    fn map(&self, f: F) -> Map
        where B: Send + Sync + Clone,
              F: Fn(A) -> B + Send + Sync,
    {
        Map::new(self, f)
    }

    fn filter<F>(&self, f: F) -> Filter
        where F: Fn(&A) -> bool + Send + Sync,
    {
        Filter::new(self, f)
    }

    fn merge<E: Event>(&self, other: &E) -> Merge {
        Merge::new(self, other)
    }

    fn iter(&self) -> Iter {
        Iter::new(self)
    }

    fn hold(&self, initial: A) -> Hold {
        Hold::new(initial, self)
    }
}

impl<A: Send + Sync + Clone, T: HasSource> Event for T {}

pub struct Sink {
    source: Arc<RwLock<Source>>,
}

impl Sink {
    pub fn new() -> Sink {
        Sink { source: Arc::new(RwLock::new(Source::new())) }
    }
}

impl Sink {
    pub fn send(&self, a: A) {
        self.source.write().unwrap().send(a);
    }
}

impl HasSource for Sink {
    type Source = subject::Source;

    fn source(&self) -> &Arc<RwLock<subject::Source>> {
        &self.source
    }
}

pub struct Map {
    mapper: Arc<RwLock<Mapper>>,
}

impl Map
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    pub fn new<E: Event>(event: &E, f: F) -> Map {
        let map = Map { mapper: Arc::new(RwLock::new(
            Mapper::new(f, event.source().wrap_as_subject())
        )) };
        event.source().write().unwrap().listen(map.mapper.wrap_as_listener());
        map
    }
}

impl HasSource for Map
    where A: Send + Sync + Clone,
          B: Send + Sync + Clone,
          F: Fn(A) -> B + Send + Sync,
{
    type Source = Mapper;

    fn source(&self) -> &Arc<RwLock<Mapper>> {
        &self.mapper
    }
}

pub struct Filter {
    filter: Arc<RwLock<subject::Filter>>,
}

impl Filter
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    pub fn new<E: Event>(event: &E, f: F) -> Filter {
        let filter = Filter {
            filter: Arc::new(RwLock::new(subject::Filter::new(f, event.source().wrap_as_subject()))),
        };
        event.source().write().unwrap().listen(filter.filter.wrap_as_listener());
        filter
    }
}

impl HasSource for Filter
    where A: Send + Sync + Clone,
          F: Fn(&A) -> bool + Send + Sync,
{
    type Source = subject::Filter;

    fn source(&self) -> &Arc<RwLock<subject::Filter>> {
        &self.filter
    }
}

pub struct Merge {
    source: Arc<RwLock<Merger>>,
}

impl Merge
    where A: Send + Sync + Clone,
{
    pub fn new<E1: Event, E2: Event>(event1: &E1, event2: &E2) -> Merge {
        let merge = Merge {
            source: Arc::new(RwLock::new(Merger::new([
                event1.source().wrap_as_subject(),
                event2.source().wrap_as_subject(),
            ]))),
        };
        event1.source().write().unwrap().listen(merge.source.wrap_as_listener());
        event2.source().write().unwrap().listen(merge.source.wrap_as_listener());
        merge
    }
}

impl HasSource for Merge
    where A: Send + Sync + Clone,
{
    type Source = Merger;

    fn source(&self) -> &Arc<RwLock<Merger>> {
        &self.source
    }
}

pub struct Snapshot {
    source: Arc<RwLock<Snapper>>,
}

impl Snapshot
    where A: Send + Sync + Clone, B: Send + Sync + Clone
{
    pub fn new<Be: Behaviour, Ev: Event>(behaviour: &Be, event: &Ev) -> Snapshot {
        let snap = Snapshot {
            source: Arc::new(RwLock::new(Snapper::new(
                behaviour.sample(),
                (behaviour.source().wrap_as_subject(), event.source().wrap_as_subject())
            )))
        };
        behaviour.source().write().unwrap()
            .listen(WeakSnapperWrapper::boxed(&snap.source));
        event.source().write().unwrap().listen(snap.source.wrap_as_listener());
        snap
    }
}

impl HasSource<(A, B)> for Snapshot
    where A: Send + Sync, B: Send + Sync
{
    type Source = Snapper;

    fn source(&self) -> &Arc<RwLock<Snapper>> { &self.source }
}

pub struct Iter {
    recv: Arc<RwLock<Receiver>>,
}

impl Iter {
    fn new<E: Event>(event: &E) -> Iter {
        let iter = Iter {
            recv: Arc::new(RwLock::new(Receiver::new(
                event.source().wrap_as_subject()
            ))),
        };
        event.source().write().unwrap().listen(iter.recv.wrap_as_listener());
        iter
    }
}

impl Iterator for Iter {
    type Item = A;
    fn next(&mut self) -> Option {
        self.recv.write().unwrap().next()
    }
}

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

    #[test]
    fn sink() {
        let sink = Sink::new();
        let mut iter = sink.iter();
        sink.send(1);
        sink.send(2);
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn map() {
        let sink = Sink::new();
        let triple = sink.map(|x| 3 * x);
        let mut iter = triple.iter();
        sink.send(1);
        assert_eq!(iter.next(), Some(3));
    }

    #[test]
    fn filter() {
        let sink = Sink::new();
        let small = sink.filter(|&x: &i32| x < 11);
        let mut iter = small.iter();
        sink.send(12);
        sink.send(9);
        assert_eq!(iter.next(), Some(9));
    }

    #[test]
    fn merge() {
        let sink1 = Sink::new();
        let sink2 = Sink::new();
        let mut iter = sink1.merge(&sink2).iter();
        sink1.send(12);
        sink2.send(9);
        assert_eq!(iter.next(), Some(12));
        assert_eq!(iter.next(), Some(9));
    }

    #[test]
    fn chain_1() {
        let sink = Sink::new();
        let chain = sink.filter(|&x: &i32| x < 20).map(|x| x / 2);
        let mut iter = chain.iter();
        sink.send(4);
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn chain_2() {
        let sink: Sink<i32> = Sink::new();
        let chain = sink.map(|x| x / 2).filter(|&x| x < 3);
        let mut iter = chain.iter();
        sink.send(4);
        assert_eq!(iter.next(), Some(2));
    }

    #[test]
    fn chain_3() {
        let sink1: Sink<i32> = Sink::new();
        let sink2: Sink<i32> = Sink::new();
        let mut iter = sink1.map(|x| x + 4)
            .merge(&sink2.filter(|&x| x < 4).map(|x| x * 5))
            .iter();
        sink1.send(12);
        sink2.send(3);
        assert_eq!(iter.next(), Some(16));
        assert_eq!(iter.next(), Some(15));
    }

    #[test]
    fn snapshot() {
        let sink1: Sink<i32> = Sink::new();
        let sink2: Sink<f64> = Sink::new();
        let mut snap_iter = sink1.hold(1).snapshot(&sink2.map(|x| x + 3.0)).iter();
        sink2.send(4.0);
        assert_eq!(snap_iter.next(), Some((1, 7.0)));
    }
}
<|endoftext|>


<commit_before>extern crate quickcheck;

use self::quickcheck::{Gen, Arbitrary};

use {
    Graph,
    EdgeType,
};
use graph::{
    IndexType,
    node_index,
};
#[cfg(feature = "stable_graph")]
use stable_graph::StableGraph;

use graphmap::{
    GraphMap,
    NodeTrait,
};

/// `Arbitrary` for `Graph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
impl<N, E, Ty, Ix> Arbitrary for Graph<N, E, Ty, Ix>
    where N: Arbitrary,
          E: Arbitrary,
          Ty: EdgeType + Send + 'static,
          Ix: IndexType + Send,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let nodes = usize::arbitrary(g);
        if nodes == 0 {
            return Graph::with_capacity(0, 0);
        }
        // use X² for edge probability (bias towards lower)
        let edge_prob = g.gen_range(0., 1.) * g.gen_range(0., 1.);
        let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
        let mut gr = Graph::with_capacity(nodes, edges);
        for _ in 0..nodes {
            gr.add_node(N::arbitrary(g));
        }
        for i in gr.node_indices() {
            for j in gr.node_indices() {
                if !gr.is_directed() && i > j {
                    continue;
                }
                let p: f64 = g.gen();
                if p <= edge_prob {
                    gr.add_edge(i, j, E::arbitrary(g));
                }
            }
        }
        gr
    }

    // shrink the graph by splitting it in two by a very
    // simple algorithm, just even and odd node indices
    fn shrink(&self) -> Box<Iterator<Item=Self>> {
        let self_ = self.clone();
        Box::new((0..2).filter_map(move |x| {
            let gr = self_.filter_map(|i, w| {
                if i.index() % 2 == x {
                    Some(w.clone())
                } else {
                    None
                }
            },
            |_, w| Some(w.clone())
            );
            // make sure we shrink
            if gr.node_count() < self_.node_count() {
                Some(gr)
            } else {
                None
            }
        }))
    }
}

#[cfg(feature = "stable_graph")]
/// `Arbitrary` for `StableGraph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, with possible
/// self loops, no parallel edges.
impl<N, E, Ty, Ix> Arbitrary for StableGraph<N, E, Ty, Ix>
    where N: Arbitrary,
          E: Arbitrary,
          Ty: EdgeType + Send + 'static,
          Ix: IndexType + Send,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let nodes = usize::arbitrary(g);
        if nodes == 0 {
            return StableGraph::with_capacity(0, 0);
        }
        // use X² for edge probability (bias towards lower)
        let edge_prob = g.gen_range(0., 1.) * g.gen_range(0., 1.);
        let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
        let mut gr = StableGraph::with_capacity(nodes, edges);
        for _ in 0..nodes {
            gr.add_node(N::arbitrary(g));
        }
        for i in 0..gr.node_count() {
            for j in 0..gr.node_count() {
                let i = node_index(i);
                let j = node_index(j);
                if !gr.is_directed() && i > j {
                    continue;
                }
                let p: f64 = g.gen();
                if p <= edge_prob {
                    gr.add_edge(i, j, E::arbitrary(g));
                }
            }
        }
        gr
    }
}

/// `Arbitrary` for `GraphMap` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
impl<N, E, Ty> Arbitrary for GraphMap<N, E, Ty>
    where N: NodeTrait + Arbitrary,
          E: Arbitrary,
          Ty: EdgeType + Clone + Send + 'static,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let nodes = usize::arbitrary(g);
        if nodes == 0 {
            return GraphMap::with_capacity(0, 0);
        }
        let mut nodes = (0..nodes).map(|_| N::arbitrary(g)).collect::<Vec<_>>();
        nodes.sort();
        nodes.dedup();

        // use X² for edge probability (bias towards lower)
        let edge_prob = g.gen_range(0., 1.) * g.gen_range(0., 1.);
        let edges = ((nodes.len() as f64).powi(2) * edge_prob) as usize;
        let mut gr = GraphMap::with_capacity(nodes.len(), edges);
        for &node in &nodes {
            gr.add_node(node);
        }
        for (index, &i) in nodes.iter().enumerate() {
            let js = if Ty::is_directed() { &nodes[..] } else { &nodes[index..] };
            for &j in js {
                let p: f64 = g.gen();
                if p <= edge_prob {
                    gr.add_edge(i, j, E::arbitrary(g));
                }
            }
        }
        gr
    }
}
<commit_msg>FEAT: Arbitrary StableGraph now can have holes<commit_after>extern crate quickcheck;

use self::quickcheck::{Gen, Arbitrary};

use {
    Graph,
    EdgeType,
};
use graph::{
    IndexType,
    node_index,
};
#[cfg(feature = "stable_graph")]
use stable_graph::StableGraph;

use graphmap::{
    GraphMap,
    NodeTrait,
};
use visit::NodeIndexable;

/// `Arbitrary` for `Graph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
impl<N, E, Ty, Ix> Arbitrary for Graph<N, E, Ty, Ix>
    where N: Arbitrary,
          E: Arbitrary,
          Ty: EdgeType + Send + 'static,
          Ix: IndexType + Send,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let nodes = usize::arbitrary(g);
        if nodes == 0 {
            return Graph::with_capacity(0, 0);
        }
        // use X² for edge probability (bias towards lower)
        let edge_prob = g.gen_range(0., 1.) * g.gen_range(0., 1.);
        let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
        let mut gr = Graph::with_capacity(nodes, edges);
        for _ in 0..nodes {
            gr.add_node(N::arbitrary(g));
        }
        for i in gr.node_indices() {
            for j in gr.node_indices() {
                if !gr.is_directed() && i > j {
                    continue;
                }
                let p: f64 = g.gen();
                if p <= edge_prob {
                    gr.add_edge(i, j, E::arbitrary(g));
                }
            }
        }
        gr
    }

    // shrink the graph by splitting it in two by a very
    // simple algorithm, just even and odd node indices
    fn shrink(&self) -> Box<Iterator<Item=Self>> {
        let self_ = self.clone();
        Box::new((0..2).filter_map(move |x| {
            let gr = self_.filter_map(|i, w| {
                if i.index() % 2 == x {
                    Some(w.clone())
                } else {
                    None
                }
            },
            |_, w| Some(w.clone())
            );
            // make sure we shrink
            if gr.node_count() < self_.node_count() {
                Some(gr)
            } else {
                None
            }
        }))
    }
}

#[cfg(feature = "stable_graph")]
/// `Arbitrary` for `StableGraph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, with possible
/// self loops, no parallel edges.
impl<N, E, Ty, Ix> Arbitrary for StableGraph<N, E, Ty, Ix>
    where N: Arbitrary,
          E: Arbitrary,
          Ty: EdgeType + Send + 'static,
          Ix: IndexType + Send,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let nodes = usize::arbitrary(g);
        if nodes == 0 {
            return StableGraph::with_capacity(0, 0);
        }
        // use X² for edge probability (bias towards lower)
        let edge_prob = g.gen_range(0., 1.) * g.gen_range(0., 1.);
        let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
        let mut gr = StableGraph::with_capacity(nodes, edges);
        for _ in 0..nodes {
            gr.add_node(N::arbitrary(g));
        }
        for i in 0..gr.node_count() {
            for j in 0..gr.node_count() {
                let i = node_index(i);
                let j = node_index(j);
                if !gr.is_directed() && i > j {
                    continue;
                }
                let p: f64 = g.gen();
                if p <= edge_prob {
                    gr.add_edge(i, j, E::arbitrary(g));
                }
            }
        }
        if bool::arbitrary(g) {
            // potentially remove nodes to make holes in nodes & edge sets
            let n = u8::arbitrary(g) % (gr.node_count() as u8);
            for _ in 0..n {
                let ni = node_index(usize::arbitrary(g) % gr.node_bound());
                if gr.node_weight(ni).is_some() {
                    gr.remove_node(ni);
                }
            }
        }
        gr
    }
}

/// `Arbitrary` for `GraphMap` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
impl<N, E, Ty> Arbitrary for GraphMap<N, E, Ty>
    where N: NodeTrait + Arbitrary,
          E: Arbitrary,
          Ty: EdgeType + Clone + Send + 'static,
{
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let nodes = usize::arbitrary(g);
        if nodes == 0 {
            return GraphMap::with_capacity(0, 0);
        }
        let mut nodes = (0..nodes).map(|_| N::arbitrary(g)).collect::<Vec<_>>();
        nodes.sort();
        nodes.dedup();

        // use X² for edge probability (bias towards lower)
        let edge_prob = g.gen_range(0., 1.) * g.gen_range(0., 1.);
        let edges = ((nodes.len() as f64).powi(2) * edge_prob) as usize;
        let mut gr = GraphMap::with_capacity(nodes.len(), edges);
        for &node in &nodes {
            gr.add_node(node);
        }
        for (index, &i) in nodes.iter().enumerate() {
            let js = if Ty::is_directed() { &nodes[..] } else { &nodes[index..] };
            for &j in js {
                let p: f64 = g.gen();
                if p <= edge_prob {
                    gr.add_edge(i, j, E::arbitrary(g));
                }
            }
        }
        gr
    }
}
<|endoftext|>


<commit_before>//! This module defines various methods and structs for interacting with uplaods on backblaze.
//!
//! The primary struct in this module is [UploadAuthorization][1], which has various methods for
//! uploading files to backblaze b2. This struct is usually obtained from a [B2Authorization][2]
//! using the method [get_upload_url][3].
//!
//!  [1]: struct.UploadAuthorization.html
//!  [2]: ../authorize/struct.B2Authorization.html
//!  [3]: ../authorize/struct.B2Authorization.html#method.get_upload_url

use std::io::{Write, Read, copy};

use hyper::{self, Client, Url};
use hyper::client::Body;
use hyper::client::request::Request;
use hyper::header::{Headers,ContentLength,ContentType};
use hyper::mime::Mime;
use hyper::method::Method;
use hyper::net::{Streaming, NetworkConnector, NetworkStream};

use serde::Deserialize;
use serde_json;

use B2Error;
use B2AuthHeader;
use raw::authorize::B2Authorization;
use raw::files::MoreFileInfo;
/// Contains the information needed to authorize an upload to b2. This struct is usually obtained
/// from a [B2Authorization][1] using the method [get_upload_url][2].
///
/// The b2 website specifies that you may not upload to the same url in parallel.
///
///  [1]: ../authorize/struct.B2Authorization.html
///  [2]: ../authorize/struct.B2Authorization.html#method.get_upload_url
#[derive(Deserialize,Serialize,Clone,Debug)]
#[serde(rename_all = "camelCase")]
pub struct UploadAuthorization {
    pub bucket_id: String,
    pub upload_url: String,
    pub authorization_token: String
}
impl UploadAuthorization {
    /// Returns a hyper header that authorizes an upload request.
    pub fn auth_header(&self) -> B2AuthHeader {
        B2AuthHeader(self.authorization_token.clone())
    }
}

/// Methods related to the [upload module][1].
///
///  [1]: ../upload/index.html
impl<'a> B2Authorization<'a> {
    /// Performs a [b2_get_upload_url][1] api call and returns the upload url wrapped in an
    /// [`UploadAuthorization`].
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_bucket_not_found`].
    ///
    ///  [1]: https://www.backblaze.com/b2/docs/b2_get_upload_url.html
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_bucket_not_found`]: ../../enum.B2Error.html#method.is_bucket_not_found
    ///  [`UploadAuthorization`]: struct.UploadAuthorization.html
    pub fn get_upload_url(&self, bucket_id: &str, client: &Client)
        -> Result<UploadAuthorization,B2Error>
    {
        let url_string: String = format!("{}/b2api/v1/b2_get_upload_url", self.api_url);
        let url: &str = &url_string;

        #[derive(Serialize)]
        #[serde(rename_all = "camelCase")]
        struct Request<'a> {
            bucket_id: &'a str
        }
        let request = Request {
            bucket_id: bucket_id
        };
        let body: String = serde_json::to_string(&request)?;

        let resp = client.post(url)
            .body(Body::BufBody(body.as_bytes(), body.len()))
            .header(self.auth_header())
            .send()?;
        if resp.status != hyper::status::StatusCode::Ok {
            Err(B2Error::from_response(resp))
        } else {
            Ok(serde_json::from_reader(resp)?)
        }
    }
}
impl UploadAuthorization {
    /// Equivalent to calling [create_upload_file_request][1], writing everything in the Read to
    /// the Writer and calling finish.
    ///
    ///  [1]: struct.UploadAuthorization.html#method.create_upload_file_request
    pub fn upload_file<InfoType, R: Read, C, S>(&self, file: &mut R, file_name: String, content_type: Option<Mime>,
                                 content_length: u64, content_sha1: String, connector: &C)
        -> Result<MoreFileInfo<InfoType>, B2Error>
        where for<'de> InfoType: Deserialize<'de>, R: Sized, C: NetworkConnector<Stream=S>,
              S: Into<Box<NetworkStream + Send>>
    {
        let mut ufr = self.create_upload_file_request(
            file_name, content_type, content_length, content_sha1, connector)?;
        copy(file, &mut ufr)?;
        ufr.finish()
    }
    /// Starts a request to upload a file to backblaze b2. This function returns an
    /// [UploadFileRequest][1], which implements [Write][2]. When writing to this object, the
    /// data is sent to backblaze b2. This method of uploading can be used to
    /// implement things such as rate limiting of the request.
    ///
    /// After the file has been sent, you need to call the [finish method][3] on the
    /// [UploadFileRequest][1], in order to close the connection.
    ///
    /// The [upload_file method][4] can be used to upload any Reader easily. The backblaze api
    /// supports not specifying the sha1 checksum. This is not recommended, but if you wish to do
    /// this, simply pass the string `do_not_verify` as the sha1 checksum.
    ///
    /// The function [create_upload_file_request_sha1_at_end][5] might be of interest. This
    /// function behaves identically to this function, except the sha1 is passed when calling
    /// finish instead of before initiating the request.
    ///
    /// Read the [backblaze api documentation][6] for more information.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_invalid_file_name`] and [`is_cap_exceeded`].
    ///
    ///  [1]: struct.UploadFileRequest.html
    ///  [2]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
    ///  [3]: struct.UploadFileRequest.html#method.finish
    ///  [4]: struct.UploadAuthorization.html#method.upload_file
    ///  [5]: struct.UploadFileRequest.html#method.create_upload_file_request_sha1_at_end
    ///  [6]: https://www.backblaze.com/b2/docs/uploading.html
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_invalid_file_name`]: ../../enum.B2Error.html#method.is_invalid_file_name
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    pub fn create_upload_file_request<C,S>(&self, file_name: String,
                                           content_type: Option<Mime>,
                                           content_length: u64, content_sha1: String,
                                           connector: &C)
        -> Result<UploadFileRequest, B2Error>
        where C: NetworkConnector<Stream=S>, S: Into<Box<NetworkStream + Send>>
    {
        let url: Url = Url::parse(&self.upload_url)?;
        let mut request = Request::with_connector(Method::Post, url, connector)?;
        {
            let headers: &mut Headers = request.headers_mut();
            headers.set(self.auth_header());
            headers.set(XBzFileName(file_name));
            headers.set(XBzContentSha1(content_sha1));
            headers.set(ContentLength(content_length));
            headers.set(ContentType(match content_type {
                Some(v) => v,
                None => "b2/x-auto".parse().unwrap()
            }));
        }
        Ok(UploadFileRequest { request: request.start()? })
    }
    /// Starts a request to upload a file to backblaze b2. This function returns an
    /// [UploadFileRequestSha1End][1], which implements [Write][2]. When writing to this object,
    /// the data is sent to backblaze b2. This method of uploading can be used to implement things
    /// such as rate limiting of the request.
    ///
    /// After the file has been sent, you need to call the [finish method][3] on the
    /// [UploadFileRequestSha1End][1], in order to close the connection.
    ///
    /// Read the [backblaze api documentation][4] for more information.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_invalid_file_name`] and [`is_cap_exceeded`].
    ///
    ///  [1]: struct.UploadFileRequestSha1End.html
    ///  [2]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
    ///  [3]: struct.UploadFileRequestSha1End.html#method.finish
    ///  [4]: https://www.backblaze.com/b2/docs/uploading.html
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_invalid_file_name`]: ../../enum.B2Error.html#method.is_invalid_file_name
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    pub fn create_upload_file_request_sha1_at_end<C,S>(&self, file_name: String,
                                                       content_type: Option<Mime>,
                                                       content_length: u64,
                                                       connector: &C)
        -> Result<UploadFileRequestSha1End, B2Error>
        where C: NetworkConnector<Stream=S>, S: Into<Box<NetworkStream + Send>>
    {
        let url: Url = Url::parse(&self.upload_url)?;
        let mut request = Request::with_connector(Method::Post, url, connector)?;
        {
            let headers: &mut Headers = request.headers_mut();
            headers.set(self.auth_header());
            headers.set(XBzFileName(file_name));
            headers.set(XBzContentSha1("hex_digits_at_end".to_owned()));
            headers.set(ContentLength(content_length + 40));
            headers.set(ContentType(match content_type {
                Some(v) => v,
                None => "b2/x-auto".parse().unwrap()
            }));
        }
        Ok(UploadFileRequestSha1End { request: request.start()? })
    }
}
header! { (XBzFileName, "X-Bz-File-Name") => [String] }
header! { (XBzContentSha1, "X-Bz-Content-Sha1") => [String] }

/// Contains an ongoing upload to the backblaze b2 api. This struct is created by the
/// [`create_upload_file_request`] method.
///
///  [`create_upload_file_request`]: struct.UploadAuthorization.html#method.create_upload_file_request
pub struct UploadFileRequest {
    request: Request<Streaming>
}
impl Write for UploadFileRequest {
    fn write(&mut self, msg: &[u8]) -> ::std::io::Result<usize> {
        self.request.write(msg)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.request.flush()
    }
    fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
        self.request.write_all(buf)
    }
    fn write_fmt(&mut self, fmt: ::core::fmt::Arguments) -> Result<(), ::std::io::Error> {
        self.request.write_fmt(fmt)
    }
}
impl UploadFileRequest {
    /// Finishes the upload of the file and returns information about the uploaded file.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_cap_exceeded`], [`is_invalid_sha1`].
    ///
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    ///  [`is_invalid_sha1`]: ../../enum.B2Error.html#method.is_invalid_sha1
    pub fn finish<InfoType>(self) -> Result<MoreFileInfo<InfoType>, B2Error>
        where for<'de> InfoType: Deserialize<'de>
    {
        let resp = self.request.send()?;
        if resp.status != hyper::status::StatusCode::Ok {
            Err(B2Error::from_response(resp))
        } else {
            Ok(serde_json::from_reader(resp)?)
        }
    }
}
/// Contains an ongoing upload to the backblaze b2 api. This struct is created by the
/// [create_upload_file_request_sha1_at_end][1] method.
///
///  [1]: struct.UploadAuthorization.html#method.create_upload_file_request_sha1_at_end
pub struct UploadFileRequestSha1End {
    request: Request<Streaming>
}
impl Write for UploadFileRequestSha1End {
    fn write(&mut self, msg: &[u8]) -> ::std::io::Result<usize> {
        self.request.write(msg)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.request.flush()
    }
    fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
        self.request.write_all(buf)
    }
    fn write_fmt(&mut self, fmt: ::core::fmt::Arguments) -> Result<(), ::std::io::Error> {
        self.request.write_fmt(fmt)
    }
}
impl UploadFileRequestSha1End {
    /// Finishes the upload of the file and returns information about the uploaded file. The `sha1`
    /// argument must be the ascii encoding of the sha1 of the file.
    ///
    /// The sha1 should be 40 bytes long, but this is not checked at runtime.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_cap_exceeded`], [`is_invalid_sha1`].
    ///
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    ///  [`is_invalid_sha1`]: ../../enum.B2Error.html#method.is_invalid_sha1
    pub fn finish<InfoType>(mut self, sha1: &str) -> Result<MoreFileInfo<InfoType>, B2Error>
        where for<'de> InfoType: Deserialize<'de>
    {
        self.request.write_all(sha1.as_bytes())?;
        let resp = self.request.send()?;
        if resp.status != hyper::status::StatusCode::Ok {
            Err(B2Error::from_response(resp))
        } else {
            Ok(serde_json::from_reader(resp)?)
        }
    }
}

<commit_msg>add note about content length and sha1 at end<commit_after>//! This module defines various methods and structs for interacting with uplaods on backblaze.
//!
//! The primary struct in this module is [UploadAuthorization][1], which has various methods for
//! uploading files to backblaze b2. This struct is usually obtained from a [B2Authorization][2]
//! using the method [get_upload_url][3].
//!
//!  [1]: struct.UploadAuthorization.html
//!  [2]: ../authorize/struct.B2Authorization.html
//!  [3]: ../authorize/struct.B2Authorization.html#method.get_upload_url

use std::io::{Write, Read, copy};

use hyper::{self, Client, Url};
use hyper::client::Body;
use hyper::client::request::Request;
use hyper::header::{Headers,ContentLength,ContentType};
use hyper::mime::Mime;
use hyper::method::Method;
use hyper::net::{Streaming, NetworkConnector, NetworkStream};

use serde::Deserialize;
use serde_json;

use B2Error;
use B2AuthHeader;
use raw::authorize::B2Authorization;
use raw::files::MoreFileInfo;
/// Contains the information needed to authorize an upload to b2. This struct is usually obtained
/// from a [B2Authorization][1] using the method [get_upload_url][2].
///
/// The b2 website specifies that you may not upload to the same url in parallel.
///
///  [1]: ../authorize/struct.B2Authorization.html
///  [2]: ../authorize/struct.B2Authorization.html#method.get_upload_url
#[derive(Deserialize,Serialize,Clone,Debug)]
#[serde(rename_all = "camelCase")]
pub struct UploadAuthorization {
    pub bucket_id: String,
    pub upload_url: String,
    pub authorization_token: String
}
impl UploadAuthorization {
    /// Returns a hyper header that authorizes an upload request.
    pub fn auth_header(&self) -> B2AuthHeader {
        B2AuthHeader(self.authorization_token.clone())
    }
}

/// Methods related to the [upload module][1].
///
///  [1]: ../upload/index.html
impl<'a> B2Authorization<'a> {
    /// Performs a [b2_get_upload_url][1] api call and returns the upload url wrapped in an
    /// [`UploadAuthorization`].
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_bucket_not_found`].
    ///
    ///  [1]: https://www.backblaze.com/b2/docs/b2_get_upload_url.html
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_bucket_not_found`]: ../../enum.B2Error.html#method.is_bucket_not_found
    ///  [`UploadAuthorization`]: struct.UploadAuthorization.html
    pub fn get_upload_url(&self, bucket_id: &str, client: &Client)
        -> Result<UploadAuthorization,B2Error>
    {
        let url_string: String = format!("{}/b2api/v1/b2_get_upload_url", self.api_url);
        let url: &str = &url_string;

        #[derive(Serialize)]
        #[serde(rename_all = "camelCase")]
        struct Request<'a> {
            bucket_id: &'a str
        }
        let request = Request {
            bucket_id: bucket_id
        };
        let body: String = serde_json::to_string(&request)?;

        let resp = client.post(url)
            .body(Body::BufBody(body.as_bytes(), body.len()))
            .header(self.auth_header())
            .send()?;
        if resp.status != hyper::status::StatusCode::Ok {
            Err(B2Error::from_response(resp))
        } else {
            Ok(serde_json::from_reader(resp)?)
        }
    }
}
impl UploadAuthorization {
    /// Equivalent to calling [create_upload_file_request][1], writing everything in the Read to
    /// the Writer and calling finish.
    ///
    ///  [1]: struct.UploadAuthorization.html#method.create_upload_file_request
    pub fn upload_file<InfoType, R: Read, C, S>(&self, file: &mut R, file_name: String, content_type: Option<Mime>,
                                 content_length: u64, content_sha1: String, connector: &C)
        -> Result<MoreFileInfo<InfoType>, B2Error>
        where for<'de> InfoType: Deserialize<'de>, R: Sized, C: NetworkConnector<Stream=S>,
              S: Into<Box<NetworkStream + Send>>
    {
        let mut ufr = self.create_upload_file_request(
            file_name, content_type, content_length, content_sha1, connector)?;
        copy(file, &mut ufr)?;
        ufr.finish()
    }
    /// Starts a request to upload a file to backblaze b2. This function returns an
    /// [UploadFileRequest][1], which implements [Write][2]. When writing to this object, the
    /// data is sent to backblaze b2. This method of uploading can be used to
    /// implement things such as rate limiting of the request.
    ///
    /// After the file has been sent, you need to call the [finish method][3] on the
    /// [UploadFileRequest][1], in order to close the connection.
    ///
    /// The [upload_file method][4] can be used to upload any Reader easily. The backblaze api
    /// supports not specifying the sha1 checksum. This is not recommended, but if you wish to do
    /// this, simply pass the string `do_not_verify` as the sha1 checksum.
    ///
    /// The function [create_upload_file_request_sha1_at_end][5] might be of interest. This
    /// function behaves identically to this function, except the sha1 is passed when calling
    /// finish instead of before initiating the request.
    ///
    /// Read the [backblaze api documentation][6] for more information.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_invalid_file_name`] and [`is_cap_exceeded`].
    ///
    ///  [1]: struct.UploadFileRequest.html
    ///  [2]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
    ///  [3]: struct.UploadFileRequest.html#method.finish
    ///  [4]: struct.UploadAuthorization.html#method.upload_file
    ///  [5]: struct.UploadFileRequest.html#method.create_upload_file_request_sha1_at_end
    ///  [6]: https://www.backblaze.com/b2/docs/uploading.html
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_invalid_file_name`]: ../../enum.B2Error.html#method.is_invalid_file_name
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    pub fn create_upload_file_request<C,S>(&self, file_name: String,
                                           content_type: Option<Mime>,
                                           content_length: u64, content_sha1: String,
                                           connector: &C)
        -> Result<UploadFileRequest, B2Error>
        where C: NetworkConnector<Stream=S>, S: Into<Box<NetworkStream + Send>>
    {
        let url: Url = Url::parse(&self.upload_url)?;
        let mut request = Request::with_connector(Method::Post, url, connector)?;
        {
            let headers: &mut Headers = request.headers_mut();
            headers.set(self.auth_header());
            headers.set(XBzFileName(file_name));
            headers.set(XBzContentSha1(content_sha1));
            headers.set(ContentLength(content_length));
            headers.set(ContentType(match content_type {
                Some(v) => v,
                None => "b2/x-auto".parse().unwrap()
            }));
        }
        Ok(UploadFileRequest { request: request.start()? })
    }
    /// Starts a request to upload a file to backblaze b2. This function returns an
    /// [UploadFileRequestSha1End][1], which implements [Write][2]. When writing to this object,
    /// the data is sent to backblaze b2. This method of uploading can be used to implement things
    /// such as rate limiting of the request.
    ///
    /// The value of the `content_length` parameter must be exactly the amount of bytes you are
    /// going to write, not including the 40 byte sha1 appended by the [finish method][3].
    ///
    /// After the file has been sent, you need to call the [finish method][3] on the
    /// [UploadFileRequestSha1End][1], in order to close the connection.
    ///
    /// Read the [backblaze api documentation][4] for more information.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_invalid_file_name`] and [`is_cap_exceeded`].
    ///
    ///  [1]: struct.UploadFileRequestSha1End.html
    ///  [2]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
    ///  [3]: struct.UploadFileRequestSha1End.html#method.finish
    ///  [4]: https://www.backblaze.com/b2/docs/uploading.html
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_invalid_file_name`]: ../../enum.B2Error.html#method.is_invalid_file_name
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    pub fn create_upload_file_request_sha1_at_end<C,S>(&self, file_name: String,
                                                       content_type: Option<Mime>,
                                                       content_length: u64,
                                                       connector: &C)
        -> Result<UploadFileRequestSha1End, B2Error>
        where C: NetworkConnector<Stream=S>, S: Into<Box<NetworkStream + Send>>
    {
        let url: Url = Url::parse(&self.upload_url)?;
        let mut request = Request::with_connector(Method::Post, url, connector)?;
        {
            let headers: &mut Headers = request.headers_mut();
            headers.set(self.auth_header());
            headers.set(XBzFileName(file_name));
            headers.set(XBzContentSha1("hex_digits_at_end".to_owned()));
            headers.set(ContentLength(content_length + 40));
            headers.set(ContentType(match content_type {
                Some(v) => v,
                None => "b2/x-auto".parse().unwrap()
            }));
        }
        Ok(UploadFileRequestSha1End { request: request.start()? })
    }
}
header! { (XBzFileName, "X-Bz-File-Name") => [String] }
header! { (XBzContentSha1, "X-Bz-Content-Sha1") => [String] }

/// Contains an ongoing upload to the backblaze b2 api. This struct is created by the
/// [`create_upload_file_request`] method.
///
///  [`create_upload_file_request`]: struct.UploadAuthorization.html#method.create_upload_file_request
pub struct UploadFileRequest {
    request: Request<Streaming>
}
impl Write for UploadFileRequest {
    fn write(&mut self, msg: &[u8]) -> ::std::io::Result<usize> {
        self.request.write(msg)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.request.flush()
    }
    fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
        self.request.write_all(buf)
    }
    fn write_fmt(&mut self, fmt: ::core::fmt::Arguments) -> Result<(), ::std::io::Error> {
        self.request.write_fmt(fmt)
    }
}
impl UploadFileRequest {
    /// Finishes the upload of the file and returns information about the uploaded file.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_cap_exceeded`], [`is_invalid_sha1`].
    ///
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    ///  [`is_invalid_sha1`]: ../../enum.B2Error.html#method.is_invalid_sha1
    pub fn finish<InfoType>(self) -> Result<MoreFileInfo<InfoType>, B2Error>
        where for<'de> InfoType: Deserialize<'de>
    {
        let resp = self.request.send()?;
        if resp.status != hyper::status::StatusCode::Ok {
            Err(B2Error::from_response(resp))
        } else {
            Ok(serde_json::from_reader(resp)?)
        }
    }
}
/// Contains an ongoing upload to the backblaze b2 api. This struct is created by the
/// [create_upload_file_request_sha1_at_end][1] method.
///
///  [1]: struct.UploadAuthorization.html#method.create_upload_file_request_sha1_at_end
pub struct UploadFileRequestSha1End {
    request: Request<Streaming>
}
impl Write for UploadFileRequestSha1End {
    fn write(&mut self, msg: &[u8]) -> ::std::io::Result<usize> {
        self.request.write(msg)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.request.flush()
    }
    fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
        self.request.write_all(buf)
    }
    fn write_fmt(&mut self, fmt: ::core::fmt::Arguments) -> Result<(), ::std::io::Error> {
        self.request.write_fmt(fmt)
    }
}
impl UploadFileRequestSha1End {
    /// Finishes the upload of the file and returns information about the uploaded file. The `sha1`
    /// argument must be the ascii encoding of the sha1 of the file.
    ///
    /// The sha1 should be 40 bytes long, but this is not checked at runtime.
    ///
    /// # Errors
    /// This function returns a [`B2Error`] in case something goes wrong. Besides the standard
    /// errors, this function can fail with [`is_cap_exceeded`], [`is_invalid_sha1`].
    ///
    ///  [`B2Error`]: ../authorize/enum.B2Error.html
    ///  [`is_cap_exceeded`]: ../../enum.B2Error.html#method.is_cap_exceeded
    ///  [`is_invalid_sha1`]: ../../enum.B2Error.html#method.is_invalid_sha1
    pub fn finish<InfoType>(mut self, sha1: &str) -> Result<MoreFileInfo<InfoType>, B2Error>
        where for<'de> InfoType: Deserialize<'de>
    {
        self.request.write_all(sha1.as_bytes())?;
        let resp = self.request.send()?;
        if resp.status != hyper::status::StatusCode::Ok {
            Err(B2Error::from_response(resp))
        } else {
            Ok(serde_json::from_reader(resp)?)
        }
    }
}

<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// no-pretty-expanded FIXME #15189
// ignore-windows FIXME #13259

#![feature(unboxed_closures)]
#![feature(unsafe_destructor)]

use std::env;
use std::old_io::process::Command;
use std::str;
use std::ops::{Drop, FnMut, FnOnce};

#[inline(never)]
fn foo() {
    let _v = vec![1, 2, 3];
    if env::var_os("IS_TEST").is_some() {
        panic!()
    }
}

#[inline(never)]
fn double() {
    struct Double;

    impl Drop for Double {
        fn drop(&mut self) { panic!("twice") }
    }

    let _d = Double;

    panic!("once");
}

fn runtest(me: &str) {
    let mut template = Command::new(me);
    template.env("IS_TEST", "1");

    // Make sure that the stack trace is printed
    let p = template.clone().arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    assert!(s.contains("stack backtrace") && s.contains("foo::h"),
            "bad output: {}", s);

    // Make sure the stack trace is *not* printed
    let p = template.clone().arg("fail").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    assert!(!s.contains("stack backtrace") && !s.contains("foo::h"),
            "bad output2: {}", s);

    // Make sure a stack trace is printed
    let p = template.clone().arg("double-fail").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    // loosened the following from double::h to double:: due to
    // spurious failures on mac, 32bit, optimized
    assert!(s.contains("stack backtrace") && s.contains("double::"),
            "bad output3: {}", s);

    // Make sure a stack trace isn't printed too many times
    let p = template.clone().arg("double-fail")
                                .env("RUST_BACKTRACE", "1").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    let mut i = 0;
    for _ in 0..2 {
        i += s[i + 10..].find_str("stack backtrace").unwrap() + 10;
    }
    assert!(s[i + 10..].find_str("stack backtrace").is_none(),
            "bad output4: {}", s);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() >= 2 && args[1] == "fail" {
        foo();
    } else if args.len() >= 2 && args[1] == "double-fail" {
        double();
    } else {
        runtest(&args[0]);
    }
}
<commit_msg>Make `test/run-pass/backtrace.rs` more robust about own host environment.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// no-pretty-expanded FIXME #15189
// ignore-windows FIXME #13259

#![feature(unboxed_closures)]
#![feature(unsafe_destructor)]

use std::env;
use std::old_io::process::Command;
use std::str;
use std::ops::{Drop, FnMut, FnOnce};

#[inline(never)]
fn foo() {
    let _v = vec![1, 2, 3];
    if env::var_os("IS_TEST").is_some() {
        panic!()
    }
}

#[inline(never)]
fn double() {
    struct Double;

    impl Drop for Double {
        fn drop(&mut self) { panic!("twice") }
    }

    let _d = Double;

    panic!("once");
}

fn runtest(me: &str) {
    let mut template = Command::new(me);
    template.env("IS_TEST", "1");

    // Make sure that the stack trace is printed
    let p = template.clone().arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    assert!(s.contains("stack backtrace") && s.contains("foo::h"),
            "bad output: {}", s);

    // Make sure the stack trace is *not* printed
    // (Remove RUST_BACKTRACE from our own environment, in case developer
    // is running `make check` with it on.)
    let p = template.clone().arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    assert!(!s.contains("stack backtrace") && !s.contains("foo::h"),
            "bad output2: {}", s);

    // Make sure a stack trace is printed
    let p = template.clone().arg("double-fail").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    // loosened the following from double::h to double:: due to
    // spurious failures on mac, 32bit, optimized
    assert!(s.contains("stack backtrace") && s.contains("double::"),
            "bad output3: {}", s);

    // Make sure a stack trace isn't printed too many times
    let p = template.clone().arg("double-fail")
                                .env("RUST_BACKTRACE", "1").spawn().unwrap();
    let out = p.wait_with_output().unwrap();
    assert!(!out.status.success());
    let s = str::from_utf8(&out.error).unwrap();
    let mut i = 0;
    for _ in 0..2 {
        i += s[i + 10..].find_str("stack backtrace").unwrap() + 10;
    }
    assert!(s[i + 10..].find_str("stack backtrace").is_none(),
            "bad output4: {}", s);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() >= 2 && args[1] == "fail" {
        foo();
    } else if args.len() >= 2 && args[1] == "double-fail" {
        double();
    } else {
        runtest(&args[0]);
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use http::method::Method;
use iron::{Middleware, Request, Response, Alloy};
use iron::middleware::{Status, Continue, Unwind};
use iron::mixin::GetUrl;

pub mod params;
mod glob;

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
#[deriving(Clone)]
pub struct Router {
    routes: Vec<Route>
}

struct Route {
    method: Method,
    glob: String,
    matches: Regex,
    handler: Box<Middleware + Send>,
    params: Vec<String>
}

impl Clone for Route {
    fn clone(&self) -> Route {
        Route {
            method: self.method.clone(),
            glob: self.glob.clone(),
            matches: self.matches.clone(),
            handler: self.handler.clone_box(),
            params: self.params.clone()
        }
    }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routes: Vec::new() } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports express-style glob patterns: `*` for a single wildcard
    /// segment, `**` for any-number of wildcard segments, and `:param` for
    /// matching storing that segment of the request url in the `Params`
    /// object, which is stored on an Alloy.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```rust
    /// router.route(
    ///     ::http::method::Get /* The HTTP verb */,
    ///     '/users/:userid/:friend'.to_string() /* A glob pattern to match */,
    ///     controller /* Any Middleware */);
    /// ```
    ///
    /// The controller provided to route can be any `Middleware`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Middleware`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<M: Middleware + Send>(&mut self, method: Method, glob: String,
                                       params: Vec<String>, handler: M) {
        self.routes.push(Route {
            method: method,
            glob: glob.clone(),
            matches: glob::deglob(glob),
            handler: box handler,
            params: params
        });
    }
}

impl Middleware for Router {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        let request_uri = match req.url() {
            Some(uri) => uri.clone(),
            // Not an AbsolutePath, not our problem.
            None => { return Continue; }
        };

        for route in self.routes.mut_iter() {
            if route.matches.is_match(request_uri.as_slice()) {
                alloy.insert::<params::Params>(
                    params::Params::new(
                        request_uri.as_slice(),
                        route.matches.clone(),
                        route.params.clone().move_iter()
                    )
                );
                let _ = route.handler.enter(req, res, alloy);
                let _ = route.handler.exit(req, res, alloy);
                return Unwind;
            }
        }
        Continue
    }
}

<commit_msg>(fix) Removed breaking comments.<commit_after>use regex::Regex;
use http::method::Method;
use iron::{Middleware, Request, Response, Alloy};
use iron::middleware::{Status, Continue, Unwind};
use iron::mixin::GetUrl;

pub mod params;
mod glob;

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
#[deriving(Clone)]
pub struct Router {
    routes: Vec<Route>
}

struct Route {
    method: Method,
    glob: String,
    matches: Regex,
    handler: Box<Middleware + Send>,
    params: Vec<String>
}

impl Clone for Route {
    fn clone(&self) -> Route {
        Route {
            method: self.method.clone(),
            glob: self.glob.clone(),
            matches: self.matches.clone(),
            handler: self.handler.clone_box(),
            params: self.params.clone()
        }
    }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routes: Vec::new() } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports express-style glob patterns: `*` for a single wildcard
    /// segment, `**` for any-number of wildcard segments, and `:param` for
    /// matching storing that segment of the request url in the `Params`
    /// object, which is stored on an Alloy.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```rust
    /// router.route(
    ///     ::http::method::Get,
    ///     "/users/:userid/:friend".to_string(),
    ///     controller
    /// ```
    ///
    /// The controller provided to route can be any `Middleware`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Middleware`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<M: Middleware + Send>(&mut self, method: Method, glob: String,
                                       params: Vec<String>, handler: M) {
        self.routes.push(Route {
            method: method,
            glob: glob.clone(),
            matches: glob::deglob(glob),
            handler: box handler,
            params: params
        });
    }
}

impl Middleware for Router {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        let request_uri = match req.url() {
            Some(uri) => uri.clone(),
            // Not an AbsolutePath, not our problem.
            None => { return Continue; }
        };

        for route in self.routes.mut_iter() {
            if route.matches.is_match(request_uri.as_slice()) {
                alloy.insert::<params::Params>(
                    params::Params::new(
                        request_uri.as_slice(),
                        route.matches.clone(),
                        route.params.clone().move_iter()
                    )
                );
                let _ = route.handler.enter(req, res, alloy);
                let _ = route.handler.exit(req, res, alloy);
                return Unwind;
            }
        }
        Continue
    }
}

<|endoftext|>


<commit_before>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  fn unsafe_pop(&mut self) -> Expr {
    self.stack.pop().expect("VM error: stack is empty")
  }

  pub fn run(&mut self) {
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false; // comparison carry

    let labels = parse_labels(&self.instructions);

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["$label", _] => (),
        ["push", "int", n] => self.stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => self.stack.push(Expr::Str(String::from(n))),

        ["dup"] => {
          let expr = self.unsafe_pop();
          self.stack.push(expr.clone());
          self.stack.push(expr);
        },

        // convert to string
        ["convert", "int", "str"] => if let Some(&Expr::Int(arg)) = self.stack.last() {
          self.stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        ["convert", from, to] => panic!("VM error: cannot convert from {} to {}", from, to),

        // how = "always" | "carry"
        ["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "say"] => if let Some(Expr::Str(arg)) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          self.stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `add`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>Split call/call primitive<commit_after>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  fn unsafe_pop(&mut self) -> Expr {
    self.stack.pop().expect("VM error: stack is empty")
  }

  pub fn run(&mut self) {
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false; // comparison carry

    let labels = parse_labels(&self.instructions);

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["$label", _] => (),
        ["push", "int", n] => self.stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => self.stack.push(Expr::Str(String::from(n))),

        ["dup"] => {
          let expr = self.unsafe_pop();
          self.stack.push(expr.clone());
          self.stack.push(expr);
        },

        // convert to string
        ["convert", "int", "str"] => if let Some(&Expr::Int(arg)) = self.stack.last() {
          self.stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        ["convert", from, to] => panic!("VM error: cannot convert from {} to {}", from, to),

        // how = "always" | "carry"
        ["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "primitive", "say"] => if let Some(Expr::Str(arg)) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        ["call", name] => panic!("VM error: unknown function '{}'.", name),

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          self.stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `add`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


<commit_before>use anyhow::{bail, Context};
use serde::Deserialize;
use std::{
    collections::BTreeMap,
    fs::File,
    io::Write,
    process::{Command, Output, Stdio},
    str,
    time::SystemTime,
};
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use vcpkg::{find_vcpkg_root, Config};

// settings for a specific Rust target
#[derive(Debug, Deserialize)]
struct Target {
    triplet: Option<String>,
    // this install key for a specific target overrides the main entry
    // so a the target can opt out of installing packages
    // #[serde(default = "Vec::new")]
    install: Option<Vec<String>>,
}

#[derive(Debug, Deserialize)]
struct Vcpkg {
    vcpkg_root: Option<String>,
    #[serde(default = "BTreeMap::new")]
    target: BTreeMap<String, Target>,
    branch: Option<String>,
    rev: Option<String>,
    git: Option<String>,
    tag: Option<String>,
    #[serde(default = "Vec::new")]
    install: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct Metadata {
    vcpkg: Vcpkg,
}
#[derive(Debug, PartialEq, StructOpt)]
/// Install vcpkg and build packages
///
/// This program clones vcpkg from the specified source and
/// compiles it. It then builds packages required by crates
/// that are depended on by the top level crate being built.
#[structopt(rename_all = "kebab-case")]
struct Opt {
    ///
    #[structopt(short, long)]
    verbose: bool,

    // #[structopt(long)]
    // manifest_path: Option<String>,
    #[structopt(subcommand)]
    sub: Subcommands,
}

#[derive(Debug, PartialEq, StructOpt)]
enum Subcommands {
    /// Build packages
    ///
    /// This command will clone or update a vcpkg tree to the version specified
    /// in Cargo.toml and build the required packages.
    Build {
        #[structopt(long)]
        /// Path to Cargo.toml
        manifest_path: Option<String>,

        #[structopt(long)]
        /// Build for the target triple
        target: Option<String>,
    },
    // `external_subcommand` tells structopt to put
    // all the extra arguments into this Vec
    // #[structopt(external_subcommand)]
    // Cargo(Vec<String>),
}

fn main() {
    // cargo passes us the "vcpkg" arg when it calls us. Drop it before
    // parsing the arg list so t doesn't end up the usage description
    let mut args = std::env::args().collect::<Vec<_>>();
    if args.len() > 2 && args[1] == "vcpkg" {
        args.remove(1);
    }
    let args = Opt::from_iter(args);

    match args.sub {
        Subcommands::Build { .. } => {
            build(args).unwrap_or_else(|e| {
                eprintln!("cargo-vcpkg: {}", e);
                std::process::exit(1);
            });
        }
    }
}
//use std::io::Write;
fn build(opt: Opt) -> Result<(), anyhow::Error> {
    let start_time = SystemTime::now();

    let target_triple = target_triple();

    let verbose = opt.verbose;

    let mut args = std::env::args().skip_while(|val| !val.starts_with("--manifest-path"));
    let mut cmd = cargo_metadata::MetadataCommand::new();
    // opt.manifest_path.map(|p| cmd.manifest_path(p));

    match args.next() {
        Some(p) if p == "--manifest-path" => {
            cmd.manifest_path(args.next().unwrap());
        }
        Some(p) => {
            cmd.manifest_path(p.trim_start_matches("--manifest-path="));
        }
        None => {}
    }
    let metadata = cmd.exec()?;

    let resolve = metadata.resolve.as_ref().unwrap();

    let root_crate = resolve
        .root
        .as_ref()
        .context("cannot run on a virtual manifest, this command requires running against an actual package in this workspace.")?;

    let mut git_url = None;
    let mut vcpkg_ports = Vec::new();
    let mut rev_tag_branch: Option<String> = None;
    let mut vcpkg_triplet = None;
    for p in &metadata.packages {
        if let Ok(v) = serde_json::from_value::<Metadata>(p.metadata.clone()) {
            let v = v.vcpkg;
            let is_root_crate = p.id == *root_crate;

            // only use git url and rev from the root crate
            if v.git.is_some() && is_root_crate {
                git_url = v.git;

                // TODO: check the target and use it's package set if required
                // TODO: get the correct target
                // TODO: make sure to pull if it's a branch
                rev_tag_branch = match (&v.branch, &v.tag, &v.rev) {
                    (Some(b), None, None) => Some(b.into()),
                    (None, Some(t), None) => Some(t.into()),
                    (None, None, Some(r)) => Some(r.into()),
                    _ => {
                        bail!("must specify one of branch,rev,tag for git source");
                    }
                };
            }

            // if there is specific configuration for the target and it has
            // an install key, use that rather than the general install key
            match v.target.get(&target_triple) {
                Some(target) => {
                    if target.install.is_some() {
                        vcpkg_ports.extend_from_slice(&target.install.as_ref().unwrap().as_slice());
                    }
                    if is_root_crate {
                        vcpkg_triplet = target.triplet.clone();
                    }
                }
                _ => {
                    // not found or install is empty
                    vcpkg_ports.extend_from_slice(&v.install.as_slice());
                }
            }
        }
    }

    // should we modify the existing?
    // let mut allow_updates = true;

    // find the vcpkg root
    let vcpkg_root = find_vcpkg_root(&Config::default()).unwrap_or_else(|_| {
        let target_directory = metadata.target_directory.clone();
        let mut vcpkg_root = target_directory.clone();
        vcpkg_root.push("vcpkg");
        vcpkg_root.to_path_buf();
        vcpkg_root
    });
    if verbose {
        println!("vcpkg root is {}", vcpkg_root.display());
    }
    // if it does not exist, clone vcpkg from git
    let mut vcpkg_root_file = vcpkg_root.clone();
    vcpkg_root_file.push(".vcpkg-root");
    if !vcpkg_root_file.exists() {
        let git_url = git_url.context(format!(
            "could not find a vcpkg installation and crate \
        {} does not specify a git repository to clone from.",
            root_crate
        ))?;
        print_tag("Cloning", &git_url);
        let mut cmd = Command::new("git");
        cmd.arg("clone");
        cmd.arg(git_url);
        cmd.arg(&vcpkg_root);
        let _output = run_command(cmd, verbose).context("failed to run git clone")?;

        // create a cargo-vcpkg.toml in the newly created vcpkg tree
        let mut cargo_vcpkg_config_file = vcpkg_root.clone();
        cargo_vcpkg_config_file.push("downloads");
        std::fs::create_dir_all(&cargo_vcpkg_config_file)
            .context("could not create downloads directory in vcpkg tree")?;
        cargo_vcpkg_config_file.push("cargo-vcpkg.toml");
        let mut file =
            File::create(cargo_vcpkg_config_file).context("could not create cargo-vcpkg.toml")?;
        file.write_all(b"# This file was created automatically by cargo-vcpkg\n")?;

    //eprintln!("git clone done = {:?}", output.status);
    } else {
        print_tag("Fetching", "vcpkg");
        let mut cmd = Command::new("git");
        cmd.arg("fetch");
        cmd.arg("--verbose");
        cmd.arg("--all");
        let output = run_command(cmd, verbose).context("failed to run git fatch")?;

        if !output.status.success() {
            bail!("fetch failed");
        }
    }
    // otherwise, check that the rev is where we want it to be
    // there needs to be some serious thought here because if we are on a branch
    // does this mean we should fetch?

    // check out the required rev
    let rev_tag_branch = rev_tag_branch.unwrap();
    print_tag("Checkout", &format!("rev/tag/branch {}", rev_tag_branch));
    let mut cmd = Command::new("git");
    cmd.arg("checkout");
    cmd.arg(rev_tag_branch);
    cmd.current_dir(&vcpkg_root);
    run_command(cmd, verbose).context("failed to execute process")?;

    // try and run 'vcpkg update' and if it fails or gives the version warning, rebuild it
    let require_bootstrap = match vcpkg_command(&vcpkg_root, &vcpkg_triplet)
        .arg("update")
        .output()
    {
        Ok(output) => {
            if verbose {
                println!("-- stdout --\n{}", String::from_utf8_lossy(&output.stdout));
                println!("-- stderr --\n{}", String::from_utf8_lossy(&output.stderr));
                println!("{:?}", output.status);
            }
            if output.status.success()
                && !str::from_utf8(&output.stdout)
                    .unwrap()
                    .contains("Warning: Different source is available for vcpkg")
            {
                false
            } else {
                true
            }
        }
        Err(_) => true,
    };

    if require_bootstrap {
        print_tag("Compiling", "vcpkg");
        let mut cmd = if cfg!(windows) {
            let mut cmd = Command::new("cmd");
            cmd.arg("/C");
            cmd.arg("bootstrap-vcpkg.bat");
            cmd
        } else {
            let mut cmd = Command::new("sh");
            cmd.arg("-c");
            cmd.arg("./bootstrap-vcpkg.sh");
            cmd
        };
        cmd.arg("-disableMetrics");
        cmd.current_dir(&vcpkg_root);
        run_command(cmd, verbose).context("failed to run vcpkg bootstrap")?;
    }

    // TODO: upgrade anything that is installed
    print_tag("Compiling", &vcpkg_ports.join(", "));
    let mut v = vcpkg_command(&vcpkg_root, &vcpkg_triplet);
    v.arg("install");
    v.arg("--recurse");
    v.args(vcpkg_ports.as_slice());
    run_command(v, verbose).context("failed to execute vcpkg install")?;

    let duration = SystemTime::now().duration_since(start_time).unwrap();
    print_tag("Finished", &format!("in {:0.2}s", duration.as_secs_f32()));
    Ok(())
}

fn target_triple() -> String {
    let mut args = std::env::args().skip_while(|val| !val.starts_with("--target"));
    match args.next() {
        Some(p) if p == "--target" => args.next().unwrap(),
        Some(p) => p.trim_start_matches("--target=").into(),
        None => std::env!("TARGET").into(),
    }
}

fn vcpkg_command(vcpkg_root: &std::path::Path, vcpkg_triplet: &Option<String>) -> Command {
    let mut x = vcpkg_root.to_path_buf();
    if cfg!(windows) {
        x.push("vcpkg.exe");
    } else {
        x.push("vcpkg")
    }
    let mut command = Command::new(x);
    command.current_dir(&vcpkg_root);
    if let Some(triplet) = &vcpkg_triplet {
        command.arg("--triplet");
        command.arg(triplet);
    }
    command
}

fn run_command(mut cmd: Command, verbose: bool) -> Result<Output, anyhow::Error> {
    if verbose {
        cmd.stdout(Stdio::inherit());
        cmd.stderr(Stdio::inherit());
    }
    let output = cmd.output()?;

    if !output.status.success() && !verbose {
        println!("-- stdout --\n{}", String::from_utf8_lossy(&output.stdout));
        println!("-- stderr --\n{}", String::from_utf8_lossy(&output.stderr));
        bail!("failed");
    }

    Ok(output)
}

fn print_tag(tag: &str, detail: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Auto);
    stdout
        .set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))
        .unwrap();

    print!("{:>12} ", tag);
    stdout.reset().unwrap();
    println!("{}", detail);
}
<commit_msg>create cargo-vcpkg.toml when updating the tree too<commit_after>use anyhow::{bail, Context};
use serde::Deserialize;
use std::{
    collections::BTreeMap,
    fs::File,
    io::Write,
    process::{Command, Output, Stdio},
    str,
    time::SystemTime,
};
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use vcpkg::{find_vcpkg_root, Config};

// settings for a specific Rust target
#[derive(Debug, Deserialize)]
struct Target {
    triplet: Option<String>,
    // this install key for a specific target overrides the main entry
    // so a the target can opt out of installing packages
    // #[serde(default = "Vec::new")]
    install: Option<Vec<String>>,
}

#[derive(Debug, Deserialize)]
struct Vcpkg {
    vcpkg_root: Option<String>,
    #[serde(default = "BTreeMap::new")]
    target: BTreeMap<String, Target>,
    branch: Option<String>,
    rev: Option<String>,
    git: Option<String>,
    tag: Option<String>,
    #[serde(default = "Vec::new")]
    install: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct Metadata {
    vcpkg: Vcpkg,
}
#[derive(Debug, PartialEq, StructOpt)]
/// Install vcpkg and build packages
///
/// This program clones vcpkg from the specified source and
/// compiles it. It then builds packages required by crates
/// that are depended on by the top level crate being built.
#[structopt(rename_all = "kebab-case")]
struct Opt {
    ///
    #[structopt(short, long)]
    verbose: bool,

    // #[structopt(long)]
    // manifest_path: Option<String>,
    #[structopt(subcommand)]
    sub: Subcommands,
}

#[derive(Debug, PartialEq, StructOpt)]
enum Subcommands {
    /// Build packages
    ///
    /// This command will clone or update a vcpkg tree to the version specified
    /// in Cargo.toml and build the required packages.
    Build {
        #[structopt(long)]
        /// Path to Cargo.toml
        manifest_path: Option<String>,

        #[structopt(long)]
        /// Build for the target triple
        target: Option<String>,
    },
    // `external_subcommand` tells structopt to put
    // all the extra arguments into this Vec
    // #[structopt(external_subcommand)]
    // Cargo(Vec<String>),
}

fn main() {
    // cargo passes us the "vcpkg" arg when it calls us. Drop it before
    // parsing the arg list so t doesn't end up the usage description
    let mut args = std::env::args().collect::<Vec<_>>();
    if args.len() > 2 && args[1] == "vcpkg" {
        args.remove(1);
    }
    let args = Opt::from_iter(args);

    match args.sub {
        Subcommands::Build { .. } => {
            build(args).unwrap_or_else(|e| {
                eprintln!("cargo-vcpkg: {}", e);
                std::process::exit(1);
            });
        }
    }
}
//use std::io::Write;
fn build(opt: Opt) -> Result<(), anyhow::Error> {
    let start_time = SystemTime::now();

    let target_triple = target_triple();

    let verbose = opt.verbose;

    let mut args = std::env::args().skip_while(|val| !val.starts_with("--manifest-path"));
    let mut cmd = cargo_metadata::MetadataCommand::new();
    // opt.manifest_path.map(|p| cmd.manifest_path(p));

    match args.next() {
        Some(p) if p == "--manifest-path" => {
            cmd.manifest_path(args.next().unwrap());
        }
        Some(p) => {
            cmd.manifest_path(p.trim_start_matches("--manifest-path="));
        }
        None => {}
    }
    let metadata = cmd.exec()?;

    let resolve = metadata.resolve.as_ref().unwrap();

    let root_crate = resolve
        .root
        .as_ref()
        .context("cannot run on a virtual manifest, this command requires running against an actual package in this workspace.")?;

    let mut git_url = None;
    let mut vcpkg_ports = Vec::new();
    let mut rev_tag_branch: Option<String> = None;
    let mut vcpkg_triplet = None;
    for p in &metadata.packages {
        if let Ok(v) = serde_json::from_value::<Metadata>(p.metadata.clone()) {
            let v = v.vcpkg;
            let is_root_crate = p.id == *root_crate;

            // only use git url and rev from the root crate
            if v.git.is_some() && is_root_crate {
                git_url = v.git;

                // TODO: check the target and use it's package set if required
                // TODO: get the correct target
                // TODO: make sure to pull if it's a branch
                rev_tag_branch = match (&v.branch, &v.tag, &v.rev) {
                    (Some(b), None, None) => Some(b.into()),
                    (None, Some(t), None) => Some(t.into()),
                    (None, None, Some(r)) => Some(r.into()),
                    _ => {
                        bail!("must specify one of branch,rev,tag for git source");
                    }
                };
            }

            // if there is specific configuration for the target and it has
            // an install key, use that rather than the general install key
            match v.target.get(&target_triple) {
                Some(target) => {
                    if target.install.is_some() {
                        vcpkg_ports.extend_from_slice(&target.install.as_ref().unwrap().as_slice());
                    }
                    if is_root_crate {
                        vcpkg_triplet = target.triplet.clone();
                    }
                }
                _ => {
                    // not found or install is empty
                    vcpkg_ports.extend_from_slice(&v.install.as_slice());
                }
            }
        }
    }

    // should we modify the existing?
    // let mut allow_updates = true;

    // find the vcpkg root
    let vcpkg_root = find_vcpkg_root(&Config::default()).unwrap_or_else(|_| {
        let target_directory = metadata.target_directory.clone();
        let mut vcpkg_root = target_directory.clone();
        vcpkg_root.push("vcpkg");
        vcpkg_root.to_path_buf();
        vcpkg_root
    });
    if verbose {
        println!("vcpkg root is {}", vcpkg_root.display());
    }
    // if it does not exist, clone vcpkg from git
    let mut vcpkg_root_file = vcpkg_root.clone();
    vcpkg_root_file.push(".vcpkg-root");
    if !vcpkg_root_file.exists() {
        let git_url = git_url.context(format!(
            "could not find a vcpkg installation and crate \
        {} does not specify a git repository to clone from.",
            root_crate
        ))?;
        print_tag("Cloning", &git_url);
        let mut cmd = Command::new("git");
        cmd.arg("clone");
        cmd.arg(git_url);
        cmd.arg(&vcpkg_root);
        let _output = run_command(cmd, verbose).context("failed to run git clone")?;

    //eprintln!("git clone done = {:?}", output.status);
    } else {
        print_tag("Fetching", "vcpkg");
        let mut cmd = Command::new("git");
        cmd.arg("fetch");
        cmd.arg("--verbose");
        cmd.arg("--all");
        let output = run_command(cmd, verbose).context("failed to run git fetch")?;

        if !output.status.success() {
            bail!("fetch failed");
        }
    }

    // create a cargo-vcpkg.toml in the vcpkg tree
    let mut cargo_vcpkg_config_file = vcpkg_root.clone();
    cargo_vcpkg_config_file.push("downloads");
    std::fs::create_dir_all(&cargo_vcpkg_config_file)
        .context("could not create downloads directory in vcpkg tree")?;
    cargo_vcpkg_config_file.push("cargo-vcpkg.toml");
    if !cargo_vcpkg_config_file.exists() {
        let mut file =
            File::create(cargo_vcpkg_config_file).context("could not create cargo-vcpkg.toml")?;
        file.write_all(b"# This file was created automatically by cargo-vcpkg\n")?;
    }

    // otherwise, check that the rev is where we want it to be
    // there needs to be some serious thought here because if we are on a branch
    // does this mean we should fetch?

    // check out the required rev
    let rev_tag_branch = rev_tag_branch.unwrap();
    print_tag("Checkout", &format!("rev/tag/branch {}", rev_tag_branch));
    let mut cmd = Command::new("git");
    cmd.arg("checkout");
    cmd.arg(rev_tag_branch);
    cmd.current_dir(&vcpkg_root);
    run_command(cmd, verbose).context("failed to execute process")?;

    // try and run 'vcpkg update' and if it fails or gives the version warning, rebuild it
    let require_bootstrap = match vcpkg_command(&vcpkg_root, &vcpkg_triplet)
        .arg("update")
        .output()
    {
        Ok(output) => {
            if verbose {
                println!("-- stdout --\n{}", String::from_utf8_lossy(&output.stdout));
                println!("-- stderr --\n{}", String::from_utf8_lossy(&output.stderr));
                println!("{:?}", output.status);
            }
            if output.status.success()
                && !str::from_utf8(&output.stdout)
                    .unwrap()
                    .contains("Warning: Different source is available for vcpkg")
            {
                false
            } else {
                true
            }
        }
        Err(_) => true,
    };

    if require_bootstrap {
        print_tag("Compiling", "vcpkg");
        let mut cmd = if cfg!(windows) {
            let mut cmd = Command::new("cmd");
            cmd.arg("/C");
            cmd.arg("bootstrap-vcpkg.bat");
            cmd
        } else {
            let mut cmd = Command::new("sh");
            cmd.arg("-c");
            cmd.arg("./bootstrap-vcpkg.sh");
            cmd
        };
        cmd.arg("-disableMetrics");
        cmd.current_dir(&vcpkg_root);
        run_command(cmd, verbose).context("failed to run vcpkg bootstrap")?;
    }

    // TODO: upgrade anything that is installed
    print_tag("Compiling", &vcpkg_ports.join(", "));
    let mut v = vcpkg_command(&vcpkg_root, &vcpkg_triplet);
    v.arg("install");
    v.arg("--recurse");
    v.args(vcpkg_ports.as_slice());
    run_command(v, verbose).context("failed to execute vcpkg install")?;

    let duration = SystemTime::now().duration_since(start_time).unwrap();
    print_tag("Finished", &format!("in {:0.2}s", duration.as_secs_f32()));
    Ok(())
}

fn target_triple() -> String {
    let mut args = std::env::args().skip_while(|val| !val.starts_with("--target"));
    match args.next() {
        Some(p) if p == "--target" => args.next().unwrap(),
        Some(p) => p.trim_start_matches("--target=").into(),
        None => std::env!("TARGET").into(),
    }
}

fn vcpkg_command(vcpkg_root: &std::path::Path, vcpkg_triplet: &Option<String>) -> Command {
    let mut x = vcpkg_root.to_path_buf();
    if cfg!(windows) {
        x.push("vcpkg.exe");
    } else {
        x.push("vcpkg")
    }
    let mut command = Command::new(x);
    command.current_dir(&vcpkg_root);
    if let Some(triplet) = &vcpkg_triplet {
        command.arg("--triplet");
        command.arg(triplet);
    }
    command
}

fn run_command(mut cmd: Command, verbose: bool) -> Result<Output, anyhow::Error> {
    if verbose {
        cmd.stdout(Stdio::inherit());
        cmd.stderr(Stdio::inherit());
    }
    let output = cmd.output()?;

    if !output.status.success() && !verbose {
        println!("-- stdout --\n{}", String::from_utf8_lossy(&output.stdout));
        println!("-- stderr --\n{}", String::from_utf8_lossy(&output.stderr));
        bail!("failed");
    }

    Ok(output)
}

fn print_tag(tag: &str, detail: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Auto);
    stdout
        .set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))
        .unwrap();

    print!("{:>12} ", tag);
    stdout.reset().unwrap();
    println!("{}", detail);
}
<|endoftext|>