<commit_before>
use graphics;
use graphics::*;
use Gl = piston::gl::Gl;
use settings;
use spring::Spring;
use bar::Bar;
use player::Player;
use shark;
use shark::Shark;

pub enum ObjectData {
    PlayerData(Player),
    SharkData(Shark),
    BarData(Bar),
}

/// All objects are of same kind.
/// Makes it easier to write game logic.
pub struct Object {
    pub pos: [f64, ..2],
    pub vel: [f64, ..2],
    pub radius: f64,
    pub test_color: [f32, ..4],
    pub springs: Vec<Spring>,
    pub data: ObjectData,
}

impl Object {
    pub fn player(pos: [f64, ..2], test_color: [f32, ..4], blood: f64) -> Object {
        Object {
            pos: pos,
            vel: [0.0, 0.0],
            radius: settings::PLAYER_RADIUS,
            test_color: test_color,
            springs: Vec::new(),
            data: PlayerData(Player { blood: blood }),
        }
    }

    pub fn shark(
        pos: [f64, ..2],
        settings: settings::SharkSettings
    ) -> Object {

        Object {
            pos: pos,
            vel: [0.0, 0.0],
            radius: settings.radius,
            test_color: settings.test_color,
            springs: Vec::new(),
            data: SharkData(Shark {
                sensor_distance: settings.sensor_distance,
                state: settings.initial_state,
                bite_damage: settings.bite_damage,
                attack_distance: settings.attack_distance,
                wait_seconds_before_initial_attack: settings.wait_seconds_before_initial_attack,
                wait_seconds_before_repeat_attack: settings.wait_seconds_before_repeat_attack,
            }),
        }
    }

    pub fn bar(
        pos: [f64, ..2],
        text: &'static str,
        text_color: [f32, ..4],
        background_color: [f32, ..4],
        bar_color: [f32, ..4],
        value: f64
    ) -> Object {

       Object {
            pos: pos,
            radius: 0.0,
            vel: [0.0, 0.0],
            springs: Vec::new(),
            test_color: settings::BLACK,
            data: BarData(Bar {
                text: text,
                value: value,
                text_color: text_color,
                background_color: background_color,
                bar_color: bar_color,
            }),
        }
    }

    pub fn blood(&self) -> Option<f64> {
        match self.data {
            PlayerData(player) => Some(player.blood),
            _ => None,
        }
    }

    pub fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        let x = self.pos[0];
        let y = self.pos[1];
        let rad = self.radius;

        match self.data {
            SharkData(_) => {
                c.square_centered(x, y, rad).color(self.test_color).fill(gl);
            },
            PlayerData(_) => {
                c.square_centered(x, y, rad).color(self.test_color).fill(gl);
            },
            BarData(bar) => {
                bar.render(&c.trans_local(x, y), gl);
            },
        };
    }

    fn move_shark(&mut self, state: shark::SharkState, player_dx: f64, player_dy: f64) {
        match state {
            shark::ChasingPlayer => {
                if player_dx > 0.0 { self.move_right(); }
                else { self.move_left(); }

                if player_dy > 0.0 { self.move_up(); }
                else { self.move_down(); }
            },
            _ => {},
       }
    }

    pub fn update(&mut self, dt: f64, player_pos: [f64, ..2]) {
        self.pos = [self.pos[0] + self.vel[0] * dt, self.pos[1] + self.vel[1] * dt];

        // Update object state.
        let (player_dx, player_dy) = (player_pos[0] - self.pos[0], player_pos[1] - self.pos[1]);
        match self.data {
            SharkData(ref mut shark) => {
                shark.update(dt, player_pos, self.pos);
            },
            _ => {},
        }

        // Move object.
        match self.data {
            SharkData(Shark { state: state, ..}) => {
                self.move_shark(state, player_dx, player_dy);
            },
            _ => {},
        }
    }

    pub fn move_right(&mut self) {
        let speed_right = settings::PLAYER_SPEED_RIGHT;
        self.vel = [speed_right, self.vel[1]];
    }

    pub fn move_left(&mut self) {
        let speed_left = settings::PLAYER_SPEED_LEFT;
        self.vel = [-speed_left, self.vel[1]];
    }

    pub fn move_up(&mut self) {
        let speed_up = settings::PLAYER_SPEED_UP;
        self.vel = [self.vel[0], speed_up];
    }

    pub fn move_down(&mut self) {
        let speed_down = settings::PLAYER_SPEED_DOWN;
        self.vel = [self.vel[0], -speed_down];
    }
}

<commit_msg>`update` returns `Action`<commit_after>
use action;
use graphics;
use graphics::*;
use Gl = piston::gl::Gl;
use settings;
use spring::Spring;
use bar::Bar;
use player::Player;
use shark;
use shark::Shark;

pub enum ObjectData {
    PlayerData(Player),
    SharkData(Shark),
    BarData(Bar),
}

/// All objects are of same kind.
/// Makes it easier to write game logic.
pub struct Object {
    pub pos: [f64, ..2],
    pub vel: [f64, ..2],
    pub radius: f64,
    pub test_color: [f32, ..4],
    pub springs: Vec<Spring>,
    pub data: ObjectData,
}

impl Object {
    pub fn player(pos: [f64, ..2], test_color: [f32, ..4], blood: f64) -> Object {
        Object {
            pos: pos,
            vel: [0.0, 0.0],
            radius: settings::PLAYER_RADIUS,
            test_color: test_color,
            springs: Vec::new(),
            data: PlayerData(Player { blood: blood }),
        }
    }

    pub fn shark(
        pos: [f64, ..2],
        settings: settings::SharkSettings
    ) -> Object {

        Object {
            pos: pos,
            vel: [0.0, 0.0],
            radius: settings.radius,
            test_color: settings.test_color,
            springs: Vec::new(),
            data: SharkData(Shark {
                sensor_distance: settings.sensor_distance,
                state: settings.initial_state,
                bite_damage: settings.bite_damage,
                attack_distance: settings.attack_distance,
                wait_seconds_before_initial_attack: settings.wait_seconds_before_initial_attack,
                wait_seconds_before_repeat_attack: settings.wait_seconds_before_repeat_attack,
            }),
        }
    }

    pub fn bar(
        pos: [f64, ..2],
        text: &'static str,
        text_color: [f32, ..4],
        background_color: [f32, ..4],
        bar_color: [f32, ..4],
        value: f64
    ) -> Object {

       Object {
            pos: pos,
            radius: 0.0,
            vel: [0.0, 0.0],
            springs: Vec::new(),
            test_color: settings::BLACK,
            data: BarData(Bar {
                text: text,
                value: value,
                text_color: text_color,
                background_color: background_color,
                bar_color: bar_color,
            }),
        }
    }

    pub fn blood(&self) -> Option<f64> {
        match self.data {
            PlayerData(player) => Some(player.blood),
            _ => None,
        }
    }

    pub fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        let x = self.pos[0];
        let y = self.pos[1];
        let rad = self.radius;

        match self.data {
            SharkData(_) => {
                c.square_centered(x, y, rad).color(self.test_color).fill(gl);
            },
            PlayerData(_) => {
                c.square_centered(x, y, rad).color(self.test_color).fill(gl);
            },
            BarData(bar) => {
                bar.render(&c.trans_local(x, y), gl);
            },
        };
    }

    fn move_shark(&mut self, state: shark::SharkState, player_dx: f64, player_dy: f64) {
        match state {
            shark::ChasingPlayer => {
                if player_dx > 0.0 { self.move_right(); }
                else { self.move_left(); }

                if player_dy > 0.0 { self.move_up(); }
                else { self.move_down(); }
            },
            _ => {},
       }
    }

    pub fn update(&mut self, dt: f64, player_pos: [f64, ..2]) -> action::Action {
        self.pos = [self.pos[0] + self.vel[0] * dt, self.pos[1] + self.vel[1] * dt];

        let mut action = action::Passive;
        // Update object state.
        let (player_dx, player_dy) = (player_pos[0] - self.pos[0], player_pos[1] - self.pos[1]);
        match self.data {
            SharkData(ref mut shark) => {
                action = shark.update(dt, player_pos, self.pos);
            },
            _ => {},
        }

        // Move object.
        match self.data {
            SharkData(Shark { state: state, ..}) => {
                self.move_shark(state, player_dx, player_dy);
            },
            _ => {},
        }

        action
    }

    pub fn move_right(&mut self) {
        let speed_right = settings::PLAYER_SPEED_RIGHT;
        self.vel = [speed_right, self.vel[1]];
    }

    pub fn move_left(&mut self) {
        let speed_left = settings::PLAYER_SPEED_LEFT;
        self.vel = [-speed_left, self.vel[1]];
    }

    pub fn move_up(&mut self) {
        let speed_up = settings::PLAYER_SPEED_UP;
        self.vel = [self.vel[0], speed_up];
    }

    pub fn move_down(&mut self) {
        let speed_down = settings::PLAYER_SPEED_DOWN;
        self.vel = [self.vel[0], -speed_down];
    }
}

<|endoftext|>


<commit_before>use std::hash::{Hash};
use std::slice::{
    Items,
};
use std::fmt;
use test;

// FIXME: These aren't stable, so a public wrapper of node/edge indices
// should be lifetimed just like pointers.
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct NodeIndex(uint);
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct EdgeIndex(uint);

