<commit_before>use std::cell::Ref;
use std::collections::HashMap;
use std::rc::Rc;

use ga::{self, Array, Tensor, TensorMode};
use rand;

use super::init::Initializer;
use super::op::{OpBuilder, OpDescriptor, Operation};
use super::var_store::{VarIndex, VarStore};

#[derive(Copy, Clone)]
pub enum NodeInput {
    Var(VarIndex),    // Regular input variable
    Recurrent(usize), // Recurrent connection
}

pub struct Node {
    pub inputs: Vec<VarIndex>,
    pub outputs: Vec<VarIndex>,
    pub in_grad: Vec<VarIndex>, // gradients on inputs
    pub out_grad: Vec<OutGrad>, // gradients on outputs
}

pub struct Graph {
    ctx: Rc<ga::Context>,
    nodes: Vec<Node>,
    node_ops: Vec<Box<Operation>>,
    pub var_store: VarStore,
    out_var_map: HashMap<VarIndex, (NodeIndex, usize)>, // Maps output variable to its node and index within node
    // Gradients on variables that are inputs to the graph - they have no corresponding node
    in_var_map: HashMap<VarIndex, usize>,
    learnables: Vec<(VarIndex, GradIndex)>, // Learnable variables
    in_grad: Vec<OutGrad>, // Gradients on variables that are inputs to the graph

    rng: rand::ThreadRng,
}

impl Graph {
    pub fn new(ctx: Rc<ga::Context>) -> Self {
        Graph {
            ctx: ctx,
            nodes: vec![],
            node_ops: vec![],
            var_store: VarStore::new(),
            out_var_map: HashMap::new(),
            in_var_map: HashMap::new(),
            learnables: vec![],
            in_grad: vec![],
            rng: rand::thread_rng(),
        }
    }

    pub fn add_node<T: OpBuilder>(&mut self, op: T) -> NodeIndex {
        let node_index = NodeIndex(self.nodes.len());

        let OpDescriptor { op, inputs, out_shapes } = op.build(&self.ctx, &self.var_store).unwrap();

        // Create output variables
        let mut outputs = vec![];
        for (i, shape) in out_shapes.into_iter().enumerate() {
            let var_index = self.var_store.add(Tensor::new(self.ctx.as_ref(), shape, TensorMode::Mut));
            outputs.push(var_index);
            self.out_var_map.insert(var_index, (node_index, i));
        }
        // Convert array of NodeInputs to VarIndexes
        let inputs: Vec<VarIndex> =
            inputs.into_iter().map(|input| {
                match input {
                    NodeInput::Var(v) => v,
                    NodeInput::Recurrent(out) => outputs[out],
                }
            }).collect();
        // Create gradients on input variables
        let mut in_grad = vec![];
        for input in &inputs {
            let gradient = self.add_gradient(*input);
            in_grad.push(gradient);
        }
        // Create the node
        let num_outputs = outputs.len();
        self.nodes.push(Node { inputs: inputs,
                               outputs: outputs,
                               in_grad: in_grad,
                               out_grad: vec![OutGrad::new(); num_outputs] });
        // Add the corresponding node op
        self.node_ops.push(Box::new(op));
        node_index
    }

    pub fn add_variable<I: Initializer>(&mut self,
                                        shape: Vec<usize>,
                                        learnable: bool,
                                        init: I) -> VarIndex {
        let a = init.init(&mut self.rng, shape);
        let v = self.var_store.add(Tensor::from_array(&self.ctx, &a, TensorMode::Mut));
        self.in_var_map.insert(v, self.in_grad.len());
        if learnable {
            self.learnables.push((v, GradIndex::InVar(self.in_grad.len())));
        }
        self.in_grad.push(OutGrad::new());
        v
    }

    pub fn get_gradient(&self, v: VarIndex) -> GradIndex {
        match self.out_var_map.get(&v).map(|x| *x) {
            Some((node, out_index)) => {
                // v is the output of a node
                GradIndex::OutVar(node, out_index)
            },
            None => {
                // v is an input to the graph - it has no corresponding node
                let in_grad_index = *self.in_var_map.get(&v)
                                         .expect("Variable is neither input nor output. Nonsense!");
                GradIndex::InVar(in_grad_index)
            },
        }
    }

    pub fn add_gradient(&mut self, v: VarIndex) -> VarIndex {
        let shape = v.get(self).shape().to_owned();
        let gradient = self.var_store.add(Tensor::new(&self.ctx, shape, TensorMode::Mut));
        match self.out_var_map.get(&v).map(|x| *x) {
            Some((node, out_index)) => {
                // v is the output of a node
                self.nodes[node.0].out_grad[out_index]
                                  .fork(&self.ctx, &mut self.var_store, gradient);
            },
            None => {
                // v is an input to the graph - it has no corresponding node
                let in_grad_index = *self.in_var_map.get(&v)
                                         .expect("Variable is neither input nor output. Nonsense!");
                self.in_grad[in_grad_index]
                    .fork(&self.ctx, &mut self.var_store, gradient);
            },
        }
        gradient
    }

    pub fn forward(&mut self) {
        // Forward pass
        //
        // NOTE: We just execute the nodes in order. We can do this because of the way the graph is
        // built. When a user wants to add a node, he/she must also supply the inputs. This means
        // any dependencies must already be added before the node can be added. Therefore, we can
        // assert that all dependents come after their dependencies in the `self.nodes` array.
        for (node, op) in self.nodes.iter().zip(&mut self.node_ops) {
            op.forward(&self.ctx, &self.var_store, node);
        }
    }

    pub fn backward(&mut self) {
        // Backward pass
        // We run through the nodes in reverse order. See note in Graph::forward
        for (node, op) in self.nodes.iter_mut().rev().zip(self.node_ops.iter_mut().rev()) {
            // Sum the gradients on each output if there are multiple gradients
            for out_grad in &node.out_grad {
                out_grad.maybe_sum(self.ctx.as_ref(), &mut self.var_store);
            }
            op.backward(&self.ctx, &mut self.var_store, node);
        }
    }

    pub fn context(&self) -> &ga::Context {
        &self.ctx
    }

    pub fn learnables(&self) -> &[(VarIndex, GradIndex)] {
        &self.learnables
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Clone)]
pub struct OutGrad {
    gradient: Option<VarIndex>, // The gradient or sum of gradients
    gradients: Vec<VarIndex>,
}

impl OutGrad {
    pub fn new() -> Self {
        OutGrad {
            gradient: None,
            gradients: vec![],
        }
    }

    pub fn get(&self) -> VarIndex {
        self.gradient.unwrap()
    }

    pub fn try_get(&self) -> Option<VarIndex> {
        self.gradient
    }

    fn maybe_sum(&self, ctx: &ga::Context, var_store: &mut VarStore) {
        if self.gradients.len() > 0 {
            if let Some(sum) = self.gradient {
                ga::copy_to(ctx, &var_store.get(self.gradients[0]), &var_store.get_mut(sum));
                for grad in &self.gradients[1..] {
                    ga::add(ctx, &var_store.get(sum), -1, &var_store.get(*grad), &var_store.get_mut(sum));
                }
            }
        }
    }

    fn fork(&mut self, ctx: &ga::Context, var_store: &mut VarStore, v: VarIndex) {
        if self.gradients.len() > 0 {
            // There are multiple gradients already, just add the new one to the list
            self.gradients.push(v);
        } else if let Some(gradient) = self.gradient {
            // There is still only one gradient, switch it to a fork
            let shape = {
                let grad = var_store.get(gradient);
                grad.shape().to_vec()
            };
            // Create variable for gradient sum
            self.gradient = Some(var_store.add(Tensor::new(ctx, shape, TensorMode::Mut)));
            self.gradients.push(gradient);
            self.gradients.push(v);
        } else {
            // This is the only gradient so far, so we don't need to sum anything
            self.gradient = Some(v);
        }
    }
}

#[derive(Copy, Clone)]
pub enum GradIndex {
    InVar(usize),
    OutVar(NodeIndex, usize),
}

impl GradIndex {
    pub fn get<'a>(&self, graph: &'a Graph) -> Ref<'a, Tensor<f32>> {
        match *self {
            GradIndex::InVar(in_grad_index) => {
                graph.in_grad[in_grad_index].get().get(graph)
            },
            GradIndex::OutVar(node, out_index) => {
                node.get(graph).out_grad[out_index].get().get(graph)
            },
        }
    }

    pub fn read(&self, g: &Graph, a: &mut Array<f32>) {
        self.get(g).read(g.context(), a);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

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

impl NodeIndex {
    pub fn get<'a>(&self, g: &'a Graph) -> &'a Node {
        &g.nodes[self.0]
    }
}

#[test]
fn it_works() {
    use super::op::MatMul;

    let ctx = Rc::new(ga::Context::new());

    // Setup the graph
    let mut graph = Graph::new(ctx.clone());
    let a = graph.add_variable(vec![1, 2], true, vec![1.4, 0.3]);
    let wa = graph.add_variable(vec![2, 3], true, vec![0.5, 0.3, 0.2,
                                                       0.6, 0.7, 0.7]);
    let node = graph.add_node(MatMul(a, wa));
    let node_out = node.get(&graph).outputs[0];
    let node_g = graph.add_gradient(node_out);

    // Send some input data
    let node_g_cpu = ga::Array::from_vec(vec![1, 3], vec![1.0, -1.0, 0.5]);
    node_g.get(&graph).set(&ctx, &node_g_cpu);

    // Run the network
    graph.forward();
    graph.backward();
    let out = node.get(&graph).outputs[0].get(&graph).get(&ctx);
    let wa_d = graph.get_gradient(wa).get(&graph).get(&ctx);
    println!("out = {:?}", out);
    println!("wa_d = {:?}", wa_d);
    assert!(out.buffer() == &[0.88, 0.63, 0.49]);
    assert!(wa_d.buffer() == &[1.4, -1.4, 0.7,
                               0.3, -0.3, 0.15]);
}
<commit_msg>Fixed bug in setting up input gradients on recurrent connections<commit_after>use std::cell::Ref;
use std::collections::HashMap;
use std::rc::Rc;

use ga::{self, Array, Tensor, TensorMode};
use rand;

use super::init::Initializer;
use super::op::{OpBuilder, OpDescriptor, Operation};
use super::var_store::{VarIndex, VarStore};

#[derive(Copy, Clone)]
pub enum NodeInput {
    Var(VarIndex),    // Regular input variable
    Recurrent(usize), // Recurrent connection
}

pub struct Node {
    pub inputs: Vec<VarIndex>,
    pub outputs: Vec<VarIndex>,
    pub in_grad: Vec<VarIndex>, // gradients on inputs
    pub out_grad: Vec<OutGrad>, // gradients on outputs
}

pub struct Graph {
    ctx: Rc<ga::Context>,
    nodes: Vec<Node>,
    node_ops: Vec<Box<Operation>>,
    pub var_store: VarStore,
    out_var_map: HashMap<VarIndex, (NodeIndex, usize)>, // Maps output variable to its node and index within node
    // Gradients on variables that are inputs to the graph - they have no corresponding node
    in_var_map: HashMap<VarIndex, usize>,
    learnables: Vec<(VarIndex, GradIndex)>, // Learnable variables
    in_grad: Vec<OutGrad>, // Gradients on variables that are inputs to the graph

