<commit_before>#![cfg(feature = "graphmap")]
extern crate petgraph;

use std::collections::HashSet;
use std::fmt;

use petgraph::prelude::*;
use petgraph::visit::{ Walker, };

use petgraph::algo::{ dijkstra, };

use petgraph::dot::{Dot, Config};

#[test]
fn simple() {
    //let root = TypedArena::<Node<_>>::new();
    let mut gr = UnGraphMap::new();
    //let node = |&: name: &'static str| Ptr(root.alloc(Node(name.to_string())));
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let f = gr.add_node("F");
    gr.add_edge(a, b, 7);
    gr.add_edge(a, c, 9);
    gr.add_edge(a, d, 14);
    gr.add_edge(b, c, 10);
    gr.add_edge(c, d, 2);
    gr.add_edge(d, e, 9);
    gr.add_edge(b, f, 15);
    gr.add_edge(c, f, 11);

    assert!(gr.add_edge(e, f, 5).is_none());

    // duplicate edges
    assert_eq!(gr.add_edge(f, b, 16), Some(15));
    assert_eq!(gr.add_edge(f, e, 6), Some(5));
    println!("{:?}", gr);
    println!("{}", Dot::with_config(&gr, &[]));

    assert_eq!(gr.node_count(), 6);
    assert_eq!(gr.edge_count(), 9);

    // check updated edge weight
    assert_eq!(gr.edge_weight(e, f), Some(&6));
    let scores = dijkstra(&gr, a, None, |e| *e.weight());
    let mut scores: Vec<_> = scores.into_iter().collect();
    scores.sort();
    assert_eq!(scores,
       vec![("A", 0), ("B", 7), ("C", 9), ("D", 11), ("E", 20), ("F", 20)]);
}

#[test]
fn remov()
{
    let mut g = UnGraphMap::new();
    g.add_node(1);
    g.add_node(2);
    g.add_edge(1, 2, -1);

    assert_eq!(g.edge_weight(1, 2), Some(&-1));
    assert_eq!(g.edge_weight(2, 1), Some(&-1));
    assert_eq!(g.neighbors(1).count(), 1);

    let noexist = g.remove_edge(2, 3);
    assert_eq!(noexist, None);

    let exist = g.remove_edge(2, 1);
    assert_eq!(exist, Some(-1));
    assert_eq!(g.edge_count(), 0);
    assert_eq!(g.edge_weight(1, 2), None);
    assert_eq!(g.edge_weight(2, 1), None);
    assert_eq!(g.neighbors(1).count(), 0);
}

#[test]
fn remove_directed()
{
    let mut g = GraphMap::<_, _, Directed>::with_capacity(0, 0);
    g.add_edge(1, 2, -1);
    println!("{:?}", g);

    assert_eq!(g.edge_weight(1, 2), Some(&-1));
    assert_eq!(g.edge_weight(2, 1), None);
    assert_eq!(g.neighbors(1).count(), 1);

    let noexist = g.remove_edge(2, 3);
    assert_eq!(noexist, None);

    let exist = g.remove_edge(2, 1);
    assert_eq!(exist, None);
    let exist = g.remove_edge(1, 2);
    assert_eq!(exist, Some(-1));
    println!("{:?}", g);
    assert_eq!(g.edge_count(), 0);
    assert_eq!(g.edge_weight(1, 2), None);
    assert_eq!(g.edge_weight(2, 1), None);
    assert_eq!(g.neighbors(1).count(), 0);
}

#[test]
fn dfs() {
    let mut gr = UnGraphMap::default();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    // Z is disconnected.
    let z = gr.add_node("Z");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);
    gr.add_edge(i, k, 2.);

    println!("{:?}", gr);

    {
        let mut cnt = 0;
        let mut dfs = Dfs::new(&gr, h);
        while let Some(_) = dfs.next(&gr) { cnt += 1; }
        assert_eq!(cnt, 4);
    }
    {
        let mut cnt = 0;
        let mut dfs = Dfs::new(&gr, z);
        while let Some(_) = dfs.next(&gr) { cnt += 1; }
        assert_eq!(cnt, 1);
    }

    assert_eq!(Dfs::new(&gr, h).iter(&gr).count(), 4);
    assert_eq!(Dfs::new(&gr, i).iter(&gr).count(), 4);
    assert_eq!(Dfs::new(&gr, z).iter(&gr).count(), 1);
}

#[test]
fn edge_iterator() {
    let mut gr = UnGraphMap::new();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    gr.add_edge(h, i, 1);
    gr.add_edge(h, j, 2);
    gr.add_edge(i, j, 3);
    gr.add_edge(i, k, 4);

    let real_edges: HashSet<_> = gr.all_edges().map(|(a, b, &w)| (a, b, w)).collect();
    let expected_edges: HashSet<_> = vec![
        ("H", "I", 1),
        ("H", "J", 2),
        ("I", "J", 3),
        ("I", "K", 4)
    ].into_iter().collect();

    assert_eq!(real_edges, expected_edges);
}

#[test]
fn from_edges() {
    let gr = GraphMap::<_, _, Undirected>::from_edges(&[
        ("a", "b", 1),
        ("a", "c", 2),
        ("c", "d", 3),
    ]);
    assert_eq!(gr.node_count(), 4);
    assert_eq!(gr.edge_count(), 3);
    assert_eq!(gr[("a", "c")], 2);

    let gr = GraphMap::<_, (), Undirected>::from_edges(&[
        (0, 1), (0, 2), (0, 3),
        (1, 2), (1, 3),
        (2, 3),
    ]);
    assert_eq!(gr.node_count(), 4);
    assert_eq!(gr.edge_count(), 6);
    assert_eq!(gr.neighbors(0).count(), 3);
    assert_eq!(gr.neighbors(1).count(), 3);
    assert_eq!(gr.neighbors(2).count(), 3);
    assert_eq!(gr.neighbors(3).count(), 3);

    println!("{:?}", Dot::with_config(&gr, &[Config::EdgeNoLabel]));
}

#[test]
fn graphmap_directed() {
    //let root = TypedArena::<Node<_>>::new();
    let mut gr = DiGraphMap::<_, ()>::with_capacity(0, 0);
    //let node = |&: name: &'static str| Ptr(root.alloc(Node(name.to_string())));
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let edges = [
        (a, b),
        (a, c),
        (a, d),
        (b, c),
        (c, d),
        (d, e),
        (b, b),
    ];
    gr.extend(&edges);

    // Add reverse edges -- ok!
    assert!(gr.add_edge(e, d, ()).is_none());
    // duplicate edge - no
    assert!(!gr.add_edge(a, b, ()).is_none());

    // duplicate self loop - no
    assert!(!gr.add_edge(b, b, ()).is_none());
    println!("{:#?}", gr);
}

fn assert_sccs_eq<N>(mut res: Vec<Vec<N>>, mut answer: Vec<Vec<N>>)
    where N: Ord + fmt::Debug,
{
    // normalize the result and compare with the answer.
    for scc in &mut res {
        scc.sort();
    }
    res.sort();
    for scc in &mut answer {
        scc.sort();
    }
    answer.sort();
    assert_eq!(res, answer);
}

#[test]
fn scc() {
    let gr: GraphMap<_, u32, Directed> = GraphMap::from_edges(&[
        (6, 0, 0),
        (0, 3, 1),
        (3, 6, 2),
        (8, 6, 3),
        (8, 2, 4),
        (2, 5, 5),
        (5, 8, 6),
        (7, 5, 7),
        (1, 7, 8),
        (7, 4, 9),
        (4, 1, 10)]);

    assert_sccs_eq(petgraph::algo::kosaraju_scc(&gr), vec![
        vec![0, 3, 6],
        vec![1, 4, 7],
        vec![2, 5, 8],
    ]);
}

#[test]
fn test_into_graph() {
    let gr: GraphMap<_, u32, Directed> = GraphMap::from_edges(&[
        (6, 0, 0),
        (0, 3, 1),
        (3, 6, 2),
        (8, 6, 3),
        (8, 2, 4),
        (2, 5, 5),
        (5, 8, 6),
        (7, 5, 7),
        (1, 7, 8),
        (7, 4, 9),
        (4, 1, 10)]);

    let graph: Graph<_, _, _> = gr.clone().into_graph();
    println!("{}", Dot::new(&gr));
    println!("{}", Dot::new(&graph));

    // node weigths in `graph` are node identifiers in `gr`.
    for edge in graph.edge_references() {
        let a = edge.source();
        let b = edge.target();
        let aw = graph[a];
        let bw = graph[b];
        assert_eq!(&gr[(aw, bw)], edge.weight());
    }
}

#[test]
fn test_all_edges_mut() {
    // graph with edge weights equal to in+out
    let mut graph: GraphMap<_, u32, Directed> = GraphMap::from_edges(&[
        (0, 1, 1),
        (1, 2, 3),
        (2, 0, 2),
    ]);

    // change it so edge weight is equal to 2 * (in+out)
    for (start, end, weight) in graph.all_edges_mut() {
        *weight = (start + end) * 2;
    }

    // test it
    for (start, end, weight) in graph.all_edges() {
        assert_eq!((start + end) * 2, *weight);
    }
}