const EdgeEnd: EdgeIndex = EdgeIndex(::std::uint::MAX);
//const InvalidNode: NodeIndex = NodeIndex(::std::uint::MAX);

/// Index into the NodeIndex and EdgeIndex arrays
#[deriving(Copy, Clone, Show, PartialEq)]
enum Dir {
    Out = 0,
    In = 1
}

const DIRECTIONS: [Dir, ..2] = [Dir::Out, Dir::In];

#[deriving(Show)]
pub struct Node<N> {
    pub data: N,
    /// Next edge in outgoing and incoming edge lists.
    next: [EdgeIndex, ..2],
}

#[deriving(Show, Copy)]
pub struct Edge<E> {
    pub data: E,
    /// Next edge in outgoing and incoming edge lists.
    next: [EdgeIndex, ..2],
    /// Start and End node index
    node: [NodeIndex, ..2],
}

/// **OGraph\<N, E\>** is a directed graph using an adjacency list representation.
///
/// The graph maintains unique indices for nodes and edges, so both node and edge
/// data may be accessed mutably.
///
/// Based upon the graph implementation in rustc.
//#[deriving(Show)]
pub struct OGraph<N, E> {
    nodes: Vec<Node<N>>,
    edges: Vec<Edge<E>>,
}

impl<N: fmt::Show, E: fmt::Show> fmt::Show for OGraph<N, E>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in self.nodes.iter() {
            try!(writeln!(f, "{}", n));
        }
        for n in self.edges.iter() {
            try!(writeln!(f, "{}", n));
        }
        Ok(())
    }
}

pub enum Pair<'a, T: 'a> {
    Both(&'a mut T, &'a mut T),
    One(&'a mut T),
    None,
}

pub fn index_twice<T>(slc: &mut [T], a: uint, b: uint) -> Pair<T>
{
    if a == b {
        slc.get_mut(a).map_or(Pair::None, Pair::One)
    } else {
        if a >= slc.len() || b >= slc.len() {
            Pair::None
        } else {
            // safe because a, b are in bounds and distinct
            unsafe {
                let ar = &mut *(slc.unsafe_mut(a) as *mut _);
                let br = &mut *(slc.unsafe_mut(b) as *mut _);
                Pair::Both(ar, br)
            }
        }
    }
}

/// Iterate over an edge list.
fn walk_edge_list<E, F: FnMut(EdgeIndex, &mut Edge<E>) -> bool>(
    fst: EdgeIndex, edges: &mut [Edge<E>], d: Dir, mut f: F)
{
    let k = d as uint;
    let mut cur = fst;
    loop {
        match edges.get_mut(cur.0) {
            None => {
                debug_assert!(cur == EdgeEnd);
                break;
            }
            Some(curedge) => {
                if !f(cur, curedge) {
                    break;
                }
                cur = curedge.next[k];
            }
        }
    }
}

impl<N, E> OGraph<N, E>
//where N: fmt::Show
{
    pub fn new() -> OGraph<N, E>
    {
        OGraph{nodes: Vec::new(), edges: Vec::new()}
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex
    {
        let node = Node{data: data, next: [EdgeEnd, EdgeEnd]};
        let node_idx = NodeIndex(self.nodes.len());
        self.nodes.push(node);
        node_idx
    }

    pub fn node(&self, a: NodeIndex) -> Option<&N>
    {
        self.nodes.get(a.0).map(|n| &n.data)
    }

    pub fn node_mut(&mut self, a: NodeIndex) -> Option<&mut N>
    {
        self.nodes.get_mut(a.0).map(|n| &mut n.data)
    }

    pub fn neighbors(&self, a: NodeIndex) -> Neighbors<N, E>
    {
        Neighbors{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    pub fn edges(&self, a: NodeIndex) -> Edges<N, E>
    {
        Edges{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex, data: E) -> EdgeIndex
    {
        let edge_idx = EdgeIndex(self.edges.len());
        match index_twice(self.nodes[mut], a.0, b.0) {
            Pair::None => panic!("NodeIndices out of bounds"),
            Pair::One(an) => {
                let edge = Edge {
                    data: data,
                    node: [a, b],
                    next: an.next,
                };
                an.next[0] = edge_idx;
                an.next[1] = edge_idx;
                self.edges.push(edge);
            }
            Pair::Both(an, bn) => {
                // a and b are different indices
                let edge = Edge {
                    data: data,
                    node: [a, b],
                    next: [an.next[0], bn.next[1]],
                };
                an.next[0] = edge_idx;
                bn.next[1] = edge_idx;
                self.edges.push(edge);
            }
        }
        edge_idx
    }

    pub fn remove_node(&mut self, a: NodeIndex) -> Option<N>
    {
        match self.nodes.get(a.0) {
            None => return None,
            _ => {}
        }
        for d in DIRECTIONS.iter() {
            let k = *d as uint;
            /*
            println!("Starting edge removal for k={}, node={}", k, a);
            for (i, n) in self.nodes.iter().enumerate() {
                println!("Node {}: Edges={}", i, n.next);
            }
            for (i, ed) in self.edges.iter().enumerate() {
                println!("Edge {}: {}", i, ed);
            }
            */
            // Remove all edges from and to this node.
            loop {
                let next = self.nodes[a.0].next[k];
                if next == EdgeEnd {
                    break
                }
                let ret = self.remove_edge(next);
                debug_assert!(ret.is_some());
                let _ = ret;
            }
        }

        // Use swap_remove -- only the swapped-in node is going to change
        // NodeIndex, so we only have to walk its edges and update them.

        let node = match self.nodes.swap_remove(a.0) {
            None => return None,
            Some(node) => node,
        };

        // Find the edge lists of the node that had to relocate.
        // It may be that no node had to relocate, then we are done already.
        let swap_edges = match self.nodes.get(a.0) {
            None => return Some(node.data),
            Some(ed) => ed.next,
        };

        // The swapped element's old index
        let old_index = NodeIndex(self.nodes.len());
        let new_index = a;

        // Adjust the starts of the out edges, and ends of the in edges.
        for &d in DIRECTIONS.iter() {
            let k = d as uint;
            walk_edge_list(swap_edges[k], self.edges[mut], d, |_, curedge| {
                debug_assert!(curedge.node[k] == old_index);
                curedge.node[k] = new_index;
                true
            });
        }
        Some(node.data)
    }

    pub fn edge_mut(&mut self, e: EdgeIndex) -> &mut Edge<E>
    {
        &mut self.edges[e.0]
    }

    /// Remove an edge and return its edge weight, or None if it didn't exist.
    pub fn remove_edge(&mut self, e: EdgeIndex) -> Option<E>
    {
        // every edge is part of two lists,
        // outgoing and incoming edges.
        // Remove it from both
        //debug_assert!(self.edges.get(e.0).is_some(), "No such edge: {}", e);
        let (edge_node, edge_next) = match self.edges.get(e.0) {
            None => return None,
            Some(x) => (x.node, x.next),
        };
        // List out from A
        // List in from B
        for &d in DIRECTIONS.iter() {
            let k = d as uint;
            let node = match self.nodes.get_mut(edge_node[k].0) {
                Some(r) => r,
                None => {
                    debug_assert!(false, "Edge's endpoint dir={} index={} not found",
                                  k, edge_node[k]);
                    return None
                }
            };
            let fst = node.next[k];
            if fst == e {
                //println!("Updating first edge 0 for node {}, set to {}", edge_node[0], edge_next[0]);
                node.next[k] = edge_next[k];
            } else {
                walk_edge_list(fst, self.edges[mut], d, |eidx, curedge| {
                    if curedge.next[k] == e {
                        curedge.next[k] = edge_next[k];
                        false
                    } else { true }
                });
            }
        }
        self.remove_edge_adjust_indices(e)
    }

    fn remove_edge_adjust_indices(&mut self, e: EdgeIndex) -> Option<E>
    {
        // swap_remove the edge -- only the removed edge
        // and the edge swapped into place are affected and need updating
        // indices.
        let edge = self.edges.swap_remove(e.0).unwrap();
        let swap = match self.edges.get(e.0) {
            // no elment needed to be swapped.
            None => return Some(edge.data),
            Some(ed) => ed.node,
        };
        let swapped_e = EdgeIndex(self.edges.len());

        // List out from A
        // List in to B
        for &d in DIRECTIONS.iter() {
            let k = d as uint;
            let node = &mut self.nodes[swap[k].0];
            let fst = node.next[k];
            if fst == swapped_e {
                node.next[k] = e;
            } else {
                walk_edge_list(fst, self.edges[mut], d, |eidx, curedge| {
                    if curedge.next[k] == swapped_e {
                        curedge.next[k] = e;
                        false
                    } else { true }
                });
            }
        }
        let edge_data = edge.data;
        Some(edge_data)
    }
}

pub struct Neighbors<'a, N: 'a, E: 'a> {
    graph: &'a OGraph<N, E>,
    next: EdgeIndex,
}

impl<'a, N, E> Iterator<NodeIndex> for Neighbors<'a, N, E>
{
    fn next(&mut self) -> Option<NodeIndex>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some(edge.node[1])
            }
        }
    }
}

pub struct Edges<'a, N: 'a, E: 'a> {
    graph: &'a OGraph<N, E>,
    next: EdgeIndex,
}