    rng: rand::ThreadRng,
}

impl Graph {
    pub fn new(ctx: Rc<ga::Context>) -> Self {
        Graph {
            ctx: ctx,
            nodes: vec![],
            node_ops: vec![],
            var_store: VarStore::new(),
            out_var_map: HashMap::new(),
            in_var_map: HashMap::new(),
            learnables: vec![],
            in_grad: vec![],
            rng: rand::thread_rng(),
        }
    }

    pub fn add_node<T: OpBuilder>(&mut self, op: T) -> NodeIndex {
        let node_index = NodeIndex(self.nodes.len());

        let OpDescriptor { op, inputs: node_inputs, out_shapes } = op.build(&self.ctx, &self.var_store).unwrap();

        // Create output variables
        let mut outputs = vec![];
        for (i, shape) in out_shapes.into_iter().enumerate() {
            let var_index = self.var_store.add(Tensor::new(self.ctx.as_ref(), shape, TensorMode::Mut));
            outputs.push(var_index);
            self.out_var_map.insert(var_index, (node_index, i));
        }
        let mut out_grad = vec![OutGrad::new(); outputs.len()];
        // Set up inputs and gradients on inputs
        let mut inputs = vec![];
        let mut in_grad = vec![];
        for input in node_inputs {
            let (v, gradient) =
                match input {
                    NodeInput::Var(v) => (v, self.add_gradient(v)),
                    NodeInput::Recurrent(out) => {
                        let v = outputs[out];
                        let gradient = Self::create_gradient(&self.ctx, &mut self.var_store, v,
                                                             &mut out_grad[out]);
                        (v, gradient)
                    }
                };
            inputs.push(v);
            in_grad.push(gradient);
        }
        // Create the node
        self.nodes.push(Node { inputs: inputs,
                               outputs: outputs,
                               in_grad: in_grad,
                               out_grad: out_grad });
        // Add the corresponding node op
        self.node_ops.push(Box::new(op));
        node_index
    }

    pub fn add_variable<I: Initializer>(&mut self,
                                        shape: Vec<usize>,
                                        learnable: bool,
                                        init: I) -> VarIndex {
        let a = init.init(&mut self.rng, shape);
        let v = self.var_store.add(Tensor::from_array(&self.ctx, &a, TensorMode::Mut));
        self.in_var_map.insert(v, self.in_grad.len());
        if learnable {
            self.learnables.push((v, GradIndex::InVar(self.in_grad.len())));
        }
        self.in_grad.push(OutGrad::new());
        v
    }

    pub fn get_gradient(&self, v: VarIndex) -> GradIndex {
        match self.out_var_map.get(&v).map(|x| *x) {
            Some((node, out_index)) => {
                // v is the output of a node
                GradIndex::OutVar(node, out_index)
            },
            None => {
                // v is an input to the graph - it has no corresponding node
                let in_grad_index = *self.in_var_map.get(&v)
                                         .expect("Variable is neither input nor output. Nonsense!");
                GradIndex::InVar(in_grad_index)
            },
        }
    }

    pub fn add_gradient(&mut self, v: VarIndex) -> VarIndex {
        match self.out_var_map.get(&v).map(|x| *x) {
            Some((node, out_index)) => {
                // v is the output of a node
                /*self.nodes[node.0].out_grad[out_index]
                                  .fork(&self.ctx, &mut self.var_store, gradient);*/
                Self::create_gradient(&self.ctx, &mut self.var_store, v,
                                      &mut self.nodes[node.0].out_grad[out_index])
            },
            None => {
                // v is an input to the graph - it has no corresponding node
                let in_grad_index = *self.in_var_map.get(&v)
                                         .expect("Variable is neither input nor output. Nonsense!");
                /*self.in_grad[in_grad_index]
                    .fork(&self.ctx, &mut self.var_store, gradient);*/
                Self::create_gradient(&self.ctx, &mut self.var_store, v,
                                      &mut self.in_grad[in_grad_index])
            },
        }
    }

    fn create_gradient(ctx: &ga::Context,
                       var_store: &mut VarStore,
                       v: VarIndex,
                       out_grad: &mut OutGrad)
                       -> VarIndex {
        let shape = var_store.get(v).shape().to_owned();
        let gradient = var_store.add(Tensor::new(ctx, shape, TensorMode::Mut));
        out_grad.fork(ctx, var_store, gradient);
        gradient
    }

    pub fn forward(&mut self) {
        // Forward pass
        //
        // NOTE: We just execute the nodes in order. We can do this because of the way the graph is
        // built. When a user wants to add a node, he/she must also supply the inputs. This means
        // any dependencies must already be added before the node can be added. Therefore, we can
        // assert that all dependents come after their dependencies in the `self.nodes` array.
        for (node, op) in self.nodes.iter().zip(&mut self.node_ops) {
            op.forward(&self.ctx, &self.var_store, node);
        }
    }

    pub fn backward(&mut self) {
        // Backward pass
        // We run through the nodes in reverse order. See note in Graph::forward
        for (node, op) in self.nodes.iter_mut().rev().zip(self.node_ops.iter_mut().rev()) {
            // Sum the gradients on each output if there are multiple gradients
            for out_grad in &node.out_grad {
                out_grad.maybe_sum(self.ctx.as_ref(), &mut self.var_store);
            }
            op.backward(&self.ctx, &mut self.var_store, node);
        }
    }

    pub fn context(&self) -> &ga::Context {
        &self.ctx
    }

    pub fn learnables(&self) -> &[(VarIndex, GradIndex)] {
        &self.learnables
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Clone)]
pub struct OutGrad {
    gradient: Option<VarIndex>, // The gradient or sum of gradients
    gradients: Vec<VarIndex>,
}

impl OutGrad {
    pub fn new() -> Self {
        OutGrad {
            gradient: None,
            gradients: vec![],
        }
    }

    pub fn get(&self) -> VarIndex {
        self.gradient.unwrap()
    }

    pub fn try_get(&self) -> Option<VarIndex> {
        self.gradient
    }

    fn maybe_sum(&self, ctx: &ga::Context, var_store: &mut VarStore) {
        if self.gradients.len() > 0 {
            if let Some(sum) = self.gradient {
                ga::copy_to(ctx, &var_store.get(self.gradients[0]), &var_store.get_mut(sum));
                for grad in &self.gradients[1..] {
                    ga::add(ctx, &var_store.get(sum), -1, &var_store.get(*grad), &var_store.get_mut(sum));
                }
            }
        }
    }

    fn fork(&mut self, ctx: &ga::Context, var_store: &mut VarStore, v: VarIndex) {
        if self.gradients.len() > 0 {
            // There are multiple gradients already, just add the new one to the list
            self.gradients.push(v);
        } else if let Some(gradient) = self.gradient {
            // There is still only one gradient, switch it to a fork
            let shape = {
                let grad = var_store.get(gradient);
                grad.shape().to_vec()
            };
            // Create variable for gradient sum
            self.gradient = Some(var_store.add(Tensor::new(ctx, shape, TensorMode::Mut)));
            self.gradients.push(gradient);
            self.gradients.push(v);
        } else {
            // This is the only gradient so far, so we don't need to sum anything
            self.gradient = Some(v);
        }
    }
}

#[derive(Copy, Clone)]
pub enum GradIndex {
    InVar(usize),
    OutVar(NodeIndex, usize),
}

impl GradIndex {
    pub fn get<'a>(&self, graph: &'a Graph) -> Ref<'a, Tensor<f32>> {
        match *self {
            GradIndex::InVar(in_grad_index) => {
                graph.in_grad[in_grad_index].get().get(graph)
            },
            GradIndex::OutVar(node, out_index) => {
                node.get(graph).out_grad[out_index].get().get(graph)
            },
        }
    }

    pub fn read(&self, g: &Graph, a: &mut Array<f32>) {
        self.get(g).read(g.context(), a);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

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

impl NodeIndex {
    pub fn get<'a>(&self, g: &'a Graph) -> &'a Node {
        &g.nodes[self.0]
    }
}

#[test]
fn it_works() {
    use super::op::MatMul;

    let ctx = Rc::new(ga::Context::new());

    // Setup the graph
    let mut graph = Graph::new(ctx.clone());
    let a = graph.add_variable(vec![1, 2], true, vec![1.4, 0.3]);
    let wa = graph.add_variable(vec![2, 3], true, vec![0.5, 0.3, 0.2,
                                                       0.6, 0.7, 0.7]);
    let node = graph.add_node(MatMul(a, wa));
    let node_out = node.get(&graph).outputs[0];
    let node_g = graph.add_gradient(node_out);

    // Send some input data
    let node_g_cpu = ga::Array::from_vec(vec![1, 3], vec![1.0, -1.0, 0.5]);
    node_g.get(&graph).set(&ctx, &node_g_cpu);

    // Run the network
    graph.forward();
    graph.backward();
    let out = node.get(&graph).outputs[0].get(&graph).get(&ctx);
    let wa_d = graph.get_gradient(wa).get(&graph).get(&ctx);
    println!("out = {:?}", out);
    println!("wa_d = {:?}", wa_d);
    assert!(out.buffer() == &[0.88, 0.63, 0.49]);
    assert!(wa_d.buffer() == &[1.4, -1.4, 0.7,
                               0.3, -0.3, 0.15]);
}
<|endoftext|>