#[test]
fn neighbors_incoming_includes_self_loops() {
    // From issue #281
    let mut graph = DiGraphMap::new();

    let node = graph.add_node(());
    graph.add_edge(node, node, ());

    assert_eq!(graph.neighbors_directed(node, Incoming).next(), Some(node));
}
<commit_msg>GraphMap: include self loops in incoming edges (tests)<commit_after>#![cfg(feature = "graphmap")]
extern crate petgraph;

use std::collections::HashSet;
use std::fmt;

use petgraph::prelude::*;
use petgraph::visit::{ Walker, };

use petgraph::algo::{ dijkstra, };

use petgraph::dot::{Dot, Config};

#[test]
fn simple() {
    //let root = TypedArena::<Node<_>>::new();
    let mut gr = UnGraphMap::new();
    //let node = |&: name: &'static str| Ptr(root.alloc(Node(name.to_string())));
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let f = gr.add_node("F");
    gr.add_edge(a, b, 7);
    gr.add_edge(a, c, 9);
    gr.add_edge(a, d, 14);
    gr.add_edge(b, c, 10);
    gr.add_edge(c, d, 2);
    gr.add_edge(d, e, 9);
    gr.add_edge(b, f, 15);
    gr.add_edge(c, f, 11);

    assert!(gr.add_edge(e, f, 5).is_none());

    // duplicate edges
    assert_eq!(gr.add_edge(f, b, 16), Some(15));
    assert_eq!(gr.add_edge(f, e, 6), Some(5));
    println!("{:?}", gr);
    println!("{}", Dot::with_config(&gr, &[]));

    assert_eq!(gr.node_count(), 6);
    assert_eq!(gr.edge_count(), 9);

    // check updated edge weight
    assert_eq!(gr.edge_weight(e, f), Some(&6));
    let scores = dijkstra(&gr, a, None, |e| *e.weight());
    let mut scores: Vec<_> = scores.into_iter().collect();
    scores.sort();
    assert_eq!(scores,
       vec![("A", 0), ("B", 7), ("C", 9), ("D", 11), ("E", 20), ("F", 20)]);
}

#[test]
fn remov()
{
    let mut g = UnGraphMap::new();
    g.add_node(1);
    g.add_node(2);
    g.add_edge(1, 2, -1);

    assert_eq!(g.edge_weight(1, 2), Some(&-1));
    assert_eq!(g.edge_weight(2, 1), Some(&-1));
    assert_eq!(g.neighbors(1).count(), 1);

    let noexist = g.remove_edge(2, 3);
    assert_eq!(noexist, None);

    let exist = g.remove_edge(2, 1);
    assert_eq!(exist, Some(-1));
    assert_eq!(g.edge_count(), 0);
    assert_eq!(g.edge_weight(1, 2), None);
    assert_eq!(g.edge_weight(2, 1), None);
    assert_eq!(g.neighbors(1).count(), 0);
}

#[test]
fn remove_directed()
{
    let mut g = GraphMap::<_, _, Directed>::with_capacity(0, 0);
    g.add_edge(1, 2, -1);
    println!("{:?}", g);

    assert_eq!(g.edge_weight(1, 2), Some(&-1));
    assert_eq!(g.edge_weight(2, 1), None);
    assert_eq!(g.neighbors(1).count(), 1);

    let noexist = g.remove_edge(2, 3);
    assert_eq!(noexist, None);

    let exist = g.remove_edge(2, 1);
    assert_eq!(exist, None);
    let exist = g.remove_edge(1, 2);
    assert_eq!(exist, Some(-1));
    println!("{:?}", g);
    assert_eq!(g.edge_count(), 0);
    assert_eq!(g.edge_weight(1, 2), None);
    assert_eq!(g.edge_weight(2, 1), None);
    assert_eq!(g.neighbors(1).count(), 0);
}

#[test]
fn dfs() {
    let mut gr = UnGraphMap::default();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    // Z is disconnected.
    let z = gr.add_node("Z");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);
    gr.add_edge(i, k, 2.);

    println!("{:?}", gr);

    {
        let mut cnt = 0;
        let mut dfs = Dfs::new(&gr, h);
        while let Some(_) = dfs.next(&gr) { cnt += 1; }
        assert_eq!(cnt, 4);
    }
    {
        let mut cnt = 0;
        let mut dfs = Dfs::new(&gr, z);
        while let Some(_) = dfs.next(&gr) { cnt += 1; }
        assert_eq!(cnt, 1);
    }

    assert_eq!(Dfs::new(&gr, h).iter(&gr).count(), 4);
    assert_eq!(Dfs::new(&gr, i).iter(&gr).count(), 4);
    assert_eq!(Dfs::new(&gr, z).iter(&gr).count(), 1);
}

#[test]
fn edge_iterator() {
    let mut gr = UnGraphMap::new();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    gr.add_edge(h, i, 1);
    gr.add_edge(h, j, 2);
    gr.add_edge(i, j, 3);
    gr.add_edge(i, k, 4);

    let real_edges: HashSet<_> = gr.all_edges().map(|(a, b, &w)| (a, b, w)).collect();
    let expected_edges: HashSet<_> = vec![
        ("H", "I", 1),
        ("H", "J", 2),
        ("I", "J", 3),
        ("I", "K", 4)
    ].into_iter().collect();

    assert_eq!(real_edges, expected_edges);
}

#[test]
fn from_edges() {
    let gr = GraphMap::<_, _, Undirected>::from_edges(&[
        ("a", "b", 1),
        ("a", "c", 2),
        ("c", "d", 3),
    ]);
    assert_eq!(gr.node_count(), 4);
    assert_eq!(gr.edge_count(), 3);
    assert_eq!(gr[("a", "c")], 2);

    let gr = GraphMap::<_, (), Undirected>::from_edges(&[
        (0, 1), (0, 2), (0, 3),
        (1, 2), (1, 3),
        (2, 3),
    ]);
    assert_eq!(gr.node_count(), 4);
    assert_eq!(gr.edge_count(), 6);
    assert_eq!(gr.neighbors(0).count(), 3);
    assert_eq!(gr.neighbors(1).count(), 3);
    assert_eq!(gr.neighbors(2).count(), 3);
    assert_eq!(gr.neighbors(3).count(), 3);

    println!("{:?}", Dot::with_config(&gr, &[Config::EdgeNoLabel]));
}

#[test]
fn graphmap_directed() {
    //let root = TypedArena::<Node<_>>::new();
    let mut gr = DiGraphMap::<_, ()>::with_capacity(0, 0);
    //let node = |&: name: &'static str| Ptr(root.alloc(Node(name.to_string())));
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let edges = [
        (a, b),
        (a, c),
        (a, d),
        (b, c),
        (c, d),
        (d, e),
        (b, b),
    ];
    gr.extend(&edges);

    // Add reverse edges -- ok!
    assert!(gr.add_edge(e, d, ()).is_none());
    // duplicate edge - no
    assert!(!gr.add_edge(a, b, ()).is_none());

    // duplicate self loop - no
    assert!(!gr.add_edge(b, b, ()).is_none());
    println!("{:#?}", gr);
}

fn assert_sccs_eq<N>(mut res: Vec<Vec<N>>, mut answer: Vec<Vec<N>>)
    where N: Ord + fmt::Debug,
{
    // normalize the result and compare with the answer.
    for scc in &mut res {
        scc.sort();
    }
    res.sort();
    for scc in &mut answer {
        scc.sort();
    }
    answer.sort();
    assert_eq!(res, answer);
}

#[test]
fn scc() {
    let gr: GraphMap<_, u32, Directed> = GraphMap::from_edges(&[
        (6, 0, 0),
        (0, 3, 1),
        (3, 6, 2),
        (8, 6, 3),
        (8, 2, 4),
        (2, 5, 5),
        (5, 8, 6),
        (7, 5, 7),
        (1, 7, 8),
        (7, 4, 9),
        (4, 1, 10)]);

    assert_sccs_eq(petgraph::algo::kosaraju_scc(&gr), vec![
        vec![0, 3, 6],
        vec![1, 4, 7],
        vec![2, 5, 8],
    ]);
}

#[test]
fn test_into_graph() {
    let gr: GraphMap<_, u32, Directed> = GraphMap::from_edges(&[
        (6, 0, 0),
        (0, 3, 1),
        (3, 6, 2),
        (8, 6, 3),
        (8, 2, 4),
        (2, 5, 5),
        (5, 8, 6),
        (7, 5, 7),
        (1, 7, 8),
        (7, 4, 9),
        (4, 1, 10)]);

    let graph: Graph<_, _, _> = gr.clone().into_graph();
    println!("{}", Dot::new(&gr));
    println!("{}", Dot::new(&graph));

    // node weigths in `graph` are node identifiers in `gr`.
    for edge in graph.edge_references() {
        let a = edge.source();
        let b = edge.target();
        let aw = graph[a];
        let bw = graph[b];
        assert_eq!(&gr[(aw, bw)], edge.weight());
    }
}

#[test]
fn test_all_edges_mut() {
    // graph with edge weights equal to in+out
    let mut graph: GraphMap<_, u32, Directed> = GraphMap::from_edges(&[
        (0, 1, 1),
        (1, 2, 3),
        (2, 0, 2),
    ]);

    // change it so edge weight is equal to 2 * (in+out)
    for (start, end, weight) in graph.all_edges_mut() {
        *weight = (start + end) * 2;
    }

    // test it
    for (start, end, weight) in graph.all_edges() {
        assert_eq!((start + end) * 2, *weight);
    }
}