impl<'a, N, E> Iterator<(NodeIndex, &'a E)> for Edges<'a, N, E>
{
    fn next(&mut self) -> Option<(NodeIndex, &'a E)>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some((edge.node[1], &edge.data))
            }
        }
    }
}
#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    for x in range(1, 125) {
        let n = og.add_node(x);
        og.add_edge(fst, n, ());
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    let mut prev = fst;
    for x in range(1, 1250) {
        let n = og.add_node(x);
        og.add_edge(prev, n, ());
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in range(0, 100i) {
            og.remove_node(fst);
        }
    })
}
<commit_msg>Docs for OGraph + find_edge<commit_after>use std::hash::{Hash};
use std::slice::{
    Items,
};
use std::fmt;
use test;

// FIXME: These aren't stable, so a public wrapper of node/edge indices
// should be lifetimed just like pointers.
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct NodeIndex(uint);
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct EdgeIndex(uint);

const EdgeEnd: EdgeIndex = EdgeIndex(::std::uint::MAX);
//const InvalidNode: NodeIndex = NodeIndex(::std::uint::MAX);

/// Index into the NodeIndex and EdgeIndex arrays
#[deriving(Copy, Clone, Show, PartialEq)]
enum Dir {
    Out = 0,
    In = 1
}

const DIRECTIONS: [Dir, ..2] = [Dir::Out, Dir::In];

#[deriving(Show)]
pub struct Node<N> {
    pub data: N,
    /// Next edge in outgoing and incoming edge lists.
    next: [EdgeIndex, ..2],
}

#[deriving(Show, Copy)]
pub struct Edge<E> {
    pub data: E,
    /// Next edge in outgoing and incoming edge lists.
    next: [EdgeIndex, ..2],
    /// Start and End node index
    node: [NodeIndex, ..2],
}

/// **OGraph\<N, E\>** is a directed graph using an adjacency list representation.
///
/// The graph maintains unique indices for nodes and edges, so both node and edge
/// data may be accessed mutably.
///
/// Based upon the graph implementation in rustc.
//#[deriving(Show)]
pub struct OGraph<N, E> {
    nodes: Vec<Node<N>>,
    edges: Vec<Edge<E>>,
}

impl<N: fmt::Show, E: fmt::Show> fmt::Show for OGraph<N, E>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in self.nodes.iter() {
            try!(writeln!(f, "{}", n));
        }
        for n in self.edges.iter() {
            try!(writeln!(f, "{}", n));
        }
        Ok(())
    }
}

pub enum Pair<'a, T: 'a> {
    Both(&'a mut T, &'a mut T),
    One(&'a mut T),
    None,
}

pub fn index_twice<T>(slc: &mut [T], a: uint, b: uint) -> Pair<T>
{
    if a == b {
        slc.get_mut(a).map_or(Pair::None, Pair::One)
    } else {
        if a >= slc.len() || b >= slc.len() {
            Pair::None
        } else {
            // safe because a, b are in bounds and distinct
            unsafe {
                let ar = &mut *(slc.unsafe_mut(a) as *mut _);
                let br = &mut *(slc.unsafe_mut(b) as *mut _);
                Pair::Both(ar, br)
            }
        }
    }
}

/// Iterate over an edge list.
fn walk_edge_list<E, F: FnMut(EdgeIndex, &mut Edge<E>) -> bool>(
    fst: EdgeIndex, edges: &mut [Edge<E>], d: Dir, mut f: F)
{
    let k = d as uint;
    let mut cur = fst;
    loop {
        match edges.get_mut(cur.0) {
            None => {
                debug_assert!(cur == EdgeEnd);
                break;
            }
            Some(curedge) => {
                if !f(cur, curedge) {
                    break;
                }
                cur = curedge.next[k];
            }
        }
    }
}

impl<N, E> OGraph<N, E>
//where N: fmt::Show
{
    /// Create a new OGraph.
    pub fn new() -> OGraph<N, E>
    {
        OGraph{nodes: Vec::new(), edges: Vec::new()}
    }

    /// Add a node with weight **data** to the graph.
    pub fn add_node(&mut self, data: N) -> NodeIndex
    {
        let node = Node{data: data, next: [EdgeEnd, EdgeEnd]};
        let node_idx = NodeIndex(self.nodes.len());
        self.nodes.push(node);
        node_idx
    }

    /// Access node data for node **a**.
    pub fn node(&self, a: NodeIndex) -> Option<&N>
    {
        self.nodes.get(a.0).map(|n| &n.data)
    }

    /// Access node data for node **a**.
    pub fn node_mut(&mut self, a: NodeIndex) -> Option<&mut N>
    {
        self.nodes.get_mut(a.0).map(|n| &mut n.data)
    }

    /// Return an iterator of all neighbors that have an edge from **a** to them.
    ///
    /// Produces an empty iterator if the node doesn't exist.
    ///
    /// Iterator element type is **NodeIndex**.
    pub fn neighbors(&self, a: NodeIndex) -> Neighbors<N, E>
    {
        Neighbors{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    /// Return an iterator over the neighbors of node **a**, paired with their respective edge
    /// weights.
    ///
    /// Produces an empty iterator if the node doesn't exist.
    ///
    /// Iterator element type is **(NodeIndex, &'a E)**.
    pub fn edges(&self, a: NodeIndex) -> Edges<N, E>
    {
        Edges{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    /// Add an edge from **a** to **b** to the graph, with its edge weight.
    pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex, data: E) -> EdgeIndex
    {
        let edge_idx = EdgeIndex(self.edges.len());
        match index_twice(self.nodes[mut], a.0, b.0) {
            Pair::None => panic!("NodeIndices out of bounds"),
            Pair::One(an) => {
                let edge = Edge {
                    data: data,
                    node: [a, b],
                    next: an.next,
                };
                an.next[0] = edge_idx;
                an.next[1] = edge_idx;
                self.edges.push(edge);
            }
            Pair::Both(an, bn) => {
                // a and b are different indices
                let edge = Edge {
                    data: data,
                    node: [a, b],
                    next: [an.next[0], bn.next[1]],
                };
                an.next[0] = edge_idx;
                bn.next[1] = edge_idx;
                self.edges.push(edge);
            }
        }
        edge_idx
    }

    /// Remove **a** from the graph if it exists, and return its data value.
    /// If it doesn't exist in the graph, return **None**.
    pub fn remove_node(&mut self, a: NodeIndex) -> Option<N>
    {
        match self.nodes.get(a.0) {
            None => return None,
            _ => {}
        }
        for d in DIRECTIONS.iter() {
            let k = *d as uint;
            /*
            println!("Starting edge removal for k={}, node={}", k, a);
            for (i, n) in self.nodes.iter().enumerate() {
                println!("Node {}: Edges={}", i, n.next);
            }
            for (i, ed) in self.edges.iter().enumerate() {
                println!("Edge {}: {}", i, ed);
            }
            */
            // Remove all edges from and to this node.
            loop {
                let next = self.nodes[a.0].next[k];
                if next == EdgeEnd {
                    break
                }
                let ret = self.remove_edge(next);
                debug_assert!(ret.is_some());
                let _ = ret;
            }
        }

        // Use swap_remove -- only the swapped-in node is going to change
        // NodeIndex, so we only have to walk its edges and update them.

        let node = match self.nodes.swap_remove(a.0) {
            None => return None,
            Some(node) => node,
        };

        // Find the edge lists of the node that had to relocate.
        // It may be that no node had to relocate, then we are done already.
        let swap_edges = match self.nodes.get(a.0) {
            None => return Some(node.data),
            Some(ed) => ed.next,
        };

        // The swapped element's old index
        let old_index = NodeIndex(self.nodes.len());
        let new_index = a;

        // Adjust the starts of the out edges, and ends of the in edges.
        for &d in DIRECTIONS.iter() {
            let k = d as uint;
            walk_edge_list(swap_edges[k], self.edges[mut], d, |_, curedge| {
                debug_assert!(curedge.node[k] == old_index);
                curedge.node[k] = new_index;
                true
            });
        }
        Some(node.data)
    }

    pub fn edge_mut(&mut self, e: EdgeIndex) -> &mut Edge<E>
    {
        &mut self.edges[e.0]
    }

    /// Remove an edge and return its edge weight, or **None** if it didn't exist.
    pub fn remove_edge(&mut self, e: EdgeIndex) -> Option<E>
    {
        // every edge is part of two lists,
        // outgoing and incoming edges.
        // Remove it from both
        //debug_assert!(self.edges.get(e.0).is_some(), "No such edge: {}", e);
        let (edge_node, edge_next) = match self.edges.get(e.0) {
            None => return None,
            Some(x) => (x.node, x.next),
        };
        // List out from A
        // List in from B
        for &d in DIRECTIONS.iter() {
            let k = d as uint;
            let node = match self.nodes.get_mut(edge_node[k].0) {
                Some(r) => r,
                None => {
                    debug_assert!(false, "Edge's endpoint dir={} index={} not found",
                                  k, edge_node[k]);
                    return None
                }
            };
            let fst = node.next[k];
            if fst == e {
                //println!("Updating first edge 0 for node {}, set to {}", edge_node[0], edge_next[0]);
                node.next[k] = edge_next[k];
            } else {
                walk_edge_list(fst, self.edges[mut], d, |eidx, curedge| {
                    if curedge.next[k] == e {
                        curedge.next[k] = edge_next[k];
                        false
                    } else { true }
                });
            }
        }
        self.remove_edge_adjust_indices(e)
    }

    fn remove_edge_adjust_indices(&mut self, e: EdgeIndex) -> Option<E>
    {
        // swap_remove the edge -- only the removed edge
        // and the edge swapped into place are affected and need updating
        // indices.
        let edge = self.edges.swap_remove(e.0).unwrap();
        let swap = match self.edges.get(e.0) {
            // no elment needed to be swapped.
            None => return Some(edge.data),
            Some(ed) => ed.node,
        };
        let swapped_e = EdgeIndex(self.edges.len());

        // List out from A
        // List in to B
        for &d in DIRECTIONS.iter() {
            let k = d as uint;
            let node = &mut self.nodes[swap[k].0];
            let fst = node.next[k];
            if fst == swapped_e {
                node.next[k] = e;
            } else {
                walk_edge_list(fst, self.edges[mut], d, |eidx, curedge| {
                    if curedge.next[k] == swapped_e {
                        curedge.next[k] = e;
                        false
                    } else { true }
                });
            }
        }
        let edge_data = edge.data;
        Some(edge_data)
    }

    /// Lookup an edge from **a** to **b**.
    pub fn find_edge(&self, a: NodeIndex, b: NodeIndex) -> Option<EdgeIndex>
    {
        match self.nodes.get(a.0) {
            None => None,
            Some(node) => {
                let mut edix = node.next[0];
                while edix != EdgeEnd {
                    let edge = &self.edges[edix.0];
                    if edge.node[1] == b {
                        return Some(edix)
                    }
                }
                None
            }
        }
    }
}

/// Iterator over the neighbors of a node.
///
/// Iterator element type is **NodeIndex**.
pub struct Neighbors<'a, N: 'a, E: 'a> {
    graph: &'a OGraph<N, E>,
    next: EdgeIndex,
}

impl<'a, N, E> Iterator<NodeIndex> for Neighbors<'a, N, E>
{
    fn next(&mut self) -> Option<NodeIndex>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some(edge.node[1])
            }
        }
    }
}