<commit_before>use syntax::ast::{Expr, Lit, TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::parse;
use syntax::parse::parser::Parser as RustParser;
use syntax::parse::token;
use syntax::ptr::P;

use super::render::{Escape, Renderer};

macro_rules! guard {
    ($e:expr) => (if !$e { return false; })
}

macro_rules! dollar {
    () => (TtToken(_, token::Dollar))
}
macro_rules! eq {
    () => (TtToken(_, token::Eq))
}
macro_rules! semi {
    () => (TtToken(_, token::Semi))
}
macro_rules! minus {
    () => (TtToken(_, token::BinOp(token::Minus)))
}
macro_rules! literal {
    () => (TtToken(_, token::Literal(..)))
}
macro_rules! ident {
    ($x:pat) => (ident!(_, $x));
    ($sp:pat, $x:pat) => (TtToken($sp, token::Ident($x, token::IdentStyle::Plain)))
}

pub fn parse(cx: &mut ExtCtxt, input: &[TokenTree]) -> Option<P<Expr>> {
    let mut success = true;
    let expr = Renderer::with(cx, |render| {
        let mut parser = Parser {
            in_attr: false,
            input: input,
            render: render,
        };
        success = parser.markups();
    });
    if success {
        Some(expr)
    } else {
        None
    }
}

struct Parser<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> {
    in_attr: bool,
    input: &'i [TokenTree],
    render: &'r mut Renderer<'cx, 's, 'o>,
}

impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> {
    /// Consume `n` items from the input.
    fn shift(&mut self, n: usize) {
        self.input = self.input.slice_from(n);
    }

    /// Construct a Rust AST parser from the given token tree.
    fn new_rust_parser(&self, tts: Vec<TokenTree>) -> RustParser<'s> {
        parse::tts_to_parser(self.render.cx.parse_sess, tts, self.render.cx.cfg.clone())
    }

    fn markups(&mut self) -> bool {
        loop {
            match self.input {
                [] => return true,
                [semi!(), ..] => self.shift(1),
                [_, ..] => guard!(self.markup()),
            }
        }
    }

    fn markup(&mut self) -> bool {
        match self.input {
            // Literal
            [minus!(), ref tt @ literal!(), ..] => {
                self.shift(2);
                self.literal(tt, true)
            },
            [ref tt @ literal!(), ..] => {
                self.shift(1);
                self.literal(tt, false)
            },
            // Splice
            [ref tt @ dollar!(), dollar!(), ..] => {
                self.shift(2);
                self.splice(Escape::PassThru, tt.get_span())
            },
            [ref tt @ dollar!(), ..] => {
                self.shift(1);
                self.splice(Escape::Escape, tt.get_span())
            },
            // Element
            [ident!(sp, name), ..] => {
                self.shift(1);
                self.element(name.as_str(), sp)
            },
            // Block
            [TtDelimited(_, ref d), ..] if d.delim == token::DelimToken::Brace => {
                self.shift(1);
                self.block(d.tts.as_slice())
            },
            // ???
            _ => {
                if let [ref tt, ..] = self.input {
                    self.render.cx.span_err(tt.get_span(), "invalid syntax");
                }
                false
            },
        }
    }

    fn literal(&mut self, tt: &TokenTree, minus: bool) -> bool {
        let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit();
        match lit_to_string(self.render.cx, lit, minus) {
            Some(s) => self.render.string(s.as_slice(), Escape::Escape),
            None => return false,
        }
        true
    }

    fn splice(&mut self, escape: Escape, sp: Span) -> bool {
        let tt = match self.input {
            [ref tt, ..] => {
                self.shift(1);
                self.new_rust_parser(vec![tt.clone()]).parse_expr()
            },
            _ => {
                self.render.cx.span_err(sp, "expected expression for this splice");
                return false;
            },
        };
        self.render.splice(tt, escape);
        true
    }

    fn element(&mut self, name: &str, sp: Span) -> bool {
        if self.in_attr {
            self.render.cx.span_err(sp, "unexpected element, you silly bumpkin");
            return false;
        }
        self.render.element_open_start(name);
        guard!(self.attrs());
        self.render.element_open_end();
        guard!(self.markup());
        self.render.element_close(name);
        true
    }

    fn attrs(&mut self) -> bool {
        while let [ident!(name), eq!(), ..] = self.input {
            self.shift(2);
            self.render.attribute_start(name.as_str());
            {
                let old_in_attr = self.in_attr;
                self.in_attr = true;
                guard!(self.markup());
                self.in_attr = old_in_attr;
            }
            self.render.attribute_end();
        }
        true
    }

    fn block(&mut self, tts: &[TokenTree]) -> bool {
        Parser {
            in_attr: self.in_attr,
            input: tts,
            render: self.render,
        }.markups()
    }
}

/// Convert a literal to a string.
fn lit_to_string(cx: &mut ExtCtxt, lit: Lit, minus: bool) -> Option<String> {
    use syntax::ast::Lit_::*;
    let mut result = String::new();
    if minus {
        result.push('-');
    }
    match lit.node {
        LitStr(s, _) => result.push_str(s.get()),
        LitBinary(..) | LitByte(..) => {
            cx.span_err(lit.span, "cannot splice binary data");
            return None;
        },
        LitChar(c) => result.push(c),
        LitInt(x, _) => result.push_str(x.to_string().as_slice()),
        LitFloat(s, _) | LitFloatUnsuffixed(s) => result.push_str(s.get()),
        LitBool(b) => result.push_str(if b { "true" } else { "false" }),
    };
    Some(result)
}
<commit_msg>Add self-closing elements<commit_after>use syntax::ast::{Expr, Lit, TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::parse;
use syntax::parse::parser::Parser as RustParser;
use syntax::parse::token;
use syntax::ptr::P;

use super::render::{Escape, Renderer};

macro_rules! guard {
    ($e:expr) => (if !$e { return false; })
}

macro_rules! dollar {
    () => (TtToken(_, token::Dollar))
}
macro_rules! eq {
    () => (TtToken(_, token::Eq))
}
macro_rules! semi {
    () => (TtToken(_, token::Semi))
}
macro_rules! minus {
    () => (TtToken(_, token::BinOp(token::Minus)))
}
macro_rules! slash {
    () => (TtToken(_, token::BinOp(token::Slash)))
}
macro_rules! literal {
    () => (TtToken(_, token::Literal(..)))
}
macro_rules! ident {
    ($x:pat) => (ident!(_, $x));
    ($sp:pat, $x:pat) => (TtToken($sp, token::Ident($x, token::IdentStyle::Plain)))
}

pub fn parse(cx: &mut ExtCtxt, input: &[TokenTree]) -> Option<P<Expr>> {
    let mut success = true;
    let expr = Renderer::with(cx, |render| {
        let mut parser = Parser {
            in_attr: false,
            input: input,
            render: render,
        };
        success = parser.markups();
    });
    if success {
        Some(expr)
    } else {
        None
    }
}

struct Parser<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> {
    in_attr: bool,
    input: &'i [TokenTree],
    render: &'r mut Renderer<'cx, 's, 'o>,
}

impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> {
    /// Consume `n` items from the input.
    fn shift(&mut self, n: usize) {
        self.input = self.input.slice_from(n);
    }

    /// Construct a Rust AST parser from the given token tree.
    fn new_rust_parser(&self, tts: Vec<TokenTree>) -> RustParser<'s> {
        parse::tts_to_parser(self.render.cx.parse_sess, tts, self.render.cx.cfg.clone())
    }

    fn markups(&mut self) -> bool {
        loop {
            match self.input {
                [] => return true,
                [semi!(), ..] => self.shift(1),
                [_, ..] => guard!(self.markup()),
            }
        }
    }

    fn markup(&mut self) -> bool {
        match self.input {
            // Literal
            [minus!(), ref tt @ literal!(), ..] => {
                self.shift(2);
                self.literal(tt, true)
            },
            [ref tt @ literal!(), ..] => {
                self.shift(1);
                self.literal(tt, false)
            },
            // Splice
            [ref tt @ dollar!(), dollar!(), ..] => {
                self.shift(2);
                self.splice(Escape::PassThru, tt.get_span())
            },
            [ref tt @ dollar!(), ..] => {
                self.shift(1);
                self.splice(Escape::Escape, tt.get_span())
            },
            // Element
            [ident!(sp, name), ..] => {
                self.shift(1);
                self.element(name.as_str(), sp)
            },
            // Block
            [TtDelimited(_, ref d), ..] if d.delim == token::DelimToken::Brace => {
                self.shift(1);
                self.block(d.tts.as_slice())
            },
            // ???
            _ => {
                if let [ref tt, ..] = self.input {
                    self.render.cx.span_err(tt.get_span(), "invalid syntax");
                }
                false
            },
        }
    }

    fn literal(&mut self, tt: &TokenTree, minus: bool) -> bool {
        let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit();
        match lit_to_string(self.render.cx, lit, minus) {
            Some(s) => self.render.string(s.as_slice(), Escape::Escape),
            None => return false,
        }
        true
    }

    fn splice(&mut self, escape: Escape, sp: Span) -> bool {
        let tt = match self.input {
            [ref tt, ..] => {
                self.shift(1);
                self.new_rust_parser(vec![tt.clone()]).parse_expr()
            },
            _ => {
                self.render.cx.span_err(sp, "expected expression for this splice");
                return false;
            },
        };
        self.render.splice(tt, escape);
        true
    }

    fn element(&mut self, name: &str, sp: Span) -> bool {
        if self.in_attr {
            self.render.cx.span_err(sp, "unexpected element, you silly bumpkin");
            return false;
        }
        self.render.element_open_start(name);
        guard!(self.attrs());
        self.render.element_open_end();
        if let [slash!(), ..] = self.input {
            self.shift(1);
        } else {
            guard!(self.markup());
            self.render.element_close(name);
        }
        true
    }

    fn attrs(&mut self) -> bool {
        while let [ident!(name), eq!(), ..] = self.input {
            self.shift(2);
            self.render.attribute_start(name.as_str());
            {
                let old_in_attr = self.in_attr;
                self.in_attr = true;
                guard!(self.markup());
                self.in_attr = old_in_attr;
            }
            self.render.attribute_end();
        }
        true
    }

    fn block(&mut self, tts: &[TokenTree]) -> bool {
        Parser {
            in_attr: self.in_attr,
            input: tts,
            render: self.render,
        }.markups()
    }
}