#[test]
fn neighbors_incoming_includes_self_loops() {
    let mut graph = DiGraphMap::new();

    let node = graph.add_node(());
    graph.add_edge(node, node, ());

    let mut neighbors = graph.neighbors_directed(node, Incoming);
    assert_eq!(neighbors.next(), Some(node));
    assert_eq!(neighbors.next(), None);
}

#[test]
fn undirected_neighbors_includes_self_loops() {
    let mut graph = UnGraphMap::new();

    let node = graph.add_node(());
    graph.add_edge(node, node, ());

    let mut neighbors = graph.neighbors(node);
    assert_eq!(neighbors.next(), Some(node));
    assert_eq!(neighbors.next(), None);
}

#[test]
fn self_loops_can_be_removed() {
    let mut graph = DiGraphMap::new();

    let node = graph.add_node(());
    graph.add_edge(node, node, ());

    graph.remove_edge(node, node);

    assert_eq!(graph.neighbors_directed(node, Outgoing).next(), None);
    assert_eq!(graph.neighbors_directed(node, Incoming).next(), None);
}
<|endoftext|>


<commit_before>use crate::result::TockResult;
use crate::util;
use core::cell::Cell;
use core::mem;
use libtock_core::{callback, syscalls};

const DRIVER_NUMBER: usize = 0x30003;

mod command_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const EMULATE: usize = 3;
    pub const CONFIGURE: usize = 4;
    pub const FRAMEDELAYMAX: usize = 5;
}

mod subscribe_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const SELECT: usize = 3;
}

mod allow_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
}

#[allow(dead_code)]
pub struct RecvOp {
    pub result_code: usize,
    pub recv_amount: usize,
}

pub struct NfcTag {}

impl NfcTag {
    pub fn enable_emulation() -> bool {
        NfcTag::emulate(true)
    }

    pub fn disable_emulation() -> bool {
        NfcTag::emulate(false)
    }

    fn emulate(enabled: bool) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0).is_ok()
    }

    /// Subscribe to the tag being SELECTED callback.
    pub fn selected() -> bool {
        let is_selected = Cell::new(false);
        let mut is_selected_alarm = || is_selected.set(true);
        let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SELECT,
            &mut is_selected_alarm,
        );
        if subscription.is_err() {
            return false;
        }

        util::yieldk_for(|| is_selected.get());
        true
    }

    /// Configure the tag type command.
    pub fn configure(tag_type: u8) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0).is_ok()
    }

    /// Set the maximum frame delay value to support transmission with the reader.
    pub fn set_framedelaymax(delay: u32) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::FRAMEDELAYMAX, delay as usize, 0).is_ok()
    }

    /// 1. Share with the driver a buffer.
    /// 2. Subscribe to having a successful receive callback.
    /// 3. Issue the request for reception.
    pub fn receive(buf: &mut [u8; 256]) -> TockResult<RecvOp> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf)?;
        // set callback with 2 arguments, to receive ReturnCode and RX Amount
        let result_code = Cell::new(None);
        let recv_amount = Cell::new(None);
        let mut callback = |result, amount| {
            result_code.set(Some(result));
            recv_amount.set(Some(amount))
        };
        let subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::RECEIVE,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0)?;
        util::yieldk_for(|| recv_amount.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(RecvOp {
            result_code: result_code.get().unwrap(),
            recv_amount: recv_amount.get().unwrap(),
        })
    }

    /// 1. Share with the driver a buffer containing the app's reply.
    /// 2. Subscribe to having a successful transmission callback.
    /// 3. Issue the request for transmitting.
    pub fn transmit(buf: &mut [u8], amount: usize) -> TockResult<usize> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT, buf)?;
        // set callback with 1 argument, to receive ReturnCode
        let result_code = Cell::new(None);
        let mut callback = |result| result_code.set(Some(result));
        let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::TRANSMIT,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, amount, 0)?;
        util::yieldk_for(|| result_code.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(result_code.get().unwrap())
    }
}
<commit_msg>Added setup function for driver existence checking<commit_after>use crate::result::TockResult;
use crate::util;
use core::cell::Cell;
use core::mem;
use libtock_core::{callback, syscalls};

const DRIVER_NUMBER: usize = 0x30003;

mod command_nr {
    pub const CHECK: usize = 0;
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const EMULATE: usize = 3;
    pub const CONFIGURE: usize = 4;
    pub const FRAMEDELAYMAX: usize = 5;
}

mod subscribe_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const SELECT: usize = 3;
}

mod allow_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
}

#[allow(dead_code)]
pub struct RecvOp {
    pub result_code: usize,
    pub recv_amount: usize,
}

pub struct NfcTag {}