pub struct Edges<'a, N: 'a, E: 'a> {
    graph: &'a OGraph<N, E>,
    next: EdgeIndex,
}

impl<'a, N, E> Iterator<(NodeIndex, &'a E)> for Edges<'a, N, E>
{
    fn next(&mut self) -> Option<(NodeIndex, &'a E)>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some((edge.node[1], &edge.data))
            }
        }
    }
}
#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    for x in range(1, 125) {
        let n = og.add_node(x);
        og.add_edge(fst, n, ());
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    let mut prev = fst;
    for x in range(1, 1250) {
        let n = og.add_node(x);
        og.add_edge(prev, n, ());
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in range(0, 100i) {
            og.remove_node(fst);
        }
    })
}
<|endoftext|>


<commit_before>//! The parser is based on the following grammar
//!
//! Expression ==> "let" Name "=" Equation
//!             |  Equation
//!
//! Equation   ==> Product { "+" Product }
//!             |  Product { "-" Product }
//!
//! Product    ==> Factor { "*" Factor }
//!             |  Factor { "/" Factor }
//!
//! Factor     ==> "-" Factor
//!             |  Exponent { "^" Factor }
//!
//! Exponent   ==> Number { "!" }
//!
//! Number     ==> Function "(" Equation ")"
//!             |  Constant
//!             |  Name
//!             |  "ans"
//!             |  "(" Equation ")"
//!             |  "|" Equation "|"
//!             |  NumLiteral
//!
//! Function   ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!             |  "ln" | "log"
//!
//! Constant   ==> "pi" | "e" | "phi"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use ast::OpKind::*;
use token::Token;
use token::TokVal;
use token::TokVal::*;
use token::KeywordKind::*;

pub fn parse_tokens(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_expression()
}