/// Convert a literal to a string.
fn lit_to_string(cx: &mut ExtCtxt, lit: Lit, minus: bool) -> Option<String> {
    use syntax::ast::Lit_::*;
    let mut result = String::new();
    if minus {
        result.push('-');
    }
    match lit.node {
        LitStr(s, _) => result.push_str(s.get()),
        LitBinary(..) | LitByte(..) => {
            cx.span_err(lit.span, "cannot splice binary data");
            return None;
        },
        LitChar(c) => result.push(c),
        LitInt(x, _) => result.push_str(x.to_string().as_slice()),
        LitFloat(s, _) | LitFloatUnsuffixed(s) => result.push_str(s.get()),
        LitBool(b) => result.push_str(if b { "true" } else { "false" }),
    };
    Some(result)
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use std::os::raw::c_int;

use ffi;
use stream::OutStream;

pub type SioResult<T> = Result<T, ffi::SioError>;

pub struct SoundIo {
    context: *mut ffi::SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn channel_layout_builtin_count() -> i32 {
        let cnt = unsafe { ffi::soundio_channel_layout_builtin_count() };
        if cnt < 0 {
            panic!("Negative # of builtin channel layouts!")
        } else {
            cnt as i32
        }
    }

    pub fn connect(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self, backend: ffi::SioBackend) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::SioError::None => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt = unsafe { ffi::soundio_backend_count(self.context) } as i32;
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::SioBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::SioBackend::None => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn current_backend(&self) -> Option<ffi::SioBackend> {
        match unsafe { (*self.context).current_backend } {
            ffi::SioBackend::None => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::SioBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }

    pub fn input_device_count(&self) -> Option<i32> {
        let cnt = unsafe { ffi::soundio_input_device_count(self.context) };
        if cnt < 0 {
            None
        } else {
            Some(cnt as i32)
        }
    }

    pub fn output_device_count(&self) -> Option<i32> {
        let cnt = unsafe { ffi::soundio_output_device_count(self.context) };
        if cnt < 0 {
            None
        } else {
            Some(cnt as i32)
        }
    }

    pub fn get_input_device(&self, idx: i32) -> Option<Device> {
        let dev_ptr = unsafe { ffi::soundio_get_input_device(self.context, idx) };
        if dev_ptr.is_null() {
            None
        } else {
            Some(Device::new(dev_ptr))
        }
    }

    pub fn get_output_device(&self, idx: i32) -> Option<Device> {
        let dev_ptr = unsafe { ffi::soundio_get_output_device(self.context, idx) };
        if dev_ptr.is_null() {
            None
        } else {
            Some(Device::new(dev_ptr))
        }
    }

    pub fn default_input_device_index(&self) -> Option<i32> {
        match unsafe { ffi::soundio_default_input_device_index(self.context) } {
            -1 => None,
            idx @ _ => Some(idx as i32),
        }
    }

    pub fn default_output_device_index(&self) -> Option<i32> {
        match unsafe { ffi::soundio_default_output_device_index(self.context) } {
            -1 => None,
            idx @ _ => Some(idx as i32),
        }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[derive(Debug)]
pub struct ChannelLayout {
    layout: *const ffi::SoundIoChannelLayout,
}
impl ChannelLayout {
    pub fn new(raw_layout: *const ffi::SoundIoChannelLayout) -> Self {
        ChannelLayout { layout: raw_layout }
    }

    pub fn get_builtin(idx: i32) -> Option<Self> {
        if 0 <= idx && idx < SoundIo::channel_layout_builtin_count() {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_builtin(idx as c_int)
            }))
        } else {
            None
        }
    }

    pub fn get_default(channel_count: i32) -> Option<Self> {
        if channel_count < 0 {
            None
        } else {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_default(channel_count as i32)
            }))
        }
    }

    pub fn find_channel(&self, channel: ffi::SioChannelId) -> Option<i32> {
        match unsafe { ffi::soundio_channel_layout_find_channel(self.layout, channel) } {
            -1 => None,
            idx @ _ => Some(idx),
        }
    }

    pub fn detect_builtin(&mut self) -> bool {
        // This is a hack because of the transmute.
        unsafe {
            let mut_layout: *mut ffi::SoundIoChannelLayout = ::std::mem::transmute(self.layout);
            ffi::soundio_channel_layout_detect_builtin(mut_layout) == 1
        }
    }

    pub fn best_matching_channel_layout(preferred_layouts: &[ChannelLayout],
                                        available_layouts: &[ChannelLayout])
                                        -> Option<ChannelLayout> {
        // do some magic with the slices
        let raw_preferred_layouts: Vec<_> = preferred_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let raw_available_layouts: Vec<_> = available_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let layout_ptr = unsafe {
            ffi::soundio_best_matching_channel_layout(raw_preferred_layouts.as_ptr(),
                                                      preferred_layouts.len() as c_int,
                                                      raw_available_layouts.as_ptr(),
                                                      available_layouts.len() as c_int)
        };
        if layout_ptr.is_null() {
            None
        } else {
            Some(ChannelLayout::new(layout_ptr))
        }
    }

    pub fn channel_count(&self) -> i32 {
        unsafe { (*self.layout).channel_count as i32 }
    }
}
impl PartialEq for ChannelLayout {
    fn eq(&self, other: &Self) -> bool {
        unsafe { ffi::soundio_channel_layout_equal(self.layout, other.layout) == 1u8 }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}
impl Display for ChannelLayout {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let str_ptr = unsafe { (*self.layout).name };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}

#[derive(Debug)]
pub struct Device {
    device: *mut ffi::SoundIoDevice,
}
impl Device {
    pub fn new(dev_ptr: *mut ffi::SoundIoDevice) -> Self {
        Device { device: dev_ptr }
    }

    // ref is a keyword
    pub fn inc_ref(&self) {
        unsafe { ffi::soundio_device_ref(self.device) }
    }

    pub fn dec_ref(&self) {
        unsafe { ffi::soundio_device_unref(self.device) }
    }

    pub fn sort_channel_layouts(&self) {
        unsafe { ffi::soundio_device_sort_channel_layouts(self.device) }
    }

    pub fn supports_format(&self, format: ffi::SioFormat) -> bool {
        unsafe { ffi::soundio_device_supports_format(self.device, format) == 1u8 }
    }

    pub fn supports_layout(&self, layout: &ChannelLayout) -> bool {
        unsafe { ffi::soundio_device_supports_layout(self.device, layout.layout) == 1u8 }
    }

    pub fn supports_sample_rate(&self, sample_rate: i32) -> bool {
        unsafe {
            ffi::soundio_device_supports_sample_rate(self.device, sample_rate as c_int) == 1u8
        }
    }

    pub fn nearest_sample_rate(&self, sample_rate: i32) -> i32 {
        unsafe { ffi::soundio_device_nearest_sample_rate(self.device, sample_rate) as i32 }
    }

    pub fn create_outstream(&self) -> Option<OutStream> {
        let stream_ptr = unsafe { ffi::soundio_outstream_create(self.device) };
        if stream_ptr.is_null() {
            None
        } else {
            Some(OutStream::new(stream_ptr))
        }
    }

    pub fn ref_count(&self) -> i32 {
        unsafe { (*self.device).ref_count as i32 }
    }
}
impl Display for Device {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let str_ptr = unsafe { (*self.device).name };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}
impl Drop for Device {
    fn drop(&mut self) {
        self.dec_ref()
    }
}
impl PartialEq for Device {
    fn eq(&self, other: &Self) -> bool {
        unsafe { ffi::soundio_device_equal(self.device, other.device) == 1u8 }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}
<commit_msg>Add `set_app_name` method<commit_after>use std::fmt::Display;
use std::os::raw::c_int;

use ffi;
use stream::OutStream;

pub type SioResult<T> = Result<T, ffi::SioError>;

pub struct SoundIo {
    context: *mut ffi::SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn channel_layout_builtin_count() -> i32 {
        let cnt = unsafe { ffi::soundio_channel_layout_builtin_count() };
        if cnt < 0 {
            panic!("Negative # of builtin channel layouts!")
        } else {
            cnt as i32
        }
    }

    pub fn connect(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self, backend: ffi::SioBackend) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::SioError::None => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt = unsafe { ffi::soundio_backend_count(self.context) } as i32;
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::SioBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::SioBackend::None => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn current_backend(&self) -> Option<ffi::SioBackend> {
        match unsafe { (*self.context).current_backend } {
            ffi::SioBackend::None => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::SioBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }

    pub fn input_device_count(&self) -> Option<i32> {
        let cnt = unsafe { ffi::soundio_input_device_count(self.context) };
        if cnt < 0 {
            None
        } else {
            Some(cnt as i32)
        }
    }

    pub fn output_device_count(&self) -> Option<i32> {
        let cnt = unsafe { ffi::soundio_output_device_count(self.context) };
        if cnt < 0 {
            None
        } else {
            Some(cnt as i32)
        }
    }

    pub fn get_input_device(&self, idx: i32) -> Option<Device> {
        let dev_ptr = unsafe { ffi::soundio_get_input_device(self.context, idx) };
        if dev_ptr.is_null() {
            None
        } else {
            Some(Device::new(dev_ptr))
        }
    }

    pub fn get_output_device(&self, idx: i32) -> Option<Device> {
        let dev_ptr = unsafe { ffi::soundio_get_output_device(self.context, idx) };
        if dev_ptr.is_null() {
            None
        } else {
            Some(Device::new(dev_ptr))
        }
    }

    pub fn default_input_device_index(&self) -> Option<i32> {
        match unsafe { ffi::soundio_default_input_device_index(self.context) } {
            -1 => None,
            idx @ _ => Some(idx as i32),
        }
    }

    pub fn default_output_device_index(&self) -> Option<i32> {
        match unsafe { ffi::soundio_default_output_device_index(self.context) } {
            -1 => None,
            idx @ _ => Some(idx as i32),
        }
    }

    /// Sets the application name that is shown in the
    /// system audio mixer and returns `true` if it could
    /// be set.
    /// The `name` must **not** contain a `:` character.
    ///
    /// TODO: Return a `Result` instead of `bool`?
    pub fn set_app_name<T: Into<String>>(&self, name: T) -> bool {
        let s = name.into();
        if s.contains(":") {
            return false;
        } else {
            match CString::new(s) {
                Ok(cstr) => {
                    unsafe { (*self.context).app_name = cstr.as_ptr() };
                    true
                }
                Err(_) => false,
            }
        }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[derive(Debug)]
pub struct ChannelLayout {
    layout: *const ffi::SoundIoChannelLayout,
}
impl ChannelLayout {
    pub fn new(raw_layout: *const ffi::SoundIoChannelLayout) -> Self {
        ChannelLayout { layout: raw_layout }
    }

    pub fn get_builtin(idx: i32) -> Option<Self> {
        if 0 <= idx && idx < SoundIo::channel_layout_builtin_count() {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_builtin(idx as c_int)
            }))
        } else {
            None
        }
    }

    pub fn get_default(channel_count: i32) -> Option<Self> {
        if channel_count < 0 {
            None
        } else {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_default(channel_count as i32)
            }))
        }
    }

    pub fn find_channel(&self, channel: ffi::SioChannelId) -> Option<i32> {
        match unsafe { ffi::soundio_channel_layout_find_channel(self.layout, channel) } {
            -1 => None,
            idx @ _ => Some(idx),
        }
    }

    pub fn detect_builtin(&mut self) -> bool {
        // This is a hack because of the transmute.
        unsafe {
            let mut_layout: *mut ffi::SoundIoChannelLayout = ::std::mem::transmute(self.layout);
            ffi::soundio_channel_layout_detect_builtin(mut_layout) == 1
        }
    }

    pub fn best_matching_channel_layout(preferred_layouts: &[ChannelLayout],
                                        available_layouts: &[ChannelLayout])
                                        -> Option<ChannelLayout> {
        // do some magic with the slices
        let raw_preferred_layouts: Vec<_> = preferred_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let raw_available_layouts: Vec<_> = available_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let layout_ptr = unsafe {
            ffi::soundio_best_matching_channel_layout(raw_preferred_layouts.as_ptr(),
                                                      preferred_layouts.len() as c_int,
                                                      raw_available_layouts.as_ptr(),
                                                      available_layouts.len() as c_int)
        };
        if layout_ptr.is_null() {
            None
        } else {
            Some(ChannelLayout::new(layout_ptr))
        }
    }

    pub fn channel_count(&self) -> i32 {
        unsafe { (*self.layout).channel_count as i32 }
    }
}
impl PartialEq for ChannelLayout {
    fn eq(&self, other: &Self) -> bool {
        unsafe { ffi::soundio_channel_layout_equal(self.layout, other.layout) == 1u8 }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}
impl Display for ChannelLayout {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let str_ptr = unsafe { (*self.layout).name };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}

#[derive(Debug)]
pub struct Device {
    device: *mut ffi::SoundIoDevice,
}
impl Device {
    pub fn new(dev_ptr: *mut ffi::SoundIoDevice) -> Self {
        Device { device: dev_ptr }
    }

    // ref is a keyword
    pub fn inc_ref(&self) {
        unsafe { ffi::soundio_device_ref(self.device) }
    }

    pub fn dec_ref(&self) {
        unsafe { ffi::soundio_device_unref(self.device) }
    }

    pub fn sort_channel_layouts(&self) {
        unsafe { ffi::soundio_device_sort_channel_layouts(self.device) }
    }

    pub fn supports_format(&self, format: ffi::SioFormat) -> bool {
        unsafe { ffi::soundio_device_supports_format(self.device, format) == 1u8 }
    }

    pub fn supports_layout(&self, layout: &ChannelLayout) -> bool {
        unsafe { ffi::soundio_device_supports_layout(self.device, layout.layout) == 1u8 }
    }