impl NfcTag {
    /// Check the existence of an NFC driver.
    pub fn setup() -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0).is_ok()
    }

    pub fn enable_emulation() -> bool {
        NfcTag::emulate(true)
    }

    pub fn disable_emulation() -> bool {
        NfcTag::emulate(false)
    }

    fn emulate(enabled: bool) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0).is_ok()
    }

    /// Subscribe to the tag being SELECTED callback.
    pub fn selected() -> bool {
        let is_selected = Cell::new(false);
        let mut is_selected_alarm = || is_selected.set(true);
        let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SELECT,
            &mut is_selected_alarm,
        );
        if subscription.is_err() {
            return false;
        }

        util::yieldk_for(|| is_selected.get());
        true
    }

    /// Configure the tag type command.
    pub fn configure(tag_type: u8) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0).is_ok()
    }

    /// Set the maximum frame delay value to support transmission with the reader.
    pub fn set_framedelaymax(delay: u32) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::FRAMEDELAYMAX, delay as usize, 0).is_ok()
    }

    /// 1. Share with the driver a buffer.
    /// 2. Subscribe to having a successful receive callback.
    /// 3. Issue the request for reception.
    pub fn receive(buf: &mut [u8; 256]) -> TockResult<RecvOp> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf)?;
        // set callback with 2 arguments, to receive ReturnCode and RX Amount
        let result_code = Cell::new(None);
        let recv_amount = Cell::new(None);
        let mut callback = |result, amount| {
            result_code.set(Some(result));
            recv_amount.set(Some(amount))
        };
        let subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::RECEIVE,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0)?;
        util::yieldk_for(|| recv_amount.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(RecvOp {
            result_code: result_code.get().unwrap(),
            recv_amount: recv_amount.get().unwrap(),
        })
    }

    /// 1. Share with the driver a buffer containing the app's reply.
    /// 2. Subscribe to having a successful transmission callback.
    /// 3. Issue the request for transmitting.
    pub fn transmit(buf: &mut [u8], amount: usize) -> TockResult<usize> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT, buf)?;
        // set callback with 1 argument, to receive ReturnCode
        let result_code = Cell::new(None);
        let mut callback = |result| result_code.set(Some(result));
        let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::TRANSMIT,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, amount, 0)?;
        util::yieldk_for(|| result_code.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(result_code.get().unwrap())
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use core::mem;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use super::CVoid;

#[repr(C)]
#[derive(Debug)]
pub struct MailboxRaw {
    msg_buf: *mut u8,
    msg_buf_len: u32,
    msg_size: u32,
    read_pos: u32,
    write_pos: u32,
    data_added: Option<extern "C" fn()>,
}

impl Default for MailboxRaw {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[repr(C)]
#[derive(Debug)]
pub struct Mailbox<'mem, T: 'mem> {
    mb: UnsafeCell<MailboxRaw>,
    _data: PhantomData<&'mem mut [T]>,
}

impl<'mem, T> Default for Mailbox<'mem, T> {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[link(name = "mouros")]
extern "C" {
    fn os_mailbox_init(
        mb: *mut MailboxRaw,
        msg_buf: *mut CVoid,
        msg_buf_len: u32,
        msg_size: u32,
        data_added_callback: Option<extern "C" fn()>,
    );

    fn os_mailbox_write(mb: *mut MailboxRaw, msg: *const CVoid) -> u8;

    fn os_mailbox_write_multiple(mb: *mut MailboxRaw, msgs: *const CVoid, msg_num: u32) -> u32;

    fn os_mailbox_read(mb: *mut MailboxRaw, out: *mut CVoid) -> u8;

    fn os_mailbox_read_multiple(mb: *mut MailboxRaw, out: *mut CVoid, out_msg_num: u32) -> u32;
}

impl<'mem, T> Mailbox<'mem, T> {
    pub fn new(buf: &'mem mut [T]) -> Mailbox<T> {
        let mb = Mailbox::default();

        unsafe {
            os_mailbox_init(
                mb.mb.get(),
                buf.as_mut_ptr() as *mut CVoid,
                buf.len() as u32,
                mem::size_of::<T>() as u32,
                None,
            );
        }

        mb
    }

    pub fn write(&self, msg: T) -> bool {
        unsafe { os_mailbox_write(self.mb.get(), &msg as *const T as *const CVoid) != 0 }
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        unsafe {
            os_mailbox_write_multiple(
                self.mb.get(),
                msgs.as_ptr() as *const CVoid,
                msgs.len() as u32,
            )
        }
    }

    pub fn read(&self) -> Option<T> {
        unsafe {
            let mut tmp = mem::zeroed();

            if os_mailbox_read(self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {
                Some(tmp)
            } else {
                None
            }
        }
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        unsafe {
            os_mailbox_read_multiple(
                self.mb.get(),
                out_buf.as_mut_ptr() as *mut CVoid,
                out_buf.len() as u32,
            )
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get()
    }
}

pub struct RxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> RxChannelSpsc<'mb, 'mem, T> {
    pub fn read(&self) -> Option<T> {
        self.mb.read()
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        self.mb.read_multiple(out_buf)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub struct TxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> TxChannelSpsc<'mb, 'mem, T> {
    pub fn write(&self, msg: T) -> bool {
        self.mb.write(msg)
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        self.mb.write_multiple(msgs)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub fn channel_spsc<'mb, 'mem, T>(
    mailbox: &'mb mut Mailbox<'mem, T>,
) -> (RxChannelSpsc<'mb, 'mem, T>, TxChannelSpsc<'mb, 'mem, T>) {
    (
        RxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
        TxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
    )
}
<commit_msg>Changed the Mailbox channels to resemble Rust channels<commit_after>#![allow(dead_code)]

use core::mem;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use super::CVoid;

#[repr(C)]
#[derive(Debug)]
pub struct MailboxRaw {
    msg_buf: *mut u8,
    msg_buf_len: u32,
    msg_size: u32,
    read_pos: u32,
    write_pos: u32,
    data_added: Option<extern "C" fn()>,
}

impl Default for MailboxRaw {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[repr(C)]
#[derive(Debug)]
pub struct Mailbox<'mem, T: 'mem> {
    mb: UnsafeCell<MailboxRaw>,
    _data: PhantomData<&'mem mut [T]>,
}

impl<'mem, T> Default for Mailbox<'mem, T> {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[link(name = "mouros")]
extern "C" {
    fn os_mailbox_init(
        mb: *mut MailboxRaw,
        msg_buf: *mut CVoid,
        msg_buf_len: u32,
        msg_size: u32,
        data_added_callback: Option<extern "C" fn()>,
    );

    fn os_mailbox_write(mb: *mut MailboxRaw, msg: *const CVoid) -> u8;

    fn os_mailbox_write_multiple(mb: *mut MailboxRaw, msgs: *const CVoid, msg_num: u32) -> u32;

    fn os_mailbox_read(mb: *mut MailboxRaw, out: *mut CVoid) -> u8;

    fn os_mailbox_read_multiple(mb: *mut MailboxRaw, out: *mut CVoid, out_msg_num: u32) -> u32;
}

impl<'mem, T> Mailbox<'mem, T>
{
    pub fn new(buf: &'mem mut [T]) -> Mailbox<T> {
        let mb = Mailbox::default();

        unsafe {
            os_mailbox_init(
                mb.mb.get(),
                buf.as_mut_ptr() as *mut CVoid,
                buf.len() as u32,
                mem::size_of::<T>() as u32,
                None,
            );
        }

        mb
    }

    pub fn write(&self, msg: T) -> bool {
        unsafe { os_mailbox_write(self.mb.get(), &msg as *const T as *const CVoid) != 0 }
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        unsafe {
            os_mailbox_write_multiple(
                self.mb.get(),
                msgs.as_ptr() as *const CVoid,
                msgs.len() as u32,
            )
        }
    }

    pub fn read(&self) -> Option<T> {
        unsafe {
            let mut tmp = mem::zeroed();

            if os_mailbox_read(self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {
                Some(tmp)
            } else {
                None
            }
        }
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        unsafe {
            os_mailbox_read_multiple(
                self.mb.get(),
                out_buf.as_mut_ptr() as *mut CVoid,
                out_buf.len() as u32,
            )
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get()
    }
}

pub struct SendError<T>(pub T);
pub struct RecvError;

pub struct RxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: UnsafeCell<&'mb mut MailboxRaw>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> RxChannelSpsc<'mb, 'mem, T> {
    pub fn recv(&self) -> T {
        unsafe {
            let mut tmp = mem::uninitialized();

            while os_mailbox_read(*self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {}

            tmp
        }
    }

    pub fn try_recv(&self) -> Result<T, RecvError> {
        unsafe {
            let mut tmp = mem::uninitialized();

            if os_mailbox_read(*self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {
                Ok(tmp)
            } else {
                Err(RecvError)
            }
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        *self.mb.get()
    }
}

pub struct TxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: UnsafeCell<&'mb mut MailboxRaw>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> TxChannelSpsc<'mb, 'mem, T> {
    pub fn send(&self, msg: T) {
        unsafe {
           while os_mailbox_write(*self.mb.get(), &msg as *const T as *const CVoid) != 0 {}
        }
     }

    pub fn try_send(&self, msg: T) -> Result<(), SendError<T>> {
        unsafe {
            if os_mailbox_write(*self.mb.get(), &msg as *const T as *const CVoid) != 0 {
                Ok(())
            } else {
                Err(SendError(msg))
            }
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        *self.mb.get()
    }
}

pub fn channel_spsc<'mb, 'mem, T>(
    mailbox: &'mb mut Mailbox<'mem, T>,
) -> (RxChannelSpsc<'mb, 'mem, T>, TxChannelSpsc<'mb, 'mem, T>) {
    unsafe {
        (
            RxChannelSpsc {
                mb: UnsafeCell::new(&mut *mailbox.get_raw_mailbox()),
                _lifetime_marker: PhantomData,
            },
            TxChannelSpsc {
                mb: UnsafeCell::new(&mut *mailbox.get_raw_mailbox()),
                _lifetime_marker: PhantomData,
            },
        )
    }
}
<|endoftext|>


<commit_before>use anyhow::{anyhow, Result};
use std::env;
use std::thread;

/// Upgrade the application
///
/// Checks for a higher version on [GitHub releases](https://github.com/stencila/stencila/releases)
/// and downloads the binary for the current platform if one is found.
///
/// # Arguments
///
/// - `confirm`: Prompt the user to confirm an upgrade
/// - `verbose`: Print information on the upgrade process
/// - `current_version`: The current version (used mainly for testing)
///
/// # Examples
///
/// ```
/// use stencila::upgrade::upgrade;
/// upgrade(true, false, None);
/// ```
pub fn upgrade(confirm: bool, verbose: bool, current_version: Option<String>) -> Result<()> {
    // This is run in a separate thread so that is does not slow down the
    // command currently being run by the user (when doing an auto-update).
    // In any case it needs to be because `self_update` creates a new `tokio`
    // runtime (which can not be nested within our main `tokio` runtime).
    thread::spawn(move || -> Result<()> {
        let result = self_update::backends::github::Update::configure()
            .repo_owner("stencila")
            .repo_name("stencila")
            .bin_name("stencila")
            .current_version(
                current_version
                    .unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string())
                    .as_str(),
            )
            .no_confirm(!confirm)
            .show_output(verbose)
            .show_download_progress(verbose)
            .build()?
            .update();
        match result {
            Ok(_) => Ok(()),
            Err(error) => {
                if format!("{}", error).contains("Update aborted") {
                    // If the user said no to the confirmation, that's `Ok`.
                    Ok(())
                } else {
                    Err(anyhow!(error))
                }
            }
        }
    })
    .join()
    .expect("Something went wrong")?;

    Ok(())
}

/// CLI options for the `upgrade` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;
    #[derive(Debug, StructOpt)]
    #[structopt(about = "Upgrade stencila to the latest version")]
    pub struct Args {
        /// Prompt the user to confirm an upgrade
        #[structopt(short, long)]
        pub confirm: bool,

        /// Print information on the upgrade process
        #[structopt(short, long)]
        pub verbose: bool,
    }

    pub fn upgrade(args: Args) -> Result<()> {
        let Args { confirm, verbose } = args;
        super::upgrade(confirm, verbose, None)
    }
}

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

    // Note that these tests are a little funky in that they make requests to the
    // GitHub API. They use an unrealistically high version to avoid any binaries
    // from being downloaded.

    #[test]
    fn test_upgrade() -> Result<()> {
        upgrade(false, false, Some("100.0.0".to_string()))
    }

    #[ignore]
    #[test]
    fn test_cli() -> Result<()> {
        cli::upgrade(cli::Args {
            confirm: false,
            verbose: false,
        })
    }
}
<commit_msg>test(Upgrade): Don't ignore test<commit_after>use anyhow::{anyhow, Result};
use std::env;
use std::thread;

/// Upgrade the application
///
/// Checks for a higher version on [GitHub releases](https://github.com/stencila/stencila/releases)
/// and downloads the binary for the current platform if one is found.
///
/// # Arguments
///
/// - `confirm`: Prompt the user to confirm an upgrade
/// - `verbose`: Print information on the upgrade process
/// - `current_version`: The current version (used mainly for testing)
///
/// # Examples
///
/// ```
/// use stencila::upgrade::upgrade;
/// upgrade(true, false, None);
/// ```
pub fn upgrade(confirm: bool, verbose: bool, current_version: Option<String>) -> Result<()> {
    // This is run in a separate thread so that is does not slow down the
    // command currently being run by the user (when doing an auto-update).
    // In any case it needs to be because `self_update` creates a new `tokio`
    // runtime (which can not be nested within our main `tokio` runtime).
    thread::spawn(move || -> Result<()> {
        let result = self_update::backends::github::Update::configure()
            .repo_owner("stencila")
            .repo_name("stencila")
            .bin_name("stencila")
            .current_version(
                current_version
                    .unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string())
                    .as_str(),
            )
            .no_confirm(!confirm)
            .show_output(verbose)
            .show_download_progress(verbose)
            .build()?
            .update();
        match result {
            Ok(_) => Ok(()),
            Err(error) => {
                if format!("{}", error).contains("Update aborted") {
                    // If the user said no to the confirmation, that's `Ok`.
                    Ok(())
                } else {
                    Err(anyhow!(error))
                }
            }
        }
    })
    .join()
    .expect("Something went wrong")?;

    Ok(())
}

/// CLI options for the `upgrade` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;
    #[derive(Debug, StructOpt)]
    #[structopt(about = "Upgrade stencila to the latest version")]
    pub struct Args {
        /// Prompt the user to confirm an upgrade
        #[structopt(short, long)]
        pub confirm: bool,

        /// Print information on the upgrade process
        #[structopt(short, long)]
        pub verbose: bool,
    }

    pub fn upgrade(args: Args) -> Result<()> {
        let Args { confirm, verbose } = args;
        super::upgrade(confirm, verbose, None)
    }
}

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

    // Note that these tests are a little funky in that they make requests to the
    // GitHub API. They use an unrealistically high version to avoid any binaries
    // from being downloaded.

    #[test]
    fn test_upgrade() -> Result<()> {
        upgrade(false, false, Some("100.0.0".to_string()))
    }

    #[test]
    fn test_cli() -> Result<()> {
        cli::upgrade(cli::Args {
            confirm: false,
            verbose: false,
        })
    }
}
<|endoftext|>


<commit_before>
use call;
use config;
use error::GGRError;
use error::GGRResult;
use error::GerritError;
use entities;
use gerrit::GerritAccess;
use gerrit::GerritVersion;
use semver;
use serde;
use std;
use url;

/// Interface to retrieve Changes information from gerrit server
pub struct Changes {
    call: call::Call,

    /// Query Information (`q`-parameter) like "owner:self"
    querylist: Vec<String>,

    /// Additional fields, like `DOWNLOAD_COMMANDS` or `CURRENT_ACTIONS`
    labellist: Vec<String>,
}

impl GerritAccess for Changes {
    // creates ("/a/changes", "pp=0&q="querystring"&o=label&o=label")
    fn build_url(&self) -> (String, String) {
        let mut querystring = String::from("pp=0&q=");
        if ! self.querylist.is_empty() {
            let mut fragment = String::new();
            for el in &self.querylist {
                fragment.push_str(el);
                fragment.push_str("+");
            }
            if let Some(x) = fragment.chars().last() {
                if x == '+' {
                    fragment = fragment.trim_right_matches(x).to_string();
                }
            };

            querystring = format!("{}{}", querystring, fragment);
        };

        if ! self.labellist.is_empty() {
            for label in &self.labellist {
                querystring = format!("{}&o={}", querystring, &label);
            }
        }

        querystring = querystring.replace("//", "/");

        (String::from("/a/changes/"), querystring)
    }
}

impl GerritVersion for Changes {
    fn check_version(&self, since: String) -> GGRResult<()> {
        let config = config::Config::new(self.call.get_base());
        if let Ok(version) = config.get_version() {
            if semver::Version::parse(&version) < semver::Version::parse(&since) {
                return Err(GGRError::GerritApiError(GerritError::UnsupportedVersion("POST /changes".into(), version.into(), since.into())));
            }
        } else {
            warn!("server version seems not supported, continuing");
        }

        Ok(())
    }
}

impl Changes {
    pub fn new(url: &url::Url) -> Changes {
        Changes {
            call: call::Call::new(url),
            querylist: Vec::new(),
            labellist: Vec::new(),
        }
    }

    /// generic helper function for calling of call object
    ///
    /// The `desc` parameter is a short description for  error messages, its embedded into 'Problem
    /// '...' with <DESC>'.
    /// The call is executed with the `path` parameter and the `httpmethod` with `uploaddata` for
    /// `Put` and `Post` http methods.
    fn execute<INPUT,OUTPUT>(c: &Changes, desc: &str, path: &str, httpmethod: call::CallMethod, uploaddata: Option<&INPUT>) -> GGRResult<OUTPUT>
    where INPUT: serde::Serialize + std::fmt::Debug,
          OUTPUT: serde::Deserialize
    {
        match c.call.request(httpmethod, path, uploaddata) {
            Ok(cr) => {
                match cr.status() {
                    200 => cr.convert::<OUTPUT>(),
                    status => { Err(GGRError::GerritApiError(GerritError::GerritApi(status, String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                }
            },
            Err(x) => {
                Err(GGRError::General(format!("Problem '{}' with {}", x, desc)))
            }
        }
    }

    /// This function is subject of future changes
    pub fn add_query_part<S>(&mut self, q: S) -> &mut Changes
    where S: Into<String> {
        self.querylist.push(q.into());
        self
    }

    /// This function is subject of future changes
    pub fn add_label<S>(&mut self, l: S) -> &mut Changes
    where S: Into<String> {
        self.labellist.push(l.into());
        self
    }

    /// api function 'GET /changes/'
    ///
    /// This function is subject of future changes
    pub fn query_changes(&mut self) -> GGRResult<Vec<entities::ChangeInfo>> {
        let (path, query) = self.build_url();

        self.call.set_url_query(Some(&query));

        match self.call.get(&path) {
            Ok(cr) => {
                if cr.ok() {
                    cr.convert::<Vec<entities::ChangeInfo>>()
                } else {
                    Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap()).unwrap())))
                }
            },
            Err(x) => {
                Err(GGRError::General(format!("call problem with: {} and {} ({})", path, query, x)))
            }
        }
    }

    /// api function 'POST /changes'
    ///
    /// V02.10
    pub fn create_change(&self, ci: &entities::ChangeInput) -> GGRResult<entities::ChangeInfo> {
        if ci.project.is_empty() || ci.branch.is_empty() || ci.subject.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeInputProblem));
        }

        if let Err(x) = self.check_version("2.10.0".into()) {
            return Err(x);
        }

        let (path, _) = self.build_url();

        match self.call.post(&path, &ci) {
            Ok(cr) => {
                if cr.ok() {
                    cr.convert::<entities::ChangeInfo>()
                } else {
                    Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap()).unwrap())))
                }
            },
            Err(x) => {
                Err(GGRError::General(format!("Problem '{}' with change create: {:?}", x, ci)))
            }
        }
    }

    /// api function 'GET /changes/{change-id}'
    pub fn get_change(&mut self, changeid: &str, features: Option<Vec<&str>>) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        if let Some(features) = features {
            for feature in features {
                self.add_label(feature);
            }
        };

        let (path, query) = self.build_url();
        let path = format!("{}/{}", path, changeid);

        self.call.set_url_query(Some(&query));

        Changes::execute::<(),entities::ChangeInfo>(self, "get change", &path, call::CallMethod::Get, None)
    }

    /// api function 'GET /changes/{change-id}/detail'
    pub fn get_change_detail(&self, changeid: &str) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/detail", path, changeid);

        Changes::execute::<(),entities::ChangeInfo>(self, "get change detail", &path, call::CallMethod::Get, None)
    }

    /// api function `GET /changes/{change-id}/reviewers/'
    pub fn get_reviewers(&self, changeid: &str) -> GGRResult<Vec<entities::ReviewerInfo>> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();

        let path = format!("{}/{}/reviewers/", path, changeid);

        match self.call.get(&path) {
            Ok(cr) => {
                if cr.ok() {
                    cr.convert::<Vec<entities::ReviewerInfo>>()
                } else {
                    Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap()).unwrap())))
                }
            },
            Err(x) => {
                Err(GGRError::General(format!("Problem '{}' with receiving reviewer list for {}", x, changeid)))
            }
        }
    }

    /// api function 'POST /changes/{change-id}/reviewers'
    pub fn add_reviewer(&self, changeid: &str, reviewer: &str) -> GGRResult<entities::AddReviewerResult> {
        if changeid.is_empty() || reviewer.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::GetReviewerListProblem("changeid or reviewer is empty".into())));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/reviewers", path, changeid);

        let reviewerinput = entities::ReviewerInput {
                reviewer: reviewer.into(),
                confirmed: None,
                state: None,
        };

        match self.call.post(&path, &reviewerinput) {
            Ok(cr) => {
                if cr.ok() {
                    cr.convert::<entities::AddReviewerResult>()
                } else {
                    Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap()).unwrap())))
                }
            },
            Err(x) => {
                Err(GGRError::General(format!("Problem '{}' with add reviewer for {}", x, changeid)))
            }
        }
    }

    /// api function 'DELETE /changes/{change-id}/reviewers/{account-id}'
    pub fn delete_reviewer(&self, changeid: &str, reviewer: &str) -> GGRResult<()> {
        if changeid.is_empty() || reviewer.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::GetReviewerListProblem("changeid or reviewer is empty".into())));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/reviewers/{}", path, changeid, reviewer);

        match self.call.delete(&path) {
            Ok(cr) => {
                match cr.status() {
                    200 ... 204 => { Ok(()) },
                    404 => { Err(GGRError::GerritApiError(GerritError::ReviewerNotFound)) },
                    _ => { Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap()).unwrap()))) },
                }
            },
            Err(x) => { Err(GGRError::General(format!("Problem '{}' with deleting reviewer for {}", x, changeid))) },
        }
    }

    /// api function 'POST /changes/{change-id}/abandon'
    ///
    /// notify is one of `none`, `owner`, `owner_reviewers` or `all`.
    pub fn abandon_change(&self, changeid: &str, message: Option<&str>, notify: Option<&str>) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/abandon", path, changeid);

        let notify = match notify {
            Some(notify) => {
                match notify {
                    "all" => Some(entities::AbandonInputNotify::ALL),
                    "owner" => Some(entities::AbandonInputNotify::OWNER),
                    "owner_reviewer" => Some(entities::AbandonInputNotify::OWNER_REVIEWERS),
                    _ => Some(entities::AbandonInputNotify::NONE),
                }
            },
            None => None
        };

        let abandoninput = entities::AbandonInput {
                message: message.map(|s| s.to_string()),
                notify: notify,
        };

        let out = self.call.post(&path, &abandoninput);
        match out {
            Ok(cr) => {
                match cr.status() {
                    200 => {
                        cr.convert::<entities::ChangeInfo>()
                    },
                    409 => { Err(GGRError::GerritApiError(GerritError::GerritApi(409, String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                    _ => { Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                }
            },
            Err(x) => { Err(GGRError::General(format!("Problem '{}' with abandon change for {}", x, changeid))) },
        }
    }

    /// api function 'POST /changes/{change-id}/restore'
    pub fn restore_change(&self, changeid: &str, message: Option<&str>) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/restore", path, changeid);

        let restoreinput = entities::RestoreInput {
            message: message.map(|s| s.to_string()),
        };

        match self.call.post(&path, &restoreinput) {
            Ok(cr) => {
                match cr.status() {
                    200 => {
                        cr.convert::<entities::ChangeInfo>()
                    },
                    409 => { Err(GGRError::GerritApiError(GerritError::GerritApi(409, String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                    _ => { Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                }
            },
            Err(x) => { Err(GGRError::General(format!("Problem '{}' with restore change for {}", x, changeid))) },
        }
    }

    /// api function 'POST /changes/{change-id}/revisions/{revision-id}/review'
    pub fn set_review(&self, changeid: &str, revisionid: &str, message: Option<&str>, labels: Option<entities::ReviewInfo>) -> GGRResult<entities::ReviewInfo> {
        if changeid.is_empty() || revisionid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/revisions/{}/review", path, changeid, revisionid);

        use std::collections::HashMap;

        #[derive(Serialize, Debug)]
        struct Review {
            message: Option<String>,
            labels: HashMap<String, i8>,
        };

        let review = Review {
            message: message.map(|s| s.to_string()),
            labels: labels.unwrap_or(entities::ReviewInfo{ labels: HashMap::new() }).labels,
        };

        match self.call.post(&path, &review) {
            Ok(cr) => {
                match cr.status() {
                    200 => {
                        cr.convert::<entities::ReviewInfo>()
                    },
                    _ => { Err(GGRError::GerritApiError(GerritError::GerritApi(cr.status(), String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                }
            },
            Err(x) => { Err(GGRError::General(format!("Problem '{}' with set review for {}", x, changeid))) },
        }

    }
}
<commit_msg>use execute function on all changes functions<commit_after>
use call;
use config;
use error::GGRError;
use error::GGRResult;
use error::GerritError;
use entities;
use gerrit::GerritAccess;
use gerrit::GerritVersion;
use semver;
use serde;
use std;
use url;

/// Interface to retrieve Changes information from gerrit server
pub struct Changes {
    call: call::Call,

    /// Query Information (`q`-parameter) like "owner:self"
    querylist: Vec<String>,

    /// Additional fields, like `DOWNLOAD_COMMANDS` or `CURRENT_ACTIONS`
    labellist: Vec<String>,
}

impl GerritAccess for Changes {
    // creates ("/a/changes", "pp=0&q="querystring"&o=label&o=label")
    fn build_url(&self) -> (String, String) {
        let mut querystring = String::from("pp=0&q=");
        if ! self.querylist.is_empty() {
            let mut fragment = String::new();
            for el in &self.querylist {
                fragment.push_str(el);
                fragment.push_str("+");
            }
            if let Some(x) = fragment.chars().last() {
                if x == '+' {
                    fragment = fragment.trim_right_matches(x).to_string();
                }
            };

            querystring = format!("{}{}", querystring, fragment);
        };

        if ! self.labellist.is_empty() {
            for label in &self.labellist {
                querystring = format!("{}&o={}", querystring, &label);
            }
        }

        querystring = querystring.replace("//", "/");

        (String::from("/a/changes/"), querystring)
    }
}

impl GerritVersion for Changes {
    fn check_version(&self, since: String) -> GGRResult<()> {
        let config = config::Config::new(self.call.get_base());
        if let Ok(version) = config.get_version() {
            if semver::Version::parse(&version) < semver::Version::parse(&since) {
                return Err(GGRError::GerritApiError(GerritError::UnsupportedVersion("POST /changes".into(), version.into(), since.into())));
            }
        } else {
            warn!("server version seems not supported, continuing");
        }

        Ok(())
    }
}

impl Changes {
    pub fn new(url: &url::Url) -> Changes {
        Changes {
            call: call::Call::new(url),
            querylist: Vec::new(),
            labellist: Vec::new(),
        }
    }

    /// generic helper function for calling of call object
    ///
    /// The `desc` parameter is a short description for  error messages, its embedded into 'Problem
    /// '...' with <DESC>'.
    /// The call is executed with the `path` parameter and the `httpmethod` with `uploaddata` for
    /// `Put` and `Post` http methods.
    fn execute<INPUT,OUTPUT>(c: &Changes, desc: &str, path: &str, httpmethod: call::CallMethod, uploaddata: Option<&INPUT>) -> GGRResult<OUTPUT>
    where INPUT: serde::Serialize + std::fmt::Debug,
          OUTPUT: serde::Deserialize
    {
        match c.call.request(httpmethod, path, uploaddata) {
            Ok(cr) => {
                match cr.status() {
                    200 => cr.convert::<OUTPUT>(),
                    status => { Err(GGRError::GerritApiError(GerritError::GerritApi(status, String::from_utf8(cr.get_body().unwrap_or_else(|| "no cause from server".into()))?))) },
                }
            },
            Err(x) => {
                Err(GGRError::General(format!("Problem '{}' with {}", x, desc)))
            }
        }
    }

    /// This function is subject of future changes
    pub fn add_query_part<S>(&mut self, q: S) -> &mut Changes
    where S: Into<String> {
        self.querylist.push(q.into());
        self
    }

    /// This function is subject of future changes
    pub fn add_label<S>(&mut self, l: S) -> &mut Changes
    where S: Into<String> {
        self.labellist.push(l.into());
        self
    }

    /// api function 'GET /changes/'
    ///
    /// This function is subject of future changes
    pub fn query_changes(&mut self) -> GGRResult<Vec<entities::ChangeInfo>> {
        let (path, query) = self.build_url();

        self.call.set_url_query(Some(&query));

        Changes::execute::<(),Vec<entities::ChangeInfo>>(self, "query change", &path, call::CallMethod::Get, None)
    }

    /// api function 'POST /changes'
    ///
    /// V02.10
    pub fn create_change(&self, ci: &entities::ChangeInput) -> GGRResult<entities::ChangeInfo> {
        if ci.project.is_empty() || ci.branch.is_empty() || ci.subject.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeInputProblem));
        }

        if let Err(x) = self.check_version("2.10.0".into()) {
            return Err(x);
        }

        let (path, _) = self.build_url();

        Changes::execute(self, "change create", &path, call::CallMethod::Post, Some(&ci))
    }

    /// api function 'GET /changes/{change-id}'
    pub fn get_change(&mut self, changeid: &str, features: Option<Vec<&str>>) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        if let Some(features) = features {
            for feature in features {
                self.add_label(feature);
            }
        };

        let (path, query) = self.build_url();
        let path = format!("{}/{}", path, changeid);

        self.call.set_url_query(Some(&query));

        Changes::execute::<(),entities::ChangeInfo>(self, "get change", &path, call::CallMethod::Get, None)
    }

    /// api function 'GET /changes/{change-id}/detail'
    pub fn get_change_detail(&self, changeid: &str) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/detail", path, changeid);

        Changes::execute::<(),entities::ChangeInfo>(self, "get change detail", &path, call::CallMethod::Get, None)
    }

    /// api function `GET /changes/{change-id}/reviewers/'
    pub fn get_reviewers(&self, changeid: &str) -> GGRResult<Vec<entities::ReviewerInfo>> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();

        let path = format!("{}/{}/reviewers/", path, changeid);

        Changes::execute::<(),Vec<entities::ReviewerInfo>>(self, "receiving reviewer list", &path, call::CallMethod::Get, None)
    }

    /// api function 'POST /changes/{change-id}/reviewers'
    pub fn add_reviewer(&self, changeid: &str, reviewer: &str) -> GGRResult<entities::AddReviewerResult> {
        if changeid.is_empty() || reviewer.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::GetReviewerListProblem("changeid or reviewer is empty".into())));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/reviewers", path, changeid);

        let reviewerinput = entities::ReviewerInput {
                reviewer: reviewer.into(),
                confirmed: None,
                state: None,
        };

        Changes::execute::<&entities::ReviewerInput,entities::AddReviewerResult>(self, "add reviewer", &path, call::CallMethod::Get, Some(&&reviewerinput))
    }

    /// api function 'DELETE /changes/{change-id}/reviewers/{account-id}'
    pub fn delete_reviewer(&self, changeid: &str, reviewer: &str) -> GGRResult<()> {
        if changeid.is_empty() || reviewer.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::GetReviewerListProblem("changeid or reviewer is empty".into())));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/reviewers/{}", path, changeid, reviewer);

        Changes::execute::<(),()>(self, "deleting reviewer", &path, call::CallMethod::Delete, None)
    }

    /// api function 'POST /changes/{change-id}/abandon'
    ///
    /// notify is one of `none`, `owner`, `owner_reviewers` or `all`.
    pub fn abandon_change(&self, changeid: &str, message: Option<&str>, notify: Option<&str>) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/abandon", path, changeid);

        let notify = match notify {
            Some(notify) => {
                match notify {
                    "all" => Some(entities::AbandonInputNotify::ALL),
                    "owner" => Some(entities::AbandonInputNotify::OWNER),
                    "owner_reviewer" => Some(entities::AbandonInputNotify::OWNER_REVIEWERS),
                    _ => Some(entities::AbandonInputNotify::NONE),
                }
            },
            None => None
        };

        let abandoninput = entities::AbandonInput {
                message: message.map(|s| s.to_string()),
                notify: notify,
        };

        Changes::execute::<&entities::AbandonInput,entities::ChangeInfo>(self, "abandon change", &path, call::CallMethod::Post, Some(&&abandoninput))
    }

    /// api function 'POST /changes/{change-id}/restore'
    pub fn restore_change(&self, changeid: &str, message: Option<&str>) -> GGRResult<entities::ChangeInfo> {
        if changeid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/restore", path, changeid);

        let restoreinput = entities::RestoreInput {
            message: message.map(|s| s.to_string()),
        };

        Changes::execute::<&entities::RestoreInput,entities::ChangeInfo>(self, "restore change", &path, call::CallMethod::Post, Some(&&restoreinput))
    }

    /// api function 'POST /changes/{change-id}/revisions/{revision-id}/review'
    pub fn set_review(&self, changeid: &str, revisionid: &str, message: Option<&str>, labels: Option<entities::ReviewInfo>) -> GGRResult<entities::ReviewInfo> {
        if changeid.is_empty() || revisionid.is_empty() {
            return Err(GGRError::GerritApiError(GerritError::ChangeIDEmpty));
        }

        let (path, _) = self.build_url();
        let path = format!("{}/{}/revisions/{}/review", path, changeid, revisionid);

        use std::collections::HashMap;

        #[derive(Serialize, Debug)]
        struct Review {
            message: Option<String>,
            labels: HashMap<String, i8>,
        };

        let review = Review {
            message: message.map(|s| s.to_string()),
            labels: labels.unwrap_or(entities::ReviewInfo{ labels: HashMap::new() }).labels,
        };

        Changes::execute::<&Review,entities::ReviewInfo>(self, "set review", &path, call::CallMethod::Post, Some(&&review))
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate gcc;

fn main() {
    if !pkg_config::find_library("liblmdb").is_ok() {
        gcc::compile_library("liblmdb.a",
                             &["mdb/libraries/liblmdb/mdb.c",
                               "mdb/libraries/liblmdb/midl.c"]);
    }
}
<commit_msg>Set MDB_DSYNC and MDB_FDATASYNC on dragonflybsd.<commit_after>extern crate pkg_config;
extern crate gcc;

fn main() {
    let target = std::env::var("TARGET").unwrap();

    if !pkg_config::find_library("liblmdb").is_ok() {
        let mut config = gcc::Config::new();
        config.file("mdb/libraries/liblmdb/mdb.c")
              .file("mdb/libraries/liblmdb/midl.c");

        if target.contains("dragonfly") {
            config.flag("-DMDB_DSYNC=O_SYNC");
            config.flag("-DMDB_FDATASYNC=fsync");
        }

        config.compile("liblmdb.a");
    }
}
<|endoftext|>


<commit_before>#[test]
fn it_works() {
}

mod SVM {
    /// Singly-linked cons list.
    ///
    /// This is used internally to represent list primitives in the machine.
    pub enum List<T> {
        Nil,
        Cons(T, List<T>)
    }

    /// Public implementation for List.
    impl<T> List<T> {

        fn new() -> List<T> {
            Nil
        }

    }

    enum Exp {
        Number(i32)
    }

    struct Engine {
        stack: Vec<Exp>
    }
}
<commit_msg>Fix issue in list<commit_after>#[test]
fn it_works() {
}

mod SVM {

    /// Singly-linked cons list.
    ///
    /// This is used internally to represent list primitives in the machine.
    pub enum List<T> {
        Nil,
        Cons(T, Box<List<T>>)
    }

    /// Public implementation for List.
    impl<T> List<T> {

        fn new() -> List<T> {
            List::Nil
        }

    }

    enum Exp {
        Number(i32)
    }

    struct Engine {
        stack: Vec<Exp>
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Example of method with explicit lifetimes<commit_after>fn main() {
    let s1 = String::from("abc");
    let s2 = "defg";

    let result = longest(s1.as_str(), s2);
    println!("Longest result is: {}", result);
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-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.

#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private))]

#[cfg(feature = "with-syntex")]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate syntax;

use std::rc::Rc;

use syntax::ast::{self, TokenTree, Generics, Expr};
use syntax::codemap::{DUMMY_SP, Spanned, dummy_spanned};
use syntax::ext::base::ExtCtxt;
use syntax::parse::{self, classify, parse_tts_from_source_str, token};
use syntax::print::pprust;
use syntax::ptr::P;

pub trait ToTokens {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for TokenTree {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec!(self.clone())
    }
}

impl<'a, T: ToTokens> ToTokens for &'a T {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        (**self).to_tokens(cx)
    }
}

impl<'a, T: ToTokens> ToTokens for &'a [T] {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter()
            .flat_map(|t| t.to_tokens(cx).into_iter())
            .collect()
    }
}

impl<T: ToTokens> ToTokens for Vec<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter().flat_map(|t| t.to_tokens(cx).into_iter()).collect()
    }
}

impl<T: ToTokens> ToTokens for Spanned<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: use the span?
        self.node.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Option<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        match self {
            &Some(ref t) => t.to_tokens(cx),
            &None => Vec::new(),
        }
    }
}