fn get_builtin_name(name: &String) -> Option<AstVal> {
    match name.as_ref() {
        "ans" => Some(AstVal::LastResult),
        "pi" | "π" => Some(AstVal::Const(Pi)),
        "e" => Some(AstVal::Const(E)),
        "phi" | "ϕ" => Some(AstVal::Const(Phi)),
        "cos" => Some(AstVal::Func(Cos)),
        "sin" => Some(AstVal::Func(Sin)),
        "tan" => Some(AstVal::Func(Tan)),
        "asin" => Some(AstVal::Func(Asin)),
        "acos" => Some(AstVal::Func(Acos)),
        "atan" => Some(AstVal::Func(Atan)),
        "sqrt" | "√" => Some(AstVal::Func(Sqrt)),
        "abs" => Some(AstVal::Func(Abs)),
        "exp" => Some(AstVal::Func(Exp)),
        "ln" => Some(AstVal::Func(Ln)),
        "log" => Some(AstVal::Func(Log)),
        _ => None
    }
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_expression(&mut self) -> CalcrResult<Ast> {
        if self.next_tok_is(Keyword(Let)) {
            self.consume_tok();
            if !self.toks_empty() {
                let Token { val: tok_val, span: tok_span } = self.consume_tok();
                match tok_val {
                    Name(ref name) if get_builtin_name(name).is_none() => {
                        if self.next_tok_is(Op(Assign)) {
                            let assign_tok = self.consume_tok();
                            let eq = try!(self.parse_equation());
                            let name_ast = Ast {
                                val: AstVal::Name(name.clone()),
                                span: tok_span,
                                branches: Leaf,
                            };
                            Ok(Ast {
                                val: AstVal::Op(Assign),
                                span: assign_tok.span,
                                branches: Binary(Box::new(name_ast), Box::new(eq)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Expected assignment operator '=' after name".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    },
                    Name(ref name) => Err(CalcrError {
                        desc: format!("Cannot assign to builtin name '{}'", name),
                        span: Some(tok_span),
                    }),
                    _ => Err(CalcrError {
                        desc: "Expected name to assign to".to_string(),
                        span: Some(tok_span),
                    }),
                }
            } else {
                Err(CalcrError {
                    desc: "Expected name to assign to".to_string(),
                    span: Some((self.end_pos, self.end_pos)),
                })
            }

        } else {
            self.parse_equation()
        }
    }

    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_product());
        while self.next_tok_matches(|val| *val == Op(Plus) || *val == Op(Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_product());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            }
        }
        if self.next_tok_is(ParenClose) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.next_tok_is(AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.next_tok_matches(|val| *val == Op(Mult) || *val == Op(Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.next_tok_is(Op(Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(Neg),
                span: tok_span,
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.next_tok_is(Op(Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(Pow),
                    span: tok_span,
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.next_tok_is(Op(Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(Fact),
                span: tok_span,
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        if self.toks_empty() {
            Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            })
        } else {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            match tok_val {
                Name(ref name) => {
                    let val = match get_builtin_name(name) {
                        Some(val) => val,
                        None => AstVal::Name(name.clone()),
                    };
                    if let AstVal::Func(_) = val {
                        // it's a function so we need to grab its argument
                        if self.next_tok_is(ParenOpen) {
                            // since we know the next token is an open paren, we use
                            // this function to get its AST
                            let arg = try!(self.parse_equation());
                            Ok(Ast {
                                val: val,
                                span: tok_span,
                                branches: Unary(Box::new(arg)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Missing opening parentheses after function".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    } else {
                        Ok(Ast {
                            val: val,
                            span: tok_span,
                            branches: Leaf,
                        })
                    }
                },
                ParenOpen => {
                    self.paren_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(ParenClose) {
                        Err(CalcrError {
                            desc: "Missing closing parentheses".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.paren_level -= 1;
                        let close_paren_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Paren,
                            span: (tok_span.0, close_paren_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                AbsDelim => {
                    self.abs_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(AbsDelim) {
                        Err(CalcrError {
                            desc: "Missing closing abs delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.abs_level -= 1;
                        let close_delim_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Func(Abs),
                            span: (tok_span.0, close_delim_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                Num(num) => {
                    Ok(Ast {
                        val: AstVal::Num(num),
                        span: tok_span,
                        branches: Leaf,
                    })
                },
                _ => Err(CalcrError {
                    desc: format!("Expected number or constant"),
                    span: Some(tok_span),
                }),
            }
        }
    }

    /// Peeks at the next token and check whether its values is equal to `val`
    fn next_tok_is(&mut self, val: TokVal) -> bool {
        self.next_tok_matches(|v| *v == val)
    }

    /// Peeks at the next token and checks whether its value makes `pred` true
    fn next_tok_matches<F>(&mut self, pred: F) -> bool where F: FnOnce(&TokVal) -> bool {
        self.iter.peek().map_or(false, |ref tok| pred(&tok.val))
    }

    /// Checks if we have run out of `Token`s to parse
    fn toks_empty(&mut self) -> bool {
        self.iter.peek().is_none()
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token::TokVal;
    use ast::Ast;
    use ast::AstVal;
    use ast::AstBranch;
    use ast::ConstKind::*;

    #[test]
    fn single_num() {
        let toks = vec!(Token { val: TokVal::Num(2.0), span: (0, 1) });
        let ast = parse_equation(toks);
        assert_eq!(ast, Ok(Ast { val: AstVal::Num(2.0), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn constants() {
        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("pi".to_string()), span: (0, 2)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 2), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("π".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("e".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(E), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("phi".to_string()), span: (0, 3)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 3), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("ϕ".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn empty() {
        let toks = vec!();
        let err = parse_equation(toks);
        assert!(err.is_err());
    }
}<commit_msg>Update doc comment in the parser<commit_after>//! The parser is based on the following grammar
//!
//! Expression ==> "let" Name "=" Equation
//!             |  Equation
//!
//! Equation   ==> Product { "+" Product }
//!             |  Product { "-" Product }
//!
//! Product    ==> Factor { "*" Factor }
//!             |  Factor { "/" Factor }
//!
//! Factor     ==> "-" Factor
//!             |  Exponent { "^" Factor }
//!
//! Exponent   ==> Number { "!" }
//!
//! Number     ==> Function "(" Equation ")"
//!             |  Constant
//!             |  Name
//!             |  "ans"
//!             |  "(" Equation ")"
//!             |  "|" Equation "|"
//!             |  NumLiteral
//!
//! Function   ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!             |  "ln" | "log"
//!
//! Constant   ==> "pi" | "π" | "e" | "phi" | "ϕ" | "ans"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use ast::OpKind::*;
use token::Token;
use token::TokVal;
use token::TokVal::*;
use token::KeywordKind::*;

pub fn parse_tokens(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_expression()
}

fn get_builtin_name(name: &String) -> Option<AstVal> {
    match name.as_ref() {
        "ans" => Some(AstVal::LastResult),
        "pi" | "π" => Some(AstVal::Const(Pi)),
        "e" => Some(AstVal::Const(E)),
        "phi" | "ϕ" => Some(AstVal::Const(Phi)),
        "cos" => Some(AstVal::Func(Cos)),
        "sin" => Some(AstVal::Func(Sin)),
        "tan" => Some(AstVal::Func(Tan)),
        "asin" => Some(AstVal::Func(Asin)),
        "acos" => Some(AstVal::Func(Acos)),
        "atan" => Some(AstVal::Func(Atan)),
        "sqrt" | "√" => Some(AstVal::Func(Sqrt)),
        "abs" => Some(AstVal::Func(Abs)),
        "exp" => Some(AstVal::Func(Exp)),
        "ln" => Some(AstVal::Func(Ln)),
        "log" => Some(AstVal::Func(Log)),
        _ => None
    }
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_expression(&mut self) -> CalcrResult<Ast> {
        if self.next_tok_is(Keyword(Let)) {
            self.consume_tok();
            if !self.toks_empty() {
                let Token { val: tok_val, span: tok_span } = self.consume_tok();
                match tok_val {
                    Name(ref name) if get_builtin_name(name).is_none() => {
                        if self.next_tok_is(Op(Assign)) {
                            let assign_tok = self.consume_tok();
                            let eq = try!(self.parse_equation());
                            let name_ast = Ast {
                                val: AstVal::Name(name.clone()),
                                span: tok_span,
                                branches: Leaf,
                            };
                            Ok(Ast {
                                val: AstVal::Op(Assign),
                                span: assign_tok.span,
                                branches: Binary(Box::new(name_ast), Box::new(eq)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Expected assignment operator '=' after name".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    },
                    Name(ref name) => Err(CalcrError {
                        desc: format!("Cannot assign to builtin name '{}'", name),
                        span: Some(tok_span),
                    }),
                    _ => Err(CalcrError {
                        desc: "Expected name to assign to".to_string(),
                        span: Some(tok_span),
                    }),
                }
            } else {
                Err(CalcrError {
                    desc: "Expected name to assign to".to_string(),
                    span: Some((self.end_pos, self.end_pos)),
                })
            }

        } else {
            self.parse_equation()
        }
    }

    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_product());
        while self.next_tok_matches(|val| *val == Op(Plus) || *val == Op(Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_product());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            }
        }
        if self.next_tok_is(ParenClose) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.next_tok_is(AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.next_tok_matches(|val| *val == Op(Mult) || *val == Op(Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.next_tok_is(Op(Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(Neg),
                span: tok_span,
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.next_tok_is(Op(Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(Pow),
                    span: tok_span,
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.next_tok_is(Op(Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(Fact),
                span: tok_span,
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        if self.toks_empty() {
            Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            })
        } else {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            match tok_val {
                Name(ref name) => {
                    let val = match get_builtin_name(name) {
                        Some(val) => val,
                        None => AstVal::Name(name.clone()),
                    };
                    if let AstVal::Func(_) = val {
                        // it's a function so we need to grab its argument
                        if self.next_tok_is(ParenOpen) {
                            // since we know the next token is an open paren, we use
                            // this function to get its AST
                            let arg = try!(self.parse_equation());
                            Ok(Ast {
                                val: val,
                                span: tok_span,
                                branches: Unary(Box::new(arg)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Missing opening parentheses after function".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    } else {
                        Ok(Ast {
                            val: val,
                            span: tok_span,
                            branches: Leaf,
                        })
                    }
                },
                ParenOpen => {
                    self.paren_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(ParenClose) {
                        Err(CalcrError {
                            desc: "Missing closing parentheses".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.paren_level -= 1;
                        let close_paren_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Paren,
                            span: (tok_span.0, close_paren_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                AbsDelim => {
                    self.abs_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(AbsDelim) {
                        Err(CalcrError {
                            desc: "Missing closing abs delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.abs_level -= 1;
                        let close_delim_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Func(Abs),
                            span: (tok_span.0, close_delim_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                Num(num) => {
                    Ok(Ast {
                        val: AstVal::Num(num),
                        span: tok_span,
                        branches: Leaf,
                    })
                },
                _ => Err(CalcrError {
                    desc: format!("Expected number or constant"),
                    span: Some(tok_span),
                }),
            }
        }
    }

    /// Peeks at the next token and check whether its values is equal to `val`
    fn next_tok_is(&mut self, val: TokVal) -> bool {
        self.next_tok_matches(|v| *v == val)
    }

    /// Peeks at the next token and checks whether its value makes `pred` true
    fn next_tok_matches<F>(&mut self, pred: F) -> bool where F: FnOnce(&TokVal) -> bool {
        self.iter.peek().map_or(false, |ref tok| pred(&tok.val))
    }

    /// Checks if we have run out of `Token`s to parse
    fn toks_empty(&mut self) -> bool {
        self.iter.peek().is_none()
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token::TokVal;
    use ast::Ast;
    use ast::AstVal;
    use ast::AstBranch;
    use ast::ConstKind::*;

    #[test]
    fn single_num() {
        let toks = vec!(Token { val: TokVal::Num(2.0), span: (0, 1) });
        let ast = parse_equation(toks);
        assert_eq!(ast, Ok(Ast { val: AstVal::Num(2.0), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn constants() {
        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("pi".to_string()), span: (0, 2)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 2), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("π".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("e".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(E), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("phi".to_string()), span: (0, 3)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 3), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("ϕ".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn empty() {
        let toks = vec!();
        let err = parse_equation(toks);
        assert!(err.is_err());
    }
}<|endoftext|>


<commit_before>/// For some reason, Pest cannot find the grammar file if listed in parser/mod.rs, so I listed it here
use pest::Parser;
use pest::iterators::Pair;
use pest::inputs::StrInput;

use ast::Expression;

use std::f64;

const _GRAMMAR: &'static str = include_str!("grammar/grammar.pest");

#[derive(Parser)]
#[grammar = "grammar/grammar.pest"]
pub struct ExpressionParser;

fn parse_expression(input: Pair<Rule, StrInput>) -> Expression {
    match input.as_rule() {
        Rule::boolean_literal =>
            Expression::Boolean(
                input.into_span().as_str().parse::<bool>().unwrap()
            ),

        Rule::string_literal =>
            Expression::String(format!("{}", input.into_span().as_str())
            ),

        Rule::identifier_literal =>
            Expression::Identifier(input.into_span().as_str().to_string()),

        // TODO: For now, just conver the value into a normal f64. No formatting!
        Rule::decimal_digits_literal =>
            Expression::Number(
                input.into_span().as_str().parse::<f64>().unwrap()
            ),

        Rule::binary_digits_literal =>
            // The parse function does not support binary digits, so do it the hard way
            Expression::Number(
                f64::from(i32::from_str_radix(&input.into_span().as_str()[2..], 2).unwrap())
            ),

        Rule::oct_digits_literal =>
            // The parse function does not support octal digits, so do it the hard way
            Expression::Number(
                f64::from(i32::from_str_radix(&input.into_span().as_str()[2..], 8).unwrap())
            ),

        Rule::hex_digits_literal =>
            // The parse function does not support hexadecimal digits, so do it the hard way
            Expression::Number(
                f64::from(i32::from_str_radix(&input.into_span().as_str()[2..], 16).unwrap())
            ),

        Rule::list_literal =>
            Expression::List(input
                            .into_inner()
                            .into_iter()
                            .map(|r| Box::new(parse_expression(r)))
                            .collect()),

        // Temporary
        _ => unreachable!()
    }

}

pub fn parse(input: String) -> Result<Expression, String> {
    // TODO: Remove unwrap
    match ExpressionParser::parse_str(Rule::main, &input) {
        Ok(mut pair) =>
            Ok(parse_expression(pair.nth(0).unwrap().into_inner().nth(0).unwrap())),

        Err(e) => Err(format!("{}", e))
    }
}<commit_msg>Remove whitespace<commit_after>/// For some reason, Pest cannot find the grammar file if listed in parser/mod.rs, so I listed it here
use pest::Parser;
use pest::iterators::Pair;
use pest::inputs::StrInput;

use ast::Expression;

use std::f64;

const _GRAMMAR: &'static str = include_str!("grammar/grammar.pest");

#[derive(Parser)]
#[grammar = "grammar/grammar.pest"]
pub struct ExpressionParser;

fn parse_expression(input: Pair<Rule, StrInput>) -> Expression {
    match input.as_rule() {
        Rule::boolean_literal =>
            Expression::Boolean(
                input.into_span().as_str().parse::<bool>().unwrap()
            ),

        Rule::string_literal =>
            Expression::String(format!("{}", input.into_span().as_str())
            ),

        Rule::identifier_literal =>
            Expression::Identifier(input.into_span().as_str().to_string()),

        // TODO: For now, just conver the value into a normal f64. No formatting!
        Rule::decimal_digits_literal =>
            Expression::Number(
                input.into_span().as_str().parse::<f64>().unwrap()
            ),

        Rule::binary_digits_literal =>
            // The parse function does not support binary digits, so do it the hard way
            Expression::Number(
                f64::from(i32::from_str_radix(&input.into_span().as_str()[2..], 2).unwrap())
            ),

        Rule::oct_digits_literal =>
            // The parse function does not support octal digits, so do it the hard way
            Expression::Number(
                f64::from(i32::from_str_radix(&input.into_span().as_str()[2..], 8).unwrap())
            ),

        Rule::hex_digits_literal =>
            // The parse function does not support hexadecimal digits, so do it the hard way
            Expression::Number(
                f64::from(i32::from_str_radix(&input.into_span().as_str()[2..], 16).unwrap())
            ),

        Rule::list_literal =>
            Expression::List(input
                            .into_inner()
                            .into_iter()
                            .map(|r| Box::new(parse_expression(r)))
                            .collect()),

        // Temporary
        _ => unreachable!()
    }

}

pub fn parse(input: String) -> Result<Expression, String> {
    // TODO: Remove unwrap
    match ExpressionParser::parse_str(Rule::main, &input) {
        Ok(mut pair) =>
            Ok(parse_expression(pair.nth(0).unwrap().into_inner().nth(0).unwrap())),

        Err(e) => Err(format!("{}", e))
    }
}<|endoftext|>


<commit_before>
use pair::Pair;
use error::{NcclError, ErrorKind};
use token::{Token, TokenKind};

pub struct Parser {
    current: usize,
    path: Vec<String>,
    tokens: Vec<Token>,
    pair: Pair,
    line: u64,
}

// nccl = (value newline)+
// value = name schema? newline (key newline)*
// key = indent value
// name = [^:]+
// schema = ": " name
// newline = ("\n" | "\r\n")+
// indent = " "+ | "\t"

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Parser {
            current: 0,
            path: vec![],
            tokens: tokens,
            pair: Pair::new("__top_level__"),
            line: 1,
        }
    }

    pub fn parse(&mut self) -> Result<Pair, NcclError> {
        while !self.is_at_end() {
            self.value()?;
            self.newline()?;
            self.advance();
        }

        Ok(self.pair.clone())
    }

    fn add(&mut self, value: String) {
        //self.pair.add_vec(self.path, value);
    }

    fn value(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.name()?;
            if self.peek().kind == TokenKind::Colon {
                self.schema()?;
            }
            self.newline()?;

            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line))
        }
    }

    fn name(&mut self) -> Result<(), NcclError> {
        Ok(())
    }

    fn schema(&mut self) -> Result<(), NcclError> {
        Ok(())
    }

    fn indent(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected indent, found EOF", self.line))
        }
    }

    fn newline(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.line += 1;
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected newline, found EOF", self.line))
        }
    }

    fn colon(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected colon, found EOF", self.line))
        }
    }

    fn matches(&mut self, kind: TokenKind) -> bool {
        if self.check(kind) {
            self.advance();
            true
        } else {
            false
        }
    }

    fn check(&mut self, kind: TokenKind) -> bool {
        if self.is_at_end() {
            false
        } else {
            self.peek().kind == kind
        }
    }

    fn advance(&mut self) -> &Token {
        if !self.is_at_end() {
            self.current += 1;
        }

        self.previous()
    }

    fn is_at_end(&mut self) -> bool {
        self.peek().kind == TokenKind::EOF
    }

    fn peek(&mut self) -> &Token {
        &self.tokens[self.current]
    }

    fn previous(&mut self) -> &Token {
        &self.tokens[self.current - 1]
    }

    fn consume(&mut self, kind: TokenKind, message: &str) -> Result<&Token, NcclError> {
        if self.check(kind) {
            Ok(self.advance())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, message, self.line))
        }
    }
}

<commit_msg>make some changes??<commit_after>
use pair::Pair;
use error::{NcclError, ErrorKind};
use token::{Token, TokenKind};

use std::io::Write;

pub struct Parser {
    current: usize,
    path: Vec<String>,
    tokens: Vec<Token>,
    pair: Pair,
    line: u64,
}

// nccl = value+
// value = name schema? nl key*
// key = indent (name nl | indent value)
// name = not colon
// nl = newline
// schema = ":" name

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Parser {
            current: 0,
            path: vec![],
            tokens: tokens,
            pair: Pair::new("__top_level__"),
            line: 1,
        }
    }

    pub fn parse(&mut self) -> Result<Pair, NcclError> {
        while !self.is_at_end() {
            self.value()?;
            self.advance();
        }

        Ok(self.pair.clone())
    }

    fn add(&mut self, value: String) {
        //self.pair.add_vec(self.path, value);
    }

    fn value(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.name()?;

            if self.peek().kind == TokenKind::Colon {
                self.schema()?;
            }

            self.newline()?;

            while self.peek().kind != TokenKind::Indent {
                self.key()?;
            }

            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line))
        }
    }

    fn key(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.indent()?;

            if self.peek().kind == TokenKind::Value {
                self.name()?;
                self.newline()?;
            } else if self.peek().kind == TokenKind::Indent {
                self.indent()?;
                self.value()?;
            }

            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected key, found EOF", self.line))
        }
    }

    fn schema(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.colon()?;
            self.name()?;
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected schema, found EOF", self.line))
        }
    }

    fn name(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.advance();
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected name, found EOF", self.line))
        }
    }

    fn indent(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.advance();
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected indent, found EOF", self.line))
        }
    }

    fn newline(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.line += 1;
            self.advance();
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected newline, found EOF", self.line))
        }
    }

    fn colon(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            self.advance();
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected colon, found EOF", self.line))
        }
    }

    fn matches(&mut self, kind: TokenKind) -> bool {
        if self.check(kind) {
            self.advance();
            true
        } else {
            false
        }
    }

    fn check(&mut self, kind: TokenKind) -> bool {
        if self.is_at_end() {
            false
        } else {
            self.peek().kind == kind
        }
    }

    fn advance(&mut self) -> &Token {
        if !self.is_at_end() {
            self.current += 1;
        }

        self.previous()
    }

    fn is_at_end(&mut self) -> bool {
        self.peek().kind == TokenKind::EOF
    }

    fn peek(&mut self) -> &Token {
        &self.tokens[self.current]
    }

    fn previous(&mut self) -> &Token {
        &self.tokens[self.current - 1]
    }

    fn consume(&mut self, kind: TokenKind, message: &str) -> Result<&Token, NcclError> {
        if self.check(kind) {
            Ok(self.advance())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, message, self.line))
        }
    }
}

<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::fmt::Display;
use std::fs::{File, create_dir_all, set_permissions, metadata};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::{symlink, MetadataExt, PermissionsExt};
use std::path::Path;
use std::collections::{BTreeMap, BTreeSet};

use cronparse::Limited;
use cronparse::crontab::{CrontabEntry, SystemCrontabEntry, UserCrontabEntry};
use cronparse::schedule::{Schedule, Period, Calendar};
use cronparse::interval::Interval;

use users::{get_user_by_name, get_user_by_uid};

use super::{REBOOT_FILE, PACKAGE, LIB_DIR};

pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String>, path: &Path, dstdir: &Path) -> io::Result<()> {
    use cronparse::crontab::CrontabEntry::*;

    info!("generating units for {}: \"{}\", {:?}", path.display(), entry, env);

    let owner = try!(metadata(path)).uid();

    let mut persistent = env.get("PERSISTENT").and_then(|v| match &**v {
        "yes" | "true" | "1" => Some(true),
        "auto" | "" => None,
        _ => Some(false)
    }).unwrap_or_else(|| match entry {
        Anacron(_) | User(UserCrontabEntry { sched: Schedule::Period(_), .. }) | System(SystemCrontabEntry { sched: Schedule::Period(_), .. }) => true,
        _ => false
    });

    let batch = env.get("BATCH").map(|v| match &**v {
        "yes" | "true" | "1" => true,
        _ => false
    }).unwrap_or(false);

    let random_delay = env.get("RANDOM_DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(1);
    let mut delay = env.get("DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
    let hour = env.get("START_HOURS_RANGE").and_then(|v| v.splitn(1, '-').next().and_then(|v| v.parse::<u64>().ok())).unwrap_or(0);
    let shell = env.get("SHELL").map(|v| &**v).unwrap_or("/bin/sh");
    let daemon_reload = metadata(REBOOT_FILE).map(|m| m.is_file()).unwrap_or(false);

    let schedule = entry.period().and_then(|period| match *period {
        Period::Reboot => {
            persistent = false;
            if delay == 0 {
                delay = 1;
            }
            None
        },
        Period::Minutely => {
            persistent = false;
            Some("@minutely".to_owned())
        },
        Period::Hourly => {
            if delay == 0 {
                Some("@hourly".to_owned())
            } else {
                Some(format!("*-*-* *:{}:0", delay))
            }
        },
        Period::Midnight => {
            if delay == 0 {
                Some("@daily".to_owned())
            } else {
                Some(format!("*-*-* 0:{}:0", delay))
            }
        },
        Period::Daily => {
            if delay == 0 && hour == 0 {
                Some("@daily".to_owned())
            } else {
                Some(format!("*-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Weekly => {
            if delay == 0 && hour == 0 {
                Some("@weekly".to_owned())
            } else {
                Some(format!("Mon *-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Monthly => {
            if delay == 0 && hour == 0 {
                Some("@monthly".to_owned())
            } else {
                Some(format!("*-*-1 {}:{}:0", hour, delay))
            }
        },
        Period::Quaterly => {
            if delay == 0 && hour == 0 {
                Some("@quaterly".to_owned())
            } else {
                Some(format!("*-1,4,7,10-1 {}:{}:0", hour, delay))
            }
        },
        Period::Biannually => {
            if delay == 0 && hour == 0 {
                Some("@semi-annually".to_owned())
            } else {
                Some(format!("*-1,7-1 {}:{}:0", hour, delay))
            }
        },
        Period::Yearly => {
            if delay == 0 && hour == 0 {
                Some("@yearly".to_owned())
            } else {
                Some(format!("*-1-1 {}:{}:0", hour, delay))
            }
        },
        Period::Days(days) => {
            // workaround for anacrontab
            if days > 31 {
                Some(format!("*-1/{}-1 {}:{}:0", days / 30, hour, delay))
            } else {
                Some(format!("*-*-1/{} {}:{}:0", days, hour, delay))
            }
        },
    }).or_else(|| entry.calendar().and_then(|cal| {
        let Calendar {
            ref dows,
            ref days,
            ref mons,
            ref hrs,
            ref mins
        } = *cal;

        Some(format!("{} *-{}-{} {}:{}:00",
                     linearize(&**dows, ""),
                     linearize(&**mons, "*"),
                     linearize(&**days, "*"),
                     linearize(&**hrs, "*"),
                     linearize(&**mins, "*")))
    }));

    if daemon_reload && schedule.is_none() {
        warn!("skipping job from {}: \"{}\"", path.display(), entry);
        return Ok(());
    }

    if let Some(cmd) = entry.command() {

        // make sure we know the user
        let user = try!(entry.user().and_then(get_user_by_name).or_else(|| get_user_by_uid(owner))
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "unknown user")));

        // generate unique cron job id
        let mut md5ctx = ::md5::Context::new();
        md5ctx.consume(path.as_os_str().as_bytes());
        if let Some(ref schedule) = schedule {
            md5ctx.consume(schedule.as_bytes());
        }
        md5ctx.consume(cmd.as_bytes());
        let md5hex = tohex(&md5ctx.compute());

        // create service and timer unit names
        let service_unit_name = format!("cron-{}.service", md5hex);
        let timer_unit_name = format!("cron-{}.timer", md5hex);

        // unit paths
        let service_unit_path = dstdir.join(&service_unit_name);
        let timer_unit_path = dstdir.join(&timer_unit_name);

        // make sure cron.target.wants dir exists
        let cron_target_wants_path = dstdir.join("cron.target.wants");
        try!(create_dir_all(&cron_target_wants_path));

        // process command in case it should be put into script
        let command = if metadata(cmd).map(|m| m.is_file()).unwrap_or(false) {
            cmd.to_owned()
        } else {
            let script_command_path = dstdir.join(format!("cron-{}.sh", md5hex));

            debug!("generating script {:?} from {:?}", script_command_path, path);
            {
                let mut script_command_file = try!(File::create(&script_command_path));
                try!(writeln!(script_command_file, "#!{}", shell));
                try!(writeln!(script_command_file, "{}", cmd));
            }

            let mut perms = try!(metadata(&script_command_path)).permissions();
            perms.set_mode(0o755);
            try!(set_permissions(&script_command_path, perms));
            script_command_path.to_str().unwrap().to_owned()
        };

        debug!("generating service {:?} from {:?}", service_unit_path, path);
        {
            let mut service_unit_file = try!(File::create(service_unit_path));

            try!(writeln!(service_unit_file, r###"[Unit]
Description=[Cron] "{entry}"
Documentation=man:systemd-crontab-generator(8)
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}"###,
                entry = entry,
                source_crontab_path = path.display(),
                ));

            if env.contains_key("MAILTO") {
                try!(writeln!(service_unit_file, "OnFailure=cron-failure@%i.service"));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "Requires=systemd-user-sessions.service"));
                if !user.home_dir.is_empty() {
                    try!(writeln!(service_unit_file, "RequiresMountsFor={}", user.home_dir));
                }
            }

            try!(writeln!(service_unit_file, r###"
[Service]
Type=oneshot
IgnoreSIGPIPE=false
ExecStart={command}"###,
                command = command,
                ));

            if schedule.is_some() && delay > 0 {
                try!(writeln!(service_unit_file, "ExecStartPre=-{}/{}/boot-delay {}", LIB_DIR, PACKAGE, delay));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "User={}", user.name));
            }

            if let Some(group) = entry.group() {
                try!(writeln!(service_unit_file, "Group={}", group));
            }
            if batch {
                try!(writeln!(service_unit_file, "CPUSchedulingPolicy=idle"));
                try!(writeln!(service_unit_file, "IOSchedulingClass=idle"));
            }

            if !env.is_empty() {
                try!(write!(service_unit_file, "Environment="));
                for (name, value) in env.iter() {
                    try!(write!(service_unit_file, r#""{}={}""#, name, value));
                }
                try!(write!(service_unit_file, "\n"));
            }
        }

        debug!("generating timer {:?} from {:?}", timer_unit_path, path);
        {
            let mut timer_unit_file = try!(File::create(&timer_unit_path));

            try!(writeln!(timer_unit_file, r###"[Unit]
Description=[Timer] "{entry}"
Documentation=man:systemd-crontab-generator(8)
PartOf=cron.target
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}

[Timer]
Unit={service_unit_name}"###,
                entry = entry,
                source_crontab_path = path.display(),
                service_unit_name = service_unit_name,
                ));

            if cfg![feature="persistent"] {
                try!(writeln!(timer_unit_file, "Persistent={}", persistent));
            }

            if let Some(schedule) = schedule {
                try!(writeln!(timer_unit_file, "OnCalendar={}", schedule));
            } else {
                try!(writeln!(timer_unit_file, "OnBootSec={}m", delay));
            }

            if random_delay != 1 {
                try!(writeln!(timer_unit_file, "AccuracySec={}m", random_delay));
            }
        }
        try!(symlink(timer_unit_path, cron_target_wants_path.join(timer_unit_name)));
    }

    Ok(())
}

fn linearize<T: Limited + Display>(input: &[Interval<T>], star: &str) -> String {
    if input.len() == 1 && input[0] == Interval::Full(1) {
        star.to_owned()
    } else {
        let mut output = String::new();
        for part in input.iter().flat_map(|v| v.iter()).collect::<BTreeSet<_>>().iter() {
            output.push_str(&*part.to_string());
            output.push(',');
        }
        output.pop();
        output
    }
}

fn tohex(input: &[u8]) -> String {
    #[inline]
    fn hex(d: u8) -> char {
        match d {
            0...9 => (d + 0x30) as char,
            10...15 => (d + 0x57) as char,
            _ => unreachable!("unexpected value: {}", d)
        }
    }

    let mut buf = String::with_capacity(32);
    for b in input.into_iter() {
        buf.push(hex(b >> 4));
        buf.push(hex(b & 0xf));
    }
    buf
}

<commit_msg>add space between environment vars (#28)<commit_after>use std::io::{self, Write};
use std::fmt::Display;
use std::fs::{File, create_dir_all, set_permissions, metadata};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::{symlink, MetadataExt, PermissionsExt};
use std::path::Path;
use std::collections::{BTreeMap, BTreeSet};

use cronparse::Limited;
use cronparse::crontab::{CrontabEntry, SystemCrontabEntry, UserCrontabEntry};
use cronparse::schedule::{Schedule, Period, Calendar};
use cronparse::interval::Interval;

use users::{get_user_by_name, get_user_by_uid};

use super::{REBOOT_FILE, PACKAGE, LIB_DIR};

pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String>, path: &Path, dstdir: &Path) -> io::Result<()> {
    use cronparse::crontab::CrontabEntry::*;

    info!("generating units for {}: \"{}\", {:?}", path.display(), entry, env);

    let owner = try!(metadata(path)).uid();

    let mut persistent = env.get("PERSISTENT").and_then(|v| match &**v {
        "yes" | "true" | "1" => Some(true),
        "auto" | "" => None,
        _ => Some(false)
    }).unwrap_or_else(|| match entry {
        Anacron(_) | User(UserCrontabEntry { sched: Schedule::Period(_), .. }) | System(SystemCrontabEntry { sched: Schedule::Period(_), .. }) => true,
        _ => false
    });

    let batch = env.get("BATCH").map(|v| match &**v {
        "yes" | "true" | "1" => true,
        _ => false
    }).unwrap_or(false);

    let random_delay = env.get("RANDOM_DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(1);
    let mut delay = env.get("DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
    let hour = env.get("START_HOURS_RANGE").and_then(|v| v.splitn(1, '-').next().and_then(|v| v.parse::<u64>().ok())).unwrap_or(0);
    let shell = env.get("SHELL").map(|v| &**v).unwrap_or("/bin/sh");
    let daemon_reload = metadata(REBOOT_FILE).map(|m| m.is_file()).unwrap_or(false);

    let schedule = entry.period().and_then(|period| match *period {
        Period::Reboot => {
            persistent = false;
            if delay == 0 {
                delay = 1;
            }
            None
        },
        Period::Minutely => {
            persistent = false;
            Some("@minutely".to_owned())
        },
        Period::Hourly => {
            if delay == 0 {
                Some("@hourly".to_owned())
            } else {
                Some(format!("*-*-* *:{}:0", delay))
            }
        },
        Period::Midnight => {
            if delay == 0 {
                Some("@daily".to_owned())
            } else {
                Some(format!("*-*-* 0:{}:0", delay))
            }
        },
        Period::Daily => {
            if delay == 0 && hour == 0 {
                Some("@daily".to_owned())
            } else {
                Some(format!("*-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Weekly => {
            if delay == 0 && hour == 0 {
                Some("@weekly".to_owned())
            } else {
                Some(format!("Mon *-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Monthly => {
            if delay == 0 && hour == 0 {
                Some("@monthly".to_owned())
            } else {
                Some(format!("*-*-1 {}:{}:0", hour, delay))
            }
        },
        Period::Quaterly => {
            if delay == 0 && hour == 0 {
                Some("@quaterly".to_owned())
            } else {
                Some(format!("*-1,4,7,10-1 {}:{}:0", hour, delay))
            }
        },
        Period::Biannually => {
            if delay == 0 && hour == 0 {
                Some("@semi-annually".to_owned())
            } else {
                Some(format!("*-1,7-1 {}:{}:0", hour, delay))
            }
        },
        Period::Yearly => {
            if delay == 0 && hour == 0 {
                Some("@yearly".to_owned())
            } else {
                Some(format!("*-1-1 {}:{}:0", hour, delay))
            }
        },
        Period::Days(days) => {
            // workaround for anacrontab
            if days > 31 {
                Some(format!("*-1/{}-1 {}:{}:0", days / 30, hour, delay))
            } else {
                Some(format!("*-*-1/{} {}:{}:0", days, hour, delay))
            }
        },
    }).or_else(|| entry.calendar().and_then(|cal| {
        let Calendar {
            ref dows,
            ref days,
            ref mons,
            ref hrs,
            ref mins
        } = *cal;

        Some(format!("{} *-{}-{} {}:{}:00",
                     linearize(&**dows, ""),
                     linearize(&**mons, "*"),
                     linearize(&**days, "*"),
                     linearize(&**hrs, "*"),
                     linearize(&**mins, "*")))
    }));

    if daemon_reload && schedule.is_none() {
        warn!("skipping job from {}: \"{}\"", path.display(), entry);
        return Ok(());
    }

    if let Some(cmd) = entry.command() {

        // make sure we know the user
        let user = try!(entry.user().and_then(get_user_by_name).or_else(|| get_user_by_uid(owner))
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "unknown user")));

        // generate unique cron job id
        let mut md5ctx = ::md5::Context::new();
        md5ctx.consume(path.as_os_str().as_bytes());
        if let Some(ref schedule) = schedule {
            md5ctx.consume(schedule.as_bytes());
        }
        md5ctx.consume(cmd.as_bytes());
        let md5hex = tohex(&md5ctx.compute());

        // create service and timer unit names
        let service_unit_name = format!("cron-{}.service", md5hex);
        let timer_unit_name = format!("cron-{}.timer", md5hex);

        // unit paths
        let service_unit_path = dstdir.join(&service_unit_name);
        let timer_unit_path = dstdir.join(&timer_unit_name);

        // make sure cron.target.wants dir exists
        let cron_target_wants_path = dstdir.join("cron.target.wants");
        try!(create_dir_all(&cron_target_wants_path));

        // process command in case it should be put into script
        let command = if metadata(cmd).map(|m| m.is_file()).unwrap_or(false) {
            cmd.to_owned()
        } else {
            let script_command_path = dstdir.join(format!("cron-{}.sh", md5hex));

            debug!("generating script {:?} from {:?}", script_command_path, path);
            {
                let mut script_command_file = try!(File::create(&script_command_path));
                try!(writeln!(script_command_file, "#!{}", shell));
                try!(writeln!(script_command_file, "{}", cmd));
            }

            let mut perms = try!(metadata(&script_command_path)).permissions();
            perms.set_mode(0o755);
            try!(set_permissions(&script_command_path, perms));
            script_command_path.to_str().unwrap().to_owned()
        };

        debug!("generating service {:?} from {:?}", service_unit_path, path);
        {
            let mut service_unit_file = try!(File::create(service_unit_path));

            try!(writeln!(service_unit_file, r###"[Unit]
Description=[Cron] "{entry}"
Documentation=man:systemd-crontab-generator(8)
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}"###,
                entry = entry,
                source_crontab_path = path.display(),
                ));

            if env.contains_key("MAILTO") {
                try!(writeln!(service_unit_file, "OnFailure=cron-failure@%i.service"));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "Requires=systemd-user-sessions.service"));
                if !user.home_dir.is_empty() {
                    try!(writeln!(service_unit_file, "RequiresMountsFor={}", user.home_dir));
                }
            }

            try!(writeln!(service_unit_file, r###"
[Service]
Type=oneshot
IgnoreSIGPIPE=false
ExecStart={command}"###,
                command = command,
                ));

            if schedule.is_some() && delay > 0 {
                try!(writeln!(service_unit_file, "ExecStartPre=-{}/{}/boot-delay {}", LIB_DIR, PACKAGE, delay));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "User={}", user.name));
            }

            if let Some(group) = entry.group() {
                try!(writeln!(service_unit_file, "Group={}", group));
            }
            if batch {
                try!(writeln!(service_unit_file, "CPUSchedulingPolicy=idle"));
                try!(writeln!(service_unit_file, "IOSchedulingClass=idle"));
            }

            if !env.is_empty() {
                try!(write!(service_unit_file, "Environment="));
                for (name, value) in env.iter() {
                    try!(write!(service_unit_file, r#""{}={}" "#, name, value));
                }
                try!(write!(service_unit_file, "\n"));
            }
        }

        debug!("generating timer {:?} from {:?}", timer_unit_path, path);
        {
            let mut timer_unit_file = try!(File::create(&timer_unit_path));

            try!(writeln!(timer_unit_file, r###"[Unit]
Description=[Timer] "{entry}"
Documentation=man:systemd-crontab-generator(8)
PartOf=cron.target
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}

[Timer]
Unit={service_unit_name}"###,
                entry = entry,
                source_crontab_path = path.display(),
                service_unit_name = service_unit_name,
                ));

            if cfg![feature="persistent"] {
                try!(writeln!(timer_unit_file, "Persistent={}", persistent));
            }

            if let Some(schedule) = schedule {
                try!(writeln!(timer_unit_file, "OnCalendar={}", schedule));
            } else {
                try!(writeln!(timer_unit_file, "OnBootSec={}m", delay));
            }

            if random_delay != 1 {
                try!(writeln!(timer_unit_file, "AccuracySec={}m", random_delay));
            }
        }
        try!(symlink(timer_unit_path, cron_target_wants_path.join(timer_unit_name)));
    }

    Ok(())
}

fn linearize<T: Limited + Display>(input: &[Interval<T>], star: &str) -> String {
    if input.len() == 1 && input[0] == Interval::Full(1) {
        star.to_owned()
    } else {
        let mut output = String::new();
        for part in input.iter().flat_map(|v| v.iter()).collect::<BTreeSet<_>>().iter() {
            output.push_str(&*part.to_string());
            output.push(',');
        }
        output.pop();
        output
    }
}

fn tohex(input: &[u8]) -> String {
    #[inline]
    fn hex(d: u8) -> char {
        match d {
            0...9 => (d + 0x30) as char,
            10...15 => (d + 0x57) as char,
            _ => unreachable!("unexpected value: {}", d)
        }
    }

    let mut buf = String::with_capacity(32);
    for b in input.into_iter() {
        buf.push(hex(b >> 4));
        buf.push(hex(b & 0xf));
    }
    buf
}

<|endoftext|>