    pub fn supports_sample_rate(&self, sample_rate: i32) -> bool {
        unsafe {
            ffi::soundio_device_supports_sample_rate(self.device, sample_rate as c_int) == 1u8
        }
    }

    pub fn nearest_sample_rate(&self, sample_rate: i32) -> i32 {
        unsafe { ffi::soundio_device_nearest_sample_rate(self.device, sample_rate) as i32 }
    }

    pub fn create_outstream(&self) -> Option<OutStream> {
        let stream_ptr = unsafe { ffi::soundio_outstream_create(self.device) };
        if stream_ptr.is_null() {
            None
        } else {
            Some(OutStream::new(stream_ptr))
        }
    }

    pub fn ref_count(&self) -> i32 {
        unsafe { (*self.device).ref_count as i32 }
    }
}
impl Display for Device {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let str_ptr = unsafe { (*self.device).name };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}
impl Drop for Device {
    fn drop(&mut self) {
        self.dec_ref()
    }
}
impl PartialEq for Device {
    fn eq(&self, other: &Self) -> bool {
        unsafe { ffi::soundio_device_equal(self.device, other.device) == 1u8 }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}
<|endoftext|>


<commit_before>//! Experimental BLAS (Basic Linear Algebra Subprograms) integration
//!
//! ***Requires `features = "rblas"`***
//!
//! Depends on crate [`rblas`], ([docs]).
//!
//! [`rblas`]: https://crates.io/crates/rblas/
//! [docs]: http://mikkyang.github.io/rust-blas/doc/rblas/
//!
//! ```
//! extern crate rblas;
//! extern crate ndarray;
//!
//! use rblas::Gemv;
//! use rblas::attribute::Transpose;
//!
//! use ndarray::{arr1, arr2, Array};
//! use ndarray::blas::AsBlas;
//!
//! fn main() {
//!     // Gemv is the operation y = α a x + β y
//!     let alpha = 1.;
//!     let mut a = arr2(&[[1., 2., 3.],
//!                        [4., 5., 6.],
//!                        [7., 8., 9.]]);
//!     let x = [1., 0., 1.];
//!     let beta = 1.;
//!     let mut y = arr1(&[0., 0., 0.]);
//!
//!     Gemv::gemv(Transpose::NoTrans, &alpha, &a.blas(), &x[..],
//!                &beta, &mut y.blas());
//!
//!     assert_eq!(y, arr1(&[4., 10., 16.]));
//! }
//!
//! ```
//!
//! Use the methods in trait `AsBlas` to convert an array into a view that
//! implements rblas’ `Vector` or `Matrix` traits.
//!
//! Blas supports strided vectors but not matrices, so they will be copied into
//! c-contiguous layout automatically. Blas has its own error reporting system
//! and will not panic on errors (that I know), instead output its own error
//! conditions, for example on dimension mismatch in a matrix multiplication.
//!
extern crate rblas;

use std::os::raw::{c_int, c_uint};

use self::rblas::{
    Matrix,
    Vector,
};
use super::{
    ArrayBase,
    ArrayViewMut,
    Ix,
    ShapeError,
    Data,
    DataMut,
    DataOwned,
    Dimension,
};

/*
/// ***Requires `features = "rblas"`***
pub struct BlasArrayView<'a, A: 'a, D>(ArrayView<'a, A, D>);
impl<'a, A, D: Copy> Copy for BlasArrayView<'a, A, D> { }
impl<'a, A, D: Clone> Clone for BlasArrayView<'a, A, D> {
    fn clone(&self) -> Self {
        BlasArrayView(self.0.clone())
    }
}
*/

/// ***Requires `features = "rblas"`***
pub struct BlasArrayViewMut<'a, A: 'a, D>(ArrayViewMut<'a, A, D>);

impl<S, D> ArrayBase<S, D>
    where S: Data,
          D: Dimension
{
    fn size_check(&self) -> Result<(), ShapeError> {
        for &dim in self.shape() {
            if dim > (c_int::max_value() as c_uint) {
                return Err(ShapeError::DimensionTooLarge(
                    self.shape().to_vec().into_boxed_slice()));
            }
        }
        Ok(())
    }

    fn contiguous_check(&self) -> Result<(), ShapeError> {
        // FIXME: handle transposed
        if self.is_standard_layout() {
            Ok(())
        } else {
            Err(ShapeError::IncompatibleLayout)
        }
    }
}

/*
impl<'a, A, D> ArrayView<'a, A, D>
    where D: Dimension,
{
    /// ***Requires `features = "rblas"`***
    fn into_matrix(self) -> Result<BlasArrayView<'a, A, D>, ShapeError>
    {
        if self.dim.ndim() > 1 {
            try!(self.contiguous_check());
        }
        try!(self.size_check());
        Ok(BlasArrayView(self))
    }
}
*/

impl<'a, A, D> ArrayViewMut<'a, A, D>
    where D: Dimension,
{
    fn into_matrix_mut(self) -> Result<BlasArrayViewMut<'a, A, D>, ShapeError>
    {
        if self.dim.ndim() > 1 {
            try!(self.contiguous_check());
        }
        try!(self.size_check());
        Ok(BlasArrayViewMut(self))
    }
}

/// Convert an array into a blas friendly wrapper.
///
/// ***Requires `features = "rblas"`***
pub trait AsBlas {
    /// Return an array view implementing Vector (1D) or Matrix (2D)
    /// traits.
    ///
    /// Elements are copied if needed to produce a contiguous matrix.

    /// The result is always mutable, due to the requirement of having write
    /// access to update the layout either way. Breaks sharing if the array is
    /// an `Array`.
    ///
    /// **Errors:** Produces an error if any dimension is larger than `c_int::MAX`.
    fn blas_checked(&mut self) -> Result<BlasArrayViewMut, ShapeError>
        where S: DataOwned + DataMut,
              A: Clone;

    /// Equivalent to `.blas_checked().unwrap()`
    ///
    /// **Panics** if there was a an error in `blas_checked`.
    fn blas(&mut self) -> BlasArrayViewMut
        where S: DataOwned<Elem=A> + DataMut,
              A: Clone
    {
        self.blas_checked().unwrap()
    }
    /*

    /// Equivalent to `.blas_checked().unwrap()`, except elements
    /// are not copied to make the array contiguous: instead just
    /// dimensions and strides are adjusted, and elements end up in
    /// arbitrary location. Useful if the content of the array doesn't matter.
    ///
    /// **Panics** if there was a an error in `blas_checked`.
    fn blas_overwrite(&mut self) -> BlasArrayViewMut
        where S: DataMut;
        */
}

impl AsBlas for ArrayBase<S, D>
    where S: Data<Elem=A>,
          D: Dimension,
{
    fn blas_checked(&mut self) -> Result<BlasArrayViewMut, ShapeError>
        where S: DataOwned + DataMut,
              A: Clone,
    {
        try!(self.size_check());
        if self.dim.ndim() > 1 {
            self.ensure_standard_layout();
        }
        self.view_mut().into_matrix_mut()
    }

    /*
    fn blas_overwrite(&mut self) -> BlasArrayViewMut
        where S: DataMut,
    {
        self.size_check().unwrap();
        if self.dim.ndim() > 1 {
            self.force_standard_layout();
        }
        BlasArrayViewMut(self.view_mut())
    }
    */
}

/*
impl<'a, A> Vector for BlasArrayView<'a, A, Ix> {
    fn len(&self) -> c_int {
        self.0.len() as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr as *const _
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        panic!("BlasArrayView is not mutable");
    }

    // increment: stride
    fn inc(&self) -> c_int {
        self.0.strides as c_int
    }
}
*/

impl<'a, A> Vector for BlasArrayViewMut<'a, A, Ix> {
    fn len(&self) -> c_int {
        self.0.len() as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        self.0.ptr
    }

    // increment: stride
    fn inc(&self) -> c_int {
        self.0.strides as c_int
    }
}

/*
impl<'a, A> Matrix for BlasArrayView<'a, A, (Ix, Ix)> {
    fn rows(&self) -> c_int {
        self.0.dim().1 as c_int
    }

    fn cols(&self) -> c_int {
        self.0.dim().0 as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr as *const _
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        panic!("BlasArrayView is not mutable");
    }
}
*/

impl<'a, A> Matrix for BlasArrayViewMut<'a, A, (Ix, Ix)> {
    fn rows(&self) -> c_int {
        self.0.dim().1 as c_int
    }

    fn cols(&self) -> c_int {
        self.0.dim().0 as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr as *const _
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        self.0.ptr
    }
}
<commit_msg>Add doc for AsBlas impl<commit_after>//! Experimental BLAS (Basic Linear Algebra Subprograms) integration
//!
//! ***Requires `features = "rblas"`***
//!
//! Depends on crate [`rblas`], ([docs]).
//!
//! [`rblas`]: https://crates.io/crates/rblas/
//! [docs]: http://mikkyang.github.io/rust-blas/doc/rblas/
//!
//! ```
//! extern crate rblas;
//! extern crate ndarray;
//!
//! use rblas::Gemv;
//! use rblas::attribute::Transpose;
//!
//! use ndarray::{arr1, arr2, Array};
//! use ndarray::blas::AsBlas;
//!
//! fn main() {
//!     // Gemv is the operation y = α a x + β y
//!     let alpha = 1.;
//!     let mut a = arr2(&[[1., 2., 3.],
//!                        [4., 5., 6.],
//!                        [7., 8., 9.]]);
//!     let x = [1., 0., 1.];
//!     let beta = 1.;
//!     let mut y = arr1(&[0., 0., 0.]);
//!
//!     Gemv::gemv(Transpose::NoTrans, &alpha, &a.blas(), &x[..],
//!                &beta, &mut y.blas());
//!
//!     assert_eq!(y, arr1(&[4., 10., 16.]));
//! }
//!
//! ```
//!
//! Use the methods in trait `AsBlas` to convert an array into a view that
//! implements rblas’ `Vector` or `Matrix` traits.
//!
//! Blas supports strided vectors but not matrices, so they will be copied into
//! c-contiguous layout automatically. Blas has its own error reporting system
//! and will not panic on errors (that I know), instead output its own error
//! conditions, for example on dimension mismatch in a matrix multiplication.
//!
extern crate rblas;

use std::os::raw::{c_int, c_uint};

use self::rblas::{
    Matrix,
    Vector,
};
use super::{
    ArrayBase,
    ArrayViewMut,
    Ix,
    ShapeError,
    Data,
    DataMut,
    DataOwned,
    Dimension,
};

/*
/// ***Requires `features = "rblas"`***
pub struct BlasArrayView<'a, A: 'a, D>(ArrayView<'a, A, D>);
impl<'a, A, D: Copy> Copy for BlasArrayView<'a, A, D> { }
impl<'a, A, D: Clone> Clone for BlasArrayView<'a, A, D> {
    fn clone(&self) -> Self {
        BlasArrayView(self.0.clone())
    }
}
*/

/// ***Requires `features = "rblas"`***
pub struct BlasArrayViewMut<'a, A: 'a, D>(ArrayViewMut<'a, A, D>);

impl<S, D> ArrayBase<S, D>
    where S: Data,
          D: Dimension
{
    fn size_check(&self) -> Result<(), ShapeError> {
        for &dim in self.shape() {
            if dim > (c_int::max_value() as c_uint) {
                return Err(ShapeError::DimensionTooLarge(
                    self.shape().to_vec().into_boxed_slice()));
            }
        }
        Ok(())
    }

    fn contiguous_check(&self) -> Result<(), ShapeError> {
        // FIXME: handle transposed
        if self.is_standard_layout() {
            Ok(())
        } else {
            Err(ShapeError::IncompatibleLayout)
        }
    }
}

/*
impl<'a, A, D> ArrayView<'a, A, D>
    where D: Dimension,
{
    /// ***Requires `features = "rblas"`***
    fn into_matrix(self) -> Result<BlasArrayView<'a, A, D>, ShapeError>
    {
        if self.dim.ndim() > 1 {
            try!(self.contiguous_check());
        }
        try!(self.size_check());
        Ok(BlasArrayView(self))
    }
}
*/

impl<'a, A, D> ArrayViewMut<'a, A, D>
    where D: Dimension,
{
    fn into_matrix_mut(self) -> Result<BlasArrayViewMut<'a, A, D>, ShapeError>
    {
        if self.dim.ndim() > 1 {
            try!(self.contiguous_check());
        }
        try!(self.size_check());
        Ok(BlasArrayViewMut(self))
    }
}

/// Convert an array into a blas friendly wrapper.
///
/// ***Requires `features = "rblas"`***
pub trait AsBlas {
    /// Return an array view implementing Vector (1D) or Matrix (2D)
    /// traits.
    ///
    /// Elements are copied if needed to produce a contiguous matrix.

    /// The result is always mutable, due to the requirement of having write
    /// access to update the layout either way. Breaks sharing if the array is
    /// an `Array`.
    ///
    /// **Errors:** Produces an error if any dimension is larger than `c_int::MAX`.
    fn blas_checked(&mut self) -> Result<BlasArrayViewMut, ShapeError>
        where S: DataOwned + DataMut,
              A: Clone;

    /// Equivalent to `.blas_checked().unwrap()`
    ///
    /// **Panics** if there was a an error in `blas_checked`.
    fn blas(&mut self) -> BlasArrayViewMut
        where S: DataOwned<Elem=A> + DataMut,
              A: Clone
    {
        self.blas_checked().unwrap()
    }
    /*

    /// Equivalent to `.blas_checked().unwrap()`, except elements
    /// are not copied to make the array contiguous: instead just
    /// dimensions and strides are adjusted, and elements end up in
    /// arbitrary location. Useful if the content of the array doesn't matter.
    ///
    /// **Panics** if there was a an error in `blas_checked`.
    fn blas_overwrite(&mut self) -> BlasArrayViewMut
        where S: DataMut;
        */
}

/// ***Requires `features = "rblas"`***
impl AsBlas for ArrayBase<S, D>
    where S: Data<Elem=A>,
          D: Dimension,
{
    fn blas_checked(&mut self) -> Result<BlasArrayViewMut, ShapeError>
        where S: DataOwned + DataMut,
              A: Clone,
    {
        try!(self.size_check());
        if self.dim.ndim() > 1 {
            self.ensure_standard_layout();
        }
        self.view_mut().into_matrix_mut()
    }

    /*
    fn blas_overwrite(&mut self) -> BlasArrayViewMut
        where S: DataMut,
    {
        self.size_check().unwrap();
        if self.dim.ndim() > 1 {
            self.force_standard_layout();
        }
        BlasArrayViewMut(self.view_mut())
    }
    */
}

/*
impl<'a, A> Vector for BlasArrayView<'a, A, Ix> {
    fn len(&self) -> c_int {
        self.0.len() as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr as *const _
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        panic!("BlasArrayView is not mutable");
    }

    // increment: stride
    fn inc(&self) -> c_int {
        self.0.strides as c_int
    }
}
*/

impl<'a, A> Vector for BlasArrayViewMut<'a, A, Ix> {
    fn len(&self) -> c_int {
        self.0.len() as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        self.0.ptr
    }

    // increment: stride
    fn inc(&self) -> c_int {
        self.0.strides as c_int
    }
}

/*
impl<'a, A> Matrix for BlasArrayView<'a, A, (Ix, Ix)> {
    fn rows(&self) -> c_int {
        self.0.dim().1 as c_int
    }

    fn cols(&self) -> c_int {
        self.0.dim().0 as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr as *const _
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        panic!("BlasArrayView is not mutable");
    }
}
*/

impl<'a, A> Matrix for BlasArrayViewMut<'a, A, (Ix, Ix)> {
    fn rows(&self) -> c_int {
        self.0.dim().1 as c_int
    }

    fn cols(&self) -> c_int {
        self.0.dim().0 as c_int
    }

    fn as_ptr(&self) -> *const A {
        self.0.ptr as *const _
    }

    fn as_mut_ptr(&mut self) -> *mut A {
        self.0.ptr
    }
}
<|endoftext|>


<commit_before>use std::{env, ffi::OsString, fs, path::Path};

use binary::{
    async_trait::async_trait,
    binaries_dir, binary_clone_box,
    eyre::{bail, Result},
    semver_versions_sorted, Binary, BinaryTrait,
};

/// A `BinaryTrait` for `asdf`
///
/// This sets the `$ASDF_DATA_DIR` to be the same as the Stencila `binaries` directory.
/// Given that `asdf` uses the same structure for this directory as Stencila, it means that
/// executables that are installed by `asdf` have the same expected location as those installed
/// by Stencila.
pub struct AsdfBinary;

#[async_trait]
impl BinaryTrait for AsdfBinary {
    fn spec(&self) -> Binary {
        Binary::new("asdf", &[], &[])
    }

    binary_clone_box!();

    async fn versions(&self, _os: &str) -> Result<Vec<String>> {
        self.versions_github_releases("asdf-vm", "asdf")
            .await
            .map(semver_versions_sorted)
    }

    fn run_env(&self, version: Option<String>) -> Vec<(OsString, OsString)> {
        if let Ok(dir) = self.dir(version, false) {
            let binaries_dir = binaries_dir();
            if let Ok(..) = dir.strip_prefix(&binaries_dir) {
                let asdf_config_file = dir.join(".asdfrc").into_os_string();
                let asdf_dir = dir.into_os_string();
                let asdf_data_dir = binaries_dir.into_os_string();
                let path = OsString::from(env::var("PATH").unwrap_or_default());
                let path = env::join_paths(&[asdf_dir.clone(), path.clone()]).unwrap_or(path);
                return vec![
                    ("ASDF_CONFIG_FILE".into(), asdf_config_file),
                    ("ASDF_DIR".into(), asdf_dir),
                    ("ASDF_DATA_DIR".into(), asdf_data_dir),
                    ("PATH".into(), path),
                ];
            }
        }
        Vec::new()
    }

    async fn install_version(
        &self,
        version: &str,
        dest: &Path,
        os: &str,
        _arch: &str,
    ) -> Result<()> {
        if os == "windows" {
            bail!("`asdf` can not be install on Windows")
        }

        let url = format!(
            "https://github.com/asdf-vm/asdf/archive/refs/tags/v{version}.tar.gz",
            version = version
        );
        let filename = format!("asdf-v{version}.tar.gz", version = version);
        let archive = self.download(&url, Some(filename), None).await?;

        self.extract(&archive, 1, dest)?;
        self.executables(dest, &["bin/asdf"])?;

        // TODO: use a setting to determine the keep downloads policy for both Stencila and asdf
        fs::write(dest.join(".asdfrc"), "always_keep_download = yes\n")?;

        Ok(())
    }
}

impl AsdfBinary {
    /// List all versions for an `asdf` package
    pub async fn list_all(package: &str) -> Result<Vec<String>> {
        let asdf = AsdfBinary {}.require(None, true).await?;
        asdf.run(&["plugin", "add", package]).await?;
        let output = asdf.run(&["list", "all", package]).await?;

        let versions: Vec<String> = std::str::from_utf8(&output.stdout)?
            .lines()
            .map(String::from)
            .collect();

        Ok(versions)
    }

    /// Install a version for an `asdf` package
    ///
    /// Calls `uninstall` first because even with an empty directory it
    /// will consider it is already installed and do nothing.
    pub async fn install(package: &str, version: &str) -> Result<()> {
        let asdf = AsdfBinary {}.require(None, true).await?;
        asdf.run(&["plugin", "add", package]).await?;
        asdf.run(&["uninstall", package, version]).await?;
        asdf.run(&["install", package, version]).await?;
        Ok(())
    }
}
<commit_msg>fix(ASDF binary): Use new method<commit_after>use std::{env, ffi::OsString, fs, path::Path};

use binary::{
    async_trait::async_trait,
    binaries_dir, binary_clone_box,
    eyre::{bail, Result},
    Binary, BinaryTrait,
};

/// A `BinaryTrait` for `asdf`
///
/// This sets the `$ASDF_DATA_DIR` to be the same as the Stencila `binaries` directory.
/// Given that `asdf` uses the same structure for this directory as Stencila, it means that
/// executables that are installed by `asdf` have the same expected location as those installed
/// by Stencila.
pub struct AsdfBinary;

#[async_trait]
impl BinaryTrait for AsdfBinary {
    fn spec(&self) -> Binary {
        Binary::new("asdf", &[], &[])
    }

    binary_clone_box!();

    async fn versions(&self, _os: &str) -> Result<Vec<String>> {
        self.versions_github_releases("asdf-vm", "asdf")
            .await
            .map(|versions| self.semver_versions_sorted(versions))
    }

    fn run_env(&self, version: Option<String>) -> Vec<(OsString, OsString)> {
        if let Ok(dir) = self.dir(version, false) {
            let binaries_dir = binaries_dir();
            if let Ok(..) = dir.strip_prefix(&binaries_dir) {
                let asdf_config_file = dir.join(".asdfrc").into_os_string();
                let asdf_dir = dir.into_os_string();
                let asdf_data_dir = binaries_dir.into_os_string();
                let path = OsString::from(env::var("PATH").unwrap_or_default());
                let path = env::join_paths(&[asdf_dir.clone(), path.clone()]).unwrap_or(path);
                return vec![
                    ("ASDF_CONFIG_FILE".into(), asdf_config_file),
                    ("ASDF_DIR".into(), asdf_dir),
                    ("ASDF_DATA_DIR".into(), asdf_data_dir),
                    ("PATH".into(), path),
                ];
            }
        }
        Vec::new()
    }

    async fn install_version(
        &self,
        version: &str,
        dest: &Path,
        os: &str,
        _arch: &str,
    ) -> Result<()> {
        if os == "windows" {
            bail!("`asdf` can not be install on Windows")
        }

        let url = format!(
            "https://github.com/asdf-vm/asdf/archive/refs/tags/v{version}.tar.gz",
            version = version
        );
        let filename = format!("asdf-v{version}.tar.gz", version = version);
        let archive = self.download(&url, Some(filename), None).await?;

        self.extract(&archive, 1, dest)?;
        self.executables(dest, &["bin/asdf"])?;

        // TODO: use a setting to determine the keep downloads policy for both Stencila and asdf
        fs::write(dest.join(".asdfrc"), "always_keep_download = yes\n")?;

        Ok(())
    }
}

impl AsdfBinary {
    /// List all versions for an `asdf` package
    pub async fn list_all(package: &str) -> Result<Vec<String>> {
        let asdf = AsdfBinary {}.require(None, true).await?;
        asdf.run(&["plugin", "add", package]).await?;
        let output = asdf.run(&["list", "all", package]).await?;

        let versions: Vec<String> = std::str::from_utf8(&output.stdout)?
            .lines()
            .map(String::from)
            .collect();

        Ok(versions)
    }

    /// Install a version for an `asdf` package
    ///
    /// Calls `uninstall` first because even with an empty directory it
    /// will consider it is already installed and do nothing.
    pub async fn install(package: &str, version: &str) -> Result<()> {
        let asdf = AsdfBinary {}.require(None, true).await?;
        asdf.run(&["plugin", "add", package]).await?;
        asdf.run(&["uninstall", package, version]).await?;
        asdf.run(&["install", package, version]).await?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(tool_lints)]

use std::env;

#[macro_export]
macro_rules! get_version_info {
    () => {{
        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
        let crate_name = String::from(env!("CARGO_PKG_NAME"));

        let host_compiler = $crate::get_channel();
        let commit_hash = option_env!("GIT_HASH").map(|s| s.to_string());
        let commit_date = option_env!("COMMIT_DATE").map(|s| s.to_string());

        VersionInfo {
            major,
            minor,
            patch,
            host_compiler,
            commit_hash,
            commit_date,
            crate_name,
        }
    }};
}

// some code taken and adapted from RLS and cargo
pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u16,
    pub host_compiler: Option<String>,
    pub commit_hash: Option<String>,
    pub commit_date: Option<String>,
    pub crate_name: String,
}

impl std::fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self.commit_hash {
            Some(_) => {
                write!(
                    f,
                    "{} {}.{}.{} ({} {})",
                    self.crate_name,
                    self.major,
                    self.minor,
                    self.patch,
                    self.commit_hash.clone().unwrap_or_default().trim(),
                    self.commit_date.clone().unwrap_or_default().trim(),
                )?;
            },
            None => {
                write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
            },
        };
        Ok(())
    }
}

pub fn get_channel() -> Option<String> {
    if let Ok(channel) = env::var("CFG_RELEASE_CHANNEL") {
        Some(channel)
    } else {
        // we could ask ${RUSTC} -Vv and do some parsing and find out
        Some(String::from("nightly"))
    }
}

pub fn get_commit_hash() -> Option<String> {
    std::process::Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

pub fn get_commit_date() -> Option<String> {
    std::process::Command::new("git")
        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

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

    #[test]
    fn test_struct_local() {
        let vi = get_version_info!();
        assert_eq!(vi.major, 0);
        assert_eq!(vi.minor, 1);
        assert_eq!(vi.patch, 0);
        assert_eq!(vi.crate_name, "rustc_tools_util");
        // hard to make positive tests for these since they will always change
        assert!(vi.commit_hash.is_none());
        assert!(vi.commit_date.is_none());
    }

    #[test]
    fn test_display_local() {
        let vi = get_version_info!();
        let fmt = format!("{}", vi);
        assert_eq!(fmt, "rustc_tools_util 0.1.0");
    }

}
<commit_msg>impl std::fmt::Debug for VersionInfo<commit_after>#![feature(test)]
#![feature(tool_lints)]

use std::env;

#[macro_export]
macro_rules! get_version_info {
    () => {{
        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
        let crate_name = String::from(env!("CARGO_PKG_NAME"));

        let host_compiler = $crate::get_channel();
        let commit_hash = option_env!("GIT_HASH").map(|s| s.to_string());
        let commit_date = option_env!("COMMIT_DATE").map(|s| s.to_string());

        VersionInfo {
            major,
            minor,
            patch,
            host_compiler,
            commit_hash,
            commit_date,
            crate_name,
        }
    }};
}

// some code taken and adapted from RLS and cargo
pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u16,
    pub host_compiler: Option<String>,
    pub commit_hash: Option<String>,
    pub commit_date: Option<String>,
    pub crate_name: String,
}

impl std::fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self.commit_hash {
            Some(_) => {
                write!(
                    f,
                    "{} {}.{}.{} ({} {})",
                    self.crate_name,
                    self.major,
                    self.minor,
                    self.patch,
                    self.commit_hash.clone().unwrap_or_default().trim(),
                    self.commit_date.clone().unwrap_or_default().trim(),
                )?;
            },
            None => {
                write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
            },
        };
        Ok(())
    }
}