impl ToTokens for ast::Ident {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Ident(*self, token::Plain))]
    }
}

impl ToTokens for ast::Path {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtPath(Box::new(self.clone()))))]
    }
}

impl ToTokens for ast::Ty {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
    }
}

impl ToTokens for P<ast::Ty> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(self.clone())))]
    }
}

impl ToTokens for P<ast::Block> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtBlock(self.clone())))]
    }
}

impl ToTokens for P<ast::Item> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtItem(self.clone())))]
    }
}

impl ToTokens for P<ast::ImplItem> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
    }
}

impl ToTokens for P<ast::TraitItem> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
    }
}

impl ToTokens for ast::Generics {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let s = pprust::generics_to_string(self);

        parse_tts_from_source_str("<quote expansion".to_string(), s, cx.cfg(), cx.parse_sess())
    }
}

impl ToTokens for ast::WhereClause {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let s = pprust::to_string(|s| {
            s.print_where_clause(&self)
        });

        parse_tts_from_source_str("<quote expansion".to_string(), s, cx.cfg(), cx.parse_sess())
    }
}

impl ToTokens for P<ast::Stmt> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut tts = vec![
            ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone())))
        ];

        // Some statements require a trailing semicolon.
        if classify::stmt_ends_with_semi(&self.node) {
            tts.push(ast::TtToken(self.span, token::Semi));
        }

        tts
    }
}