impl std::fmt::Debug for VersionInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}",
            self.crate_name, self.major, self.minor, self.patch,
        )?;
        match self.commit_hash {
            Some(_) => {
                write!(
                    f,
                    ", commit_hash: \"{}\", commit_date: \"{}\" }}",
                    self.commit_hash.clone().unwrap_or_default().trim(),
                    self.commit_date.clone().unwrap_or_default().trim()
                )?;
            },
            None => {
                write!(f, " }}")?;
            },
        }
        Ok(())
    }
}

pub fn get_channel() -> Option<String> {
    if let Ok(channel) = env::var("CFG_RELEASE_CHANNEL") {
        Some(channel)
    } else {
        // we could ask ${RUSTC} -Vv and do some parsing and find out
        Some(String::from("nightly"))
    }
}

pub fn get_commit_hash() -> Option<String> {
    std::process::Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

pub fn get_commit_date() -> Option<String> {
    std::process::Command::new("git")
        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
        .output()
        .ok()
        .and_then(|r| String::from_utf8(r.stdout).ok())
}

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

    #[test]
    fn test_struct_local() {
        let vi = get_version_info!();
        assert_eq!(vi.major, 0);
        assert_eq!(vi.minor, 1);
        assert_eq!(vi.patch, 0);
        assert_eq!(vi.crate_name, "rustc_tools_util");
        // hard to make positive tests for these since they will always change
        assert!(vi.commit_hash.is_none());
        assert!(vi.commit_date.is_none());
    }

    #[test]
    fn test_display_local() {
        let vi = get_version_info!();
        assert_eq!(vi.to_string(), "rustc_tools_util 0.1.0");
    }

    #[test]
    fn test_debug_local() {
        let vi = get_version_info!();
        let s = format!("{:?}", vi);
        assert_eq!(
            s,
            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 1, patch: 0 }"
        );
    }

}
<|endoftext|>