impl ToTokens for P<ast::Expr> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtExpr(self.clone())))]
    }
}

impl ToTokens for P<ast::Pat> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtPat(self.clone())))]
    }
}

impl ToTokens for ast::Arm {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
    }
}

macro_rules! impl_to_tokens_slice {
    ($t: ty, $sep: expr) => {
        impl ToTokens for [$t] {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                let mut v = vec![];
                for (i, x) in self.iter().enumerate() {
                    if i > 0 {
                        v.extend($sep.iter().cloned());
                    }
                    v.extend(x.to_tokens(cx));
                }
                v
            }
        }
    };
}

impl_to_tokens_slice! { ast::Ty, [ast::TtToken(DUMMY_SP, token::Comma)] }
impl_to_tokens_slice! { P<ast::Item>, [] }

impl ToTokens for P<ast::MetaItem> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
    }
}

impl ToTokens for ast::Attribute {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut r = vec![];
        // FIXME: The spans could be better
        r.push(ast::TtToken(self.span, token::Pound));
        if self.node.style == ast::AttrInner {
            r.push(ast::TtToken(self.span, token::Not));
        }
        r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited {
            delim: token::Bracket,
            open_span: self.span,
            tts: self.node.value.to_tokens(cx),
            close_span: self.span,
        })));
        r
    }
}

impl ToTokens for str {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let lit = ast::LitStr(
            token::intern_and_get_ident(self), ast::CookedStr);
        dummy_spanned(lit).to_tokens(cx)
    }
}

impl ToTokens for () {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtDelimited(DUMMY_SP, Rc::new(ast::Delimited {
            delim: token::Paren,
            open_span: DUMMY_SP,
            tts: vec![],
            close_span: DUMMY_SP,
        }))]
    }
}

impl ToTokens for ast::Lit {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: This is wrong
        P(ast::Expr {
            id: ast::DUMMY_NODE_ID,
            node: ast::ExprLit(P(self.clone())),
            span: DUMMY_SP,
        }).to_tokens(cx)
    }
}

impl ToTokens for bool {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
    }
}

impl ToTokens for char {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
    }
}

macro_rules! impl_to_tokens_int {
    (signed, $t:ty, $tag:expr) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                      ast::Sign::new(*self)));
                dummy_spanned(lit).to_tokens(cx)
            }
        }
    );
    (unsigned, $t:ty, $tag:expr) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
                dummy_spanned(lit).to_tokens(cx)
            }
        }
    );
}

impl_to_tokens_int! { signed, isize, ast::TyIs }
impl_to_tokens_int! { signed, i8,  ast::TyI8 }
impl_to_tokens_int! { signed, i16, ast::TyI16 }
impl_to_tokens_int! { signed, i32, ast::TyI32 }
impl_to_tokens_int! { signed, i64, ast::TyI64 }