<commit_before>#[link(name = "simplify", vers = "0.0.5")];
extern mod extra;
use extra::json::*;
use extra::treemap::TreeSet;
use std::vec;
pub struct Point {
	x: float,
	y: float
}
impl ToJson for Point {
    fn to_json(&self) -> Json { List(~[self.x.to_json(),self.y.to_json()]) }
}
impl Eq for Point {
    fn eq(&self, other: &Point) -> bool { other.x == self.x && other.y == self.y }
    fn ne(&self, other: &Point) -> bool { other.x != self.x || other.y != self.y }
}
impl Sub<Point,Point> for Point {
    #[inline]
    fn sub(&self, other: &Point) -> Point { Point {x:self.x-other.x,y:self.y-other.y} }
}
impl Add<Point,Point> for Point {
    #[inline]
    fn add(&self, other: &Point) -> Point { Point { x:self.x+other.x,y:self.y+other.y }}
}
impl Mul<Point,Point> for Point {
    #[inline]
    fn mul(&self, other: &Point) -> Point { Point { x:self.x*other.x,y:self.y*other.y }}
}

impl Point {
    fn sum(self) -> float { self.x+self.y }
    fn sqsum(self) -> float { self.x * self.x + self.y * self.y}
    fn sub(self, other: float) -> Point { Point { x:self.x - other , y:self.y - other }}
    fn mul(self, other: float) -> Point { Point { x:self.x * other, y:self.y * other }}
    fn add(self, other: float) -> Point {  Point {x:self.x + other, y:self.y + other }}
}

fn calcStuff(p:Point,p1:Point,d1:Point)->float {
	let top : float = ((p - p1) * d1).sum();
	let bottom : float =  d1.sqsum();
	match bottom{
		0.0=>0.0,
		_=>top/bottom
	}
}
fn getSquareSegmentDistance(p: Point, p1: Point, p2: Point) -> float {
	let d1 : Point = p2-p1;
	let d2 : Point = match d1{
		Point {x:0.0,_} | Point {y:0.0,_}=> {p1}
		_=>{
			let t : float = calcStuff(p,p1,d1);
			match t {
				tt if tt>1.0=>p2,
				tt if tt>0.0=> d1.mul(tt)+p1,
				_=>p1
			}
		}
	};
	let d4 : Point = p-d2;
	d4.sqsum()
}

fn simplifyRadialDistance(points:~[Point], sqTolerance:float) -> ~[Point]{
    let mut it = points.iter();
    it.next();
	let mut prevPoint : Point = points[0u];
	let mut newPoints : ~[Point] = ~[prevPoint];
	let &last = points.last();
	for &point in it{
	    if (point - prevPoint).sqsum() > sqTolerance {
			newPoints.push(point);
			prevPoint = point;
		}
	}
	if (prevPoint!= last) {
		newPoints.push(last);
	}
	newPoints
}
fn simplifyDouglasPeucker(points : ~[Point], tolerance : float) -> ~[Point]{
	let len : uint = points.len();
	let mut markers = TreeSet::new();
	let mut first : uint = 0u;
	let mut last : uint = len - 1u;
	let mut firstStack : ~[uint] = vec:: with_capacity(len);
	let mut lastStack : ~[uint] = vec:: with_capacity(len);
	markers.insert(first);
	markers.insert(last);
	let mut index : uint = 0;
	loop {
		let mut maxSqDist : float = 0.0f;
		let mut i : uint = first + 1u;
		while (i < last) {

			let sqDist :float  = getSquareSegmentDistance(
				points[i],
				points[first],
				points[last]
			);
			if (sqDist > maxSqDist) {
				index = i;
				maxSqDist = sqDist;
			}
			i += 1;
		}
		if (maxSqDist > tolerance) {
			markers.insert(index);
			firstStack.push(first);
			lastStack.push(index);
			firstStack.push(index);
			lastStack.push(last);
		}
		if(lastStack.len()>0u){
			first = firstStack.pop();
			last = lastStack.pop();
		}else{
			break;
		};
	};
    vec::from_fn(markers.len(),|k| points[k])
}

pub fn simplify(points : ~[Point], sqTolerance : float, hq:bool) -> ~[Point]{
	let tolerance : float = sqTolerance*sqTolerance;
	let pts:~[Point]=match hq {
		true=>points,
		_=>simplifyRadialDistance(points,tolerance)
	};
	simplifyDouglasPeucker(pts,tolerance)
}
<commit_msg>use pars<commit_after>#[link(name = "simplify", vers = "0.0.5")];
extern mod extra;
use extra::json::*;
use extra::treemap::TreeSet;
use std::vec;
pub struct Point {
	x: float,
	y: float
}
impl ToJson for Point {
    fn to_json(&self) -> Json { List(~[self.x.to_json(),self.y.to_json()]) }
}
impl Eq for Point {
    fn eq(&self, other: &Point) -> bool { other.x == self.x && other.y == self.y }
    fn ne(&self, other: &Point) -> bool { other.x != self.x || other.y != self.y }
}
impl Sub<Point,Point> for Point {
    #[inline]
    fn sub(&self, other: &Point) -> Point { Point {x:self.x-other.x,y:self.y-other.y} }
}
impl Add<Point,Point> for Point {
    #[inline]
    fn add(&self, other: &Point) -> Point { Point { x:self.x+other.x,y:self.y+other.y }}
}
impl Mul<Point,Point> for Point {
    #[inline]
    fn mul(&self, other: &Point) -> Point { Point { x:self.x*other.x,y:self.y*other.y }}
}