impl_to_tokens_int! { unsigned, usize, ast::TyUs }
impl_to_tokens_int! { unsigned, u8,   ast::TyU8 }
impl_to_tokens_int! { unsigned, u16,  ast::TyU16 }
impl_to_tokens_int! { unsigned, u32,  ast::TyU32 }
impl_to_tokens_int! { unsigned, u64,  ast::TyU64 }

pub trait ExtParseUtils {
    fn parse_item(&self, s: String) -> P<ast::Item>;
    fn parse_expr(&self, s: String) -> P<ast::Expr>;
    fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}

impl<'a> ExtParseUtils for ExtCtxt<'a> {

    fn parse_item(&self, s: String) -> P<ast::Item> {
        parse::parse_item_from_source_str(
            "<quote expansion>".to_string(),
            s,
            self.cfg(),
            self.parse_sess()).expect("parse error")
    }

    fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
        parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess()).expect("parse error")
    }

    fn parse_expr(&self, s: String) -> P<ast::Expr> {
        parse::parse_expr_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess())
    }

    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
        parse::parse_tts_from_source_str("<quote expansion>".to_string(),
                                         s,
                                         self.cfg(),
                                         self.parse_sess())
    }
}
<commit_msg>Might as well close these tags like libsyntax does.<commit_after>// Copyright 2012-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.

#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private))]

#[cfg(feature = "with-syntex")]
extern crate syntex_syntax as syntax;

#[cfg(not(feature = "with-syntex"))]
extern crate syntax;

use std::rc::Rc;

use syntax::ast::{self, TokenTree, Generics, Expr};
use syntax::codemap::{DUMMY_SP, Spanned, dummy_spanned};
use syntax::ext::base::ExtCtxt;
use syntax::parse::{self, classify, parse_tts_from_source_str, token};
use syntax::print::pprust;
use syntax::ptr::P;

pub trait ToTokens {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for TokenTree {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec!(self.clone())
    }
}

impl<'a, T: ToTokens> ToTokens for &'a T {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        (**self).to_tokens(cx)
    }
}

impl<'a, T: ToTokens> ToTokens for &'a [T] {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter()
            .flat_map(|t| t.to_tokens(cx).into_iter())
            .collect()
    }
}

impl<T: ToTokens> ToTokens for Vec<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter().flat_map(|t| t.to_tokens(cx).into_iter()).collect()
    }
}

impl<T: ToTokens> ToTokens for Spanned<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: use the span?
        self.node.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Option<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        match self {
            &Some(ref t) => t.to_tokens(cx),
            &None => Vec::new(),
        }
    }
}

impl ToTokens for ast::Ident {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Ident(*self, token::Plain))]
    }
}

impl ToTokens for ast::Path {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtPath(Box::new(self.clone()))))]
    }
}

impl ToTokens for ast::Ty {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
    }
}

impl ToTokens for P<ast::Ty> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(self.clone())))]
    }
}

impl ToTokens for P<ast::Block> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtBlock(self.clone())))]
    }
}

impl ToTokens for P<ast::Item> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtItem(self.clone())))]
    }
}

impl ToTokens for P<ast::ImplItem> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
    }
}

impl ToTokens for P<ast::TraitItem> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
    }
}

impl ToTokens for ast::Generics {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let s = pprust::generics_to_string(self);

        parse_tts_from_source_str("<quote expansion>".to_string(), s, cx.cfg(), cx.parse_sess())
    }
}

impl ToTokens for ast::WhereClause {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let s = pprust::to_string(|s| {
            s.print_where_clause(&self)
        });

        parse_tts_from_source_str("<quote expansion>".to_string(), s, cx.cfg(), cx.parse_sess())
    }
}

impl ToTokens for P<ast::Stmt> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut tts = vec![
            ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone())))
        ];

        // Some statements require a trailing semicolon.
        if classify::stmt_ends_with_semi(&self.node) {
            tts.push(ast::TtToken(self.span, token::Semi));
        }

        tts
    }
}

impl ToTokens for P<ast::Expr> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtExpr(self.clone())))]
    }
}

impl ToTokens for P<ast::Pat> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(self.span, token::Interpolated(token::NtPat(self.clone())))]
    }
}

impl ToTokens for ast::Arm {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
    }
}

macro_rules! impl_to_tokens_slice {
    ($t: ty, $sep: expr) => {
        impl ToTokens for [$t] {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                let mut v = vec![];
                for (i, x) in self.iter().enumerate() {
                    if i > 0 {
                        v.extend($sep.iter().cloned());
                    }
                    v.extend(x.to_tokens(cx));
                }
                v
            }
        }
    };
}

impl_to_tokens_slice! { ast::Ty, [ast::TtToken(DUMMY_SP, token::Comma)] }
impl_to_tokens_slice! { P<ast::Item>, [] }

impl ToTokens for P<ast::MetaItem> {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
    }
}

impl ToTokens for ast::Attribute {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let mut r = vec![];
        // FIXME: The spans could be better
        r.push(ast::TtToken(self.span, token::Pound));
        if self.node.style == ast::AttrInner {
            r.push(ast::TtToken(self.span, token::Not));
        }
        r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited {
            delim: token::Bracket,
            open_span: self.span,
            tts: self.node.value.to_tokens(cx),
            close_span: self.span,
        })));
        r
    }
}

impl ToTokens for str {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let lit = ast::LitStr(
            token::intern_and_get_ident(self), ast::CookedStr);
        dummy_spanned(lit).to_tokens(cx)
    }
}

impl ToTokens for () {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec![ast::TtDelimited(DUMMY_SP, Rc::new(ast::Delimited {
            delim: token::Paren,
            open_span: DUMMY_SP,
            tts: vec![],
            close_span: DUMMY_SP,
        }))]
    }
}

impl ToTokens for ast::Lit {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: This is wrong
        P(ast::Expr {
            id: ast::DUMMY_NODE_ID,
            node: ast::ExprLit(P(self.clone())),
            span: DUMMY_SP,
        }).to_tokens(cx)
    }
}

impl ToTokens for bool {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
    }
}

impl ToTokens for char {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
    }
}

macro_rules! impl_to_tokens_int {
    (signed, $t:ty, $tag:expr) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                      ast::Sign::new(*self)));
                dummy_spanned(lit).to_tokens(cx)
            }
        }
    );
    (unsigned, $t:ty, $tag:expr) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
                dummy_spanned(lit).to_tokens(cx)
            }
        }
    );
}

impl_to_tokens_int! { signed, isize, ast::TyIs }
impl_to_tokens_int! { signed, i8,  ast::TyI8 }
impl_to_tokens_int! { signed, i16, ast::TyI16 }
impl_to_tokens_int! { signed, i32, ast::TyI32 }
impl_to_tokens_int! { signed, i64, ast::TyI64 }

impl_to_tokens_int! { unsigned, usize, ast::TyUs }
impl_to_tokens_int! { unsigned, u8,   ast::TyU8 }
impl_to_tokens_int! { unsigned, u16,  ast::TyU16 }
impl_to_tokens_int! { unsigned, u32,  ast::TyU32 }
impl_to_tokens_int! { unsigned, u64,  ast::TyU64 }

pub trait ExtParseUtils {
    fn parse_item(&self, s: String) -> P<ast::Item>;
    fn parse_expr(&self, s: String) -> P<ast::Expr>;
    fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}

impl<'a> ExtParseUtils for ExtCtxt<'a> {

    fn parse_item(&self, s: String) -> P<ast::Item> {
        parse::parse_item_from_source_str(
            "<quote expansion>".to_string(),
            s,
            self.cfg(),
            self.parse_sess()).expect("parse error")
    }

    fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
        parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess()).expect("parse error")
    }

    fn parse_expr(&self, s: String) -> P<ast::Expr> {
        parse::parse_expr_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess())
    }

    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
        parse::parse_tts_from_source_str("<quote expansion>".to_string(),
                                         s,
                                         self.cfg(),
                                         self.parse_sess())
    }
}
<|endoftext|>