impl Point {
    fn sum(self) -> float { self.x+self.y }
    fn sqsum(self) -> float { self.x * self.x + self.y * self.y}
    fn sub(self, other: float) -> Point { Point { x:self.x - other , y:self.y - other }}
    fn mul(self, other: float) -> Point { Point { x:self.x * other, y:self.y * other }}
    fn add(self, other: float) -> Point {  Point {x:self.x + other, y:self.y + other }}
}
struct Pair(uint,uint);
impl Pair {
fn first(self)-> uint {
        match self {
            Pair(l,_)=>l
        }
    }
    fn last(self)-> uint {
        match self {
            Pair(_,l)=>l
        }
    }
}
fn calcStuff(p:Point,p1:Point,d1:Point)->float {
	let top : float = ((p - p1) * d1).sum();
	let bottom : float =  d1.sqsum();
	match bottom{
		0.0=>0.0,
		_=>top/bottom
	}
}
fn getSquareSegmentDistance(p: Point, p1: Point, p2: Point) -> float {
	let d1 : Point = p2-p1;
	let d2 : Point = match d1{
		Point {x:0.0,_} | Point {y:0.0,_}=> {p1}
		_=>{
			let t : float = calcStuff(p,p1,d1);
			match t {
				tt if tt>1.0=>p2,
				tt if tt>0.0=> d1.mul(tt)+p1,
				_=>p1
			}
		}
	};
	let d4 : Point = p-d2;
	d4.sqsum()
}

fn simplifyRadialDistance(points:~[Point], sqTolerance:float) -> ~[Point]{
    let mut it = points.iter();
    it.next();
	let mut prevPoint : Point = points[0u];
	let mut newPoints : ~[Point] = ~[prevPoint];
	let &last = points.last();
	for &point in it{
	    if (point - prevPoint).sqsum() > sqTolerance {
			newPoints.push(point);
			prevPoint = point;
		}
	}
	if (prevPoint!= last) {
		newPoints.push(last);
	}
	newPoints
}

fn simplifyDouglasPeucker(points : ~[Point], tolerance : float) -> ~[Point]{
	let len : uint = points.len();
	let mut markers = TreeSet::new();
	let mut pair = Pair(0u,len-1u);
	let mut stack : ~[Pair] = ~[];
	markers.insert(0u);
	markers.insert(len-1u);
	let mut index : uint = 0;

	loop{
			    let first = pair.first();
	    let last = pair.last();
		let mut maxSqDist : float = 0.0f;
		let mut i : uint = first + 1u;
		while (i < last) {

			let sqDist :float  = getSquareSegmentDistance(
				points[i],
				points[first],
				points[last]
			);
			if (sqDist > maxSqDist) {
				index = i;
				maxSqDist = sqDist;
			}
			i += 1;
		}
		if (maxSqDist > tolerance) {
			markers.insert(index);
			stack.push(Pair(first,index));
			stack.push(Pair(index,last));
		}
		match stack.pop_opt() {
		    Some(p)=>{
		        pair = p;
		    }
		    None=>break
		}
	};
    vec::from_fn(markers.len(),|k| points[k])
}

pub fn simplify(points : ~[Point], sqTolerance : float, hq:bool) -> ~[Point]{
	let tolerance : float = sqTolerance*sqTolerance;
	let pts:~[Point]=match hq {
		true=>points,
		_=>simplifyRadialDistance(points,tolerance)
	};
	simplifyDouglasPeucker(pts,tolerance)
}
<|endoftext|>


<commit_before>//! Graph traits for associated data and graph construction.

use Graph;
use ::{
    EdgeType,
};
use graph::IndexType;
use visit::{
    Data,
    NodeCount,
    NodeIndexable,
};

trait_template!{
    /// Access node and edge weights (associated data).
pub trait DataMap : Data {
    @section self_ref
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight>;
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight>;
}
}

DataMap!{delegate_impl []}
DataMap!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}

trait_template! {
    /// Access node and edge weights mutably.
pub trait DataMapMut : DataMap {
    @section self_mut
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight>;
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight>;
}
}

DataMapMut!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}

/// A graph that can be extended with further nodes and edges
pub trait Build : Data + NodeCount {
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId;
    /// Add a new edge. If parallel edges (duplicate) are not allowed and
    /// the edge already exists, return `None`.
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId> {
        Some(self.update_edge(a, b, weight))
    }
    /// Add or update the edge from `a` to `b`. Return the id of the affected
    /// edge.
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId;
}

/// A graph that can be created
pub trait Create : Build + DataMapMut + Default {
    fn with_capacity(nodes: usize, edges: usize) -> Self;
}

impl<N, E, Ty, Ix> Data for Graph<N, E, Ty, Ix>
    where Ix: IndexType
{
    type NodeWeight = N;
    type EdgeWeight = E;
}

impl<N, E, Ty, Ix> DataMap for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        self.node_weight(id)
    }
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.edge_weight(id)
    }
}

impl<N, E, Ty, Ix> DataMapMut for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
        self.node_weight_mut(id)
    }
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
        self.edge_weight_mut(id)
    }
}

impl<N, E, Ty, Ix> Build for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        Some(self.add_edge(a, b, weight))
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.update_edge(a, b, weight)
    }
}

impl<N, E, Ty, Ix> Create for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

/// A graph element
pub enum Element<N, E> {
    Node(N),
    Edge(usize, usize, E),
}

/// Create a graph from an iterator of elements.
pub trait FromElements : Create {
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        let mut gr = Self::with_capacity(0, 0);
        // usize -> NodeId map
        let mut map = Vec::new();
        for element in iterable {
            match element {
                Element::Node(w) => {
                    map.push(gr.add_node(w));
                }
                Element::Edge(a, b, w) => {
                    gr.add_edge(map[a], map[b], w);
                }
            }
        }
        gr
    }

}

fn from_elements_indexable<G, I>(iterable: I) -> G
    where G: Create + NodeIndexable,
          I: IntoIterator<Item=Element<G::NodeWeight, G::EdgeWeight>>,
{
    let mut gr = G::with_capacity(0, 0);
    let map = |gr: &G, i| gr.from_index(i);
    for element in iterable {
        match element {
            Element::Node(w) => {
                gr.add_node(w);
            }
            Element::Edge(a, b, w) => {
                let from = map(&gr, a);
                let to = map(&gr, b);
                gr.add_edge(from, to, w);
            }
        }
    }
    gr
}

impl<N, E, Ty, Ix> FromElements for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}
<commit_msg>DataMut/DataMapMut for Reversed<commit_after>//! Graph traits for associated data and graph construction.

use Graph;
use ::{
    EdgeType,
};
use graph::IndexType;
use visit::{
    Data,
    NodeCount,
    NodeIndexable,
    Reversed,
};

trait_template!{
    /// Access node and edge weights (associated data).
pub trait DataMap : Data {
    @section self_ref
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight>;
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight>;
}
}

macro_rules! access0 {
    ($e:expr) => ($e.0);
}

DataMap!{delegate_impl []}
DataMap!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMap!{delegate_impl [[G], G, Reversed<G>, access0]}

trait_template! {
    /// Access node and edge weights mutably.
pub trait DataMapMut : DataMap {
    @section self_mut
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight>;
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight>;
}
}

DataMapMut!{delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMapMut!{delegate_impl [[G], G, Reversed<G>, access0]}

/// A graph that can be extended with further nodes and edges
pub trait Build : Data + NodeCount {
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId;
    /// Add a new edge. If parallel edges (duplicate) are not allowed and
    /// the edge already exists, return `None`.
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId> {
        Some(self.update_edge(a, b, weight))
    }
    /// Add or update the edge from `a` to `b`. Return the id of the affected
    /// edge.
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId;
}

/// A graph that can be created
pub trait Create : Build + DataMapMut + Default {
    fn with_capacity(nodes: usize, edges: usize) -> Self;
}

impl<N, E, Ty, Ix> Data for Graph<N, E, Ty, Ix>
    where Ix: IndexType
{
    type NodeWeight = N;
    type EdgeWeight = E;
}

impl<N, E, Ty, Ix> DataMap for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        self.node_weight(id)
    }
    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.edge_weight(id)
    }
}

impl<N, E, Ty, Ix> DataMapMut for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType
{
    fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
        self.node_weight_mut(id)
    }
    fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
        self.edge_weight_mut(id)
    }
}

impl<N, E, Ty, Ix> Build for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
        self.add_node(weight)
    }
    fn add_edge(&mut self,
                a: Self::NodeId,
                b: Self::NodeId,
                weight: Self::EdgeWeight) -> Option<Self::EdgeId>
    {
        Some(self.add_edge(a, b, weight))
    }
    fn update_edge(&mut self,
                   a: Self::NodeId,
                   b: Self::NodeId,
                   weight: Self::EdgeWeight) -> Self::EdgeId
    {
        self.update_edge(a, b, weight)
    }
}

impl<N, E, Ty, Ix> Create for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn with_capacity(nodes: usize, edges: usize) -> Self {
        Self::with_capacity(nodes, edges)
    }
}

/// A graph element
pub enum Element<N, E> {
    Node(N),
    Edge(usize, usize, E),
}

/// Create a graph from an iterator of elements.
pub trait FromElements : Create {
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        let mut gr = Self::with_capacity(0, 0);
        // usize -> NodeId map
        let mut map = Vec::new();
        for element in iterable {
            match element {
                Element::Node(w) => {
                    map.push(gr.add_node(w));
                }
                Element::Edge(a, b, w) => {
                    gr.add_edge(map[a], map[b], w);
                }
            }
        }
        gr
    }

}

fn from_elements_indexable<G, I>(iterable: I) -> G
    where G: Create + NodeIndexable,
          I: IntoIterator<Item=Element<G::NodeWeight, G::EdgeWeight>>,
{
    let mut gr = G::with_capacity(0, 0);
    let map = |gr: &G, i| gr.from_index(i);
    for element in iterable {
        match element {
            Element::Node(w) => {
                gr.add_node(w);
            }
            Element::Edge(a, b, w) => {
                let from = map(&gr, a);
                let to = map(&gr, b);
                gr.add_edge(from, to, w);
            }
        }
    }
    gr
}

impl<N, E, Ty, Ix> FromElements for Graph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn from_elements<I>(iterable: I) -> Self
        where Self: Sized,
              I: IntoIterator<Item=Element<Self::NodeWeight, Self::EdgeWeight>>,
    {
        from_elements_indexable(iterable)
    }
}
<|endoftext|>