<commit_before>#[macro_use]
extern crate mopa;
extern crate pulse;
extern crate threadpool;
extern crate fnv;

use std::any::TypeId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use mopa::Any;
use pulse::{Pulse, Signal};
use threadpool::ThreadPool;

pub use storage::{Storage, StorageBase, VecStorage, HashMapStorage};

mod storage;

/// Index generation. When a new entity is placed at the old index,
/// it bumps the generation by 1. This allows to avoid using components
/// from the entities that were deleted.
/// G<=0 - the entity of generation G is dead
/// G >0 - the entity of generation G is alive
pub type Generation = i32;
/// Index type is arbitrary. It doesn't show up in any interfaces.
/// Keeping it 32bit allows for a single 64bit word per entity.
pub type Index = u32;
/// Entity type, as seen by the user.
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity(Index, Generation);

impl Entity {
    #[cfg(test)]
    /// Create a new entity (externally from ECS)
    pub fn new(index: u32, gen: i32) -> Entity {
        Entity(index, gen)
    }

    /// Get the index of the entity.
    pub fn get_id(&self) -> usize { self.0 as usize }
    /// Get the generation of the entity.
    pub fn get_gen(&self) -> Generation { self.1 }
}

/// A custom entity iterator. Needed because the world doesn't really store
/// entities directly, but rather has just a vector of Index -> Generation.
pub struct EntityIter<'a> {
    guard: RwLockReadGuard<'a, Vec<Generation>>,
    index: usize,
}

impl<'a> Iterator for EntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        loop {
            match self.guard.get(self.index) {
                Some(&gen) if gen > 0 => {
                    let ent = Entity(self.index as Index, gen);
                    self.index += 1;
                    return Some(ent)
                },
                Some(_) => self.index += 1, // continue
                None => return None,
            }
        }
    }
}

/// Abstract component type. Doesn't have to be Copy or even Clone.
pub trait Component: Any + Sized {
    type Storage: Storage<Self> + Any + Send + Sync;
}

trait StorageLock: Any + Send + Sync {
    fn del_slice(&self, &[Entity]);
}

mopafy!(StorageLock);

impl<S: StorageBase + Any + Send + Sync> StorageLock for RwLock<S> {
    fn del_slice(&self, entities: &[Entity]) {
        let mut guard = self.write().unwrap();
        for &e in entities.iter() {
            guard.del(e);
        }
    }
}

struct Appendix {
    next: Entity,
    add_queue: Vec<Entity>,
    sub_queue: Vec<Entity>
}

/// The world struct contains all the data, which is entities and their components.
/// The methods are supposed to be valid for any context they are available in.
pub struct World {
    generations: RwLock<Vec<Generation>>,
    components: HashMap<TypeId, Box<StorageLock>>,
    appendix: RwLock<Appendix>,
}

impl World {
    /// Create a new empty world.
    pub fn new() -> World {
        World {
            generations: RwLock::new(Vec::new()),
            components: HashMap::new(),
            appendix: RwLock::new(Appendix {
                next: Entity(0, 1),
                add_queue: Vec::new(),
                sub_queue: Vec::new(),
            }),
        }
    }
    /// Register a new component type.
    pub fn register<T: Component>(&mut self) {
        let any = RwLock::new(T::Storage::new());
        self.components.insert(TypeId::of::<T>(), Box::new(any));
    }
    /// Unregister a component type.
    pub fn unregister<T: Component>(&mut self) -> Option<T::Storage> {
        self.components.remove(&TypeId::of::<T>()).map(|boxed|
            match boxed.downcast::<RwLock<T::Storage>>() {
                Ok(b) => (*b).into_inner().unwrap(),
                Err(_) => panic!("Unable to downcast the storage type"),
            }
        )
    }
    fn lock<T: Component>(&self) -> &RwLock<T::Storage> {
        let boxed = self.components.get(&TypeId::of::<T>()).unwrap();
        boxed.downcast_ref().unwrap()
    }
    /// Lock a component for reading.
    pub fn read<'a, T: Component>(&'a self) -> RwLockReadGuard<'a, T::Storage> {
        self.lock::<T>().read().unwrap()
    }
    /// Lock a component for writing.
    pub fn write<'a, T: Component>(&'a self) -> RwLockWriteGuard<'a, T::Storage> {
        self.lock::<T>().write().unwrap()
    }
    /// Return the entity iterator.
    pub fn entities<'a>(&'a self) -> EntityIter<'a> {
        EntityIter {
            guard: self.generations.read().unwrap(),
            index: 0,
        }
    }
    fn find_next(&self, base: usize) -> Entity {
        let gens = self.generations.read().unwrap();
        match gens.iter().enumerate().skip(base).find(|&(_, g)| *g <= 0) {
            Some((id, gen)) => Entity(id as Index, 1 - gen),
            None => Entity(gens.len() as Index, 1),
        }
    }
    /// Return the generations array locked for reading. Useful for debugging.
    pub fn get_generations<'a>(&'a self) -> RwLockReadGuard<'a, Vec<Generation>> {
        self.generations.read().unwrap()
    }
}

/// A custom entity iterator for dynamically added entities.
pub struct NewEntityIter<'a> {
    guard: RwLockReadGuard<'a, Appendix>,
    index: usize,
}

impl<'a> Iterator for NewEntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        let ent = self.guard.add_queue.get(self.index);
        self.index += 1;
        ent.map(|e| *e)
    }
}

/// World argument for a system closure.
pub struct WorldArg {
    world: Arc<World>,
    pulse: RefCell<Option<Pulse>>,
}

impl WorldArg {
    /// Borrows the world, allowing the system lock some components and get the entity
    /// iterator. Has to be called only once. Fires a pulse at the end.
    pub fn fetch<'a, U, F>(&'a self, f: F) -> U
        where F: FnOnce(&'a World) -> U
    {
        let pulse = self.pulse.borrow_mut().take()
                        .expect("fetch may only be called once.");
        let u = f(&self.world);
        pulse.pulse();
        u
    }
    /// Create a new entity dynamically.
    pub fn create(&self) -> Entity {
        let mut app = self.world.appendix.write().unwrap();
        let ent = app.next;
        app.add_queue.push(ent);
        app.next = self.world.find_next(ent.get_id() + 1);
        ent
    }
    /// Delete an entity dynamically.
    pub fn delete(&self, entity: Entity) {
        let mut app = self.world.appendix.write().unwrap();
        app.sub_queue.push(entity);
    }
    /// Iterate dynamically added entities.
    pub fn new_entities<'a>(&'a self) -> NewEntityIter<'a> {
        NewEntityIter {
            guard: self.world.appendix.read().unwrap(),
            index: 0,
        }
    }
}

/// Helper builder for entities.
pub struct EntityBuilder<'a>(Entity, &'a World);

impl<'a> EntityBuilder<'a> {
    /// Add a component value to the new entity.
    pub fn with<T: Component>(self, value: T) -> EntityBuilder<'a> {
        self.1.write::<T>().insert(self.0, value);
        self
    }
    /// Finish entity construction.
    pub fn build(self) -> Entity {
        self.0
    }
}

pub struct Scheduler {
    world: Arc<World>,
    threads: ThreadPool,
}

impl Scheduler {
    pub fn new(world: World, num_threads: usize) -> Scheduler {
        Scheduler {
            world: Arc::new(world),
            threads: ThreadPool::new(num_threads),
        }
    }
    pub fn get_world(&self) -> &World {
        &self.world
    }
    pub fn run<F>(&mut self, functor: F) where
        F: 'static + Send + FnOnce(WorldArg)
    {
        let (signal, pulse) = Signal::new();
        let world = self.world.clone();
        self.threads.execute(|| {
            functor(WorldArg {
                world: world,
                pulse: RefCell::new(Some(pulse)),
            });
        });
        signal.wait().unwrap();
    }
    pub fn add_entity<'a>(&'a mut self) -> EntityBuilder<'a> {
        let mut appendix = self.world.appendix.write().unwrap();
        let ent = appendix.next;
        assert!(ent.get_gen() > 0);
        if ent.get_gen() == 1 {
            let mut gens = self.world.generations.write().unwrap();
            assert!(gens.len() == ent.get_id());
            gens.push(ent.get_gen());
        }
        appendix.next = self.world.find_next(ent.get_id() + 1);
        EntityBuilder(ent, &self.world)
    }
    pub fn del_entity(&mut self, entity: Entity) {
        for boxed in self.world.components.values() {
            boxed.del_slice(&[entity]);
        }
        let mut gens = self.world.generations.write().unwrap();
        let mut gen = &mut gens[entity.get_id() as usize];
        assert!(*gen > 0);
        let mut app = self.world.appendix.write().unwrap();
        if entity.get_id() < app.next.get_id() {
            app.next = Entity(entity.0, *gen+1);
        }
        *gen *= -1;
    }
    pub fn rest(&self) {
        let mut gens = self.world.generations.write().unwrap();
        let mut app = self.world.appendix.write().unwrap();
        for ent in app.add_queue.drain(..) {
            while gens.len() <= ent.get_id() {
                gens.push(0);
            }
            assert_eq!(ent.get_gen(), 1 - gens[ent.get_id()]);
            gens[ent.get_id()] = ent.get_gen();
        }
        let mut next = app.next;
        for ent in app.sub_queue.drain(..) {
            assert_eq!(ent.get_gen(), gens[ent.get_id()]);
            if ent.get_id() < next.get_id() {
                next = Entity(ent.0, ent.1 + 1);
            }
            gens[ent.get_id()] *= -1;
        }
        app.next = next;
    }
}

macro_rules! impl_run {
    ($name:ident [$( $write:ident ),*] [$( $read:ident ),*]) => (impl Scheduler {
        #[allow(non_snake_case, unused_mut)]
        pub fn $name<
            $($write:Component,)* $($read:Component,)*
            F: 'static + Send + FnMut( $(&mut $write,)* $(&$read,)* )
        >(&mut self, functor: F) {
            self.run(|warg| {
                let mut fun = functor;
                let ($(mut $write,)* $($read,)* entities) = warg.fetch(|w|
                    ($(w.write::<$write>(),)*
                     $(w.read::<$read>(),)*
                       w.entities())
                );
                for ent in entities {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
                for ent in warg.new_entities() {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
            });
        }
    })
}

impl_run!( run0w1r [] [R0] );
impl_run!( run0w2r [] [R0, R1] );
impl_run!( run1w0r [W0] [] );
impl_run!( run1w1r [W0] [R0] );
impl_run!( run1w2r [W0] [R0, R1] );
impl_run!( run1w3r [W0] [R0, R1, R2] );
impl_run!( run1w4r [W0] [R0, R1, R2, R3] );
impl_run!( run1w5r [W0] [R0, R1, R2, R3, R4] );
impl_run!( run1w6r [W0] [R0, R1, R2, R3, R4, R5] );
impl_run!( run1w7r [W0] [R0, R1, R2, R3, R5, R6, R7] );
impl_run!( run2w0r [W0, W1] [] );
impl_run!( run2w1r [W0, W1] [R0] );
impl_run!( run2w2r [W0, W1] [R0, R1] );
<commit_msg>Improved rest() and moved into the World<commit_after>#[macro_use]
extern crate mopa;
extern crate pulse;
extern crate threadpool;
extern crate fnv;

use std::any::TypeId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use mopa::Any;
use pulse::{Pulse, Signal};
use threadpool::ThreadPool;

pub use storage::{Storage, StorageBase, VecStorage, HashMapStorage};

mod storage;

/// Index generation. When a new entity is placed at the old index,
/// it bumps the generation by 1. This allows to avoid using components
/// from the entities that were deleted.
/// G<=0 - the entity of generation G is dead
/// G >0 - the entity of generation G is alive
pub type Generation = i32;
/// Index type is arbitrary. It doesn't show up in any interfaces.
/// Keeping it 32bit allows for a single 64bit word per entity.
pub type Index = u32;
/// Entity type, as seen by the user.
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity(Index, Generation);

impl Entity {
    #[cfg(test)]
    /// Create a new entity (externally from ECS)
    pub fn new(index: u32, gen: i32) -> Entity {
        Entity(index, gen)
    }

    /// Get the index of the entity.
    pub fn get_id(&self) -> usize { self.0 as usize }
    /// Get the generation of the entity.
    pub fn get_gen(&self) -> Generation { self.1 }
}

/// A custom entity iterator. Needed because the world doesn't really store
/// entities directly, but rather has just a vector of Index -> Generation.
pub struct EntityIter<'a> {
    guard: RwLockReadGuard<'a, Vec<Generation>>,
    index: usize,
}

impl<'a> Iterator for EntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        loop {
            match self.guard.get(self.index) {
                Some(&gen) if gen > 0 => {
                    let ent = Entity(self.index as Index, gen);
                    self.index += 1;
                    return Some(ent)
                },
                Some(_) => self.index += 1, // continue
                None => return None,
            }
        }
    }
}

/// Abstract component type. Doesn't have to be Copy or even Clone.
pub trait Component: Any + Sized {
    type Storage: Storage<Self> + Any + Send + Sync;
}

trait StorageLock: Any + Send + Sync {
    fn del_slice(&self, &[Entity]);
}

mopafy!(StorageLock);

impl<S: StorageBase + Any + Send + Sync> StorageLock for RwLock<S> {
    fn del_slice(&self, entities: &[Entity]) {
        let mut guard = self.write().unwrap();
        for &e in entities.iter() {
            guard.del(e);
        }
    }
}

struct Appendix {
    next: Entity,
    add_queue: Vec<Entity>,
    sub_queue: Vec<Entity>
}

/// The world struct contains all the data, which is entities and their components.
/// The methods are supposed to be valid for any context they are available in.
pub struct World {
    generations: RwLock<Vec<Generation>>,
    components: HashMap<TypeId, Box<StorageLock>>,
    appendix: RwLock<Appendix>,
}

impl World {
    /// Create a new empty world.
    pub fn new() -> World {
        World {
            generations: RwLock::new(Vec::new()),
            components: HashMap::new(),
            appendix: RwLock::new(Appendix {
                next: Entity(0, 1),
                add_queue: Vec::new(),
                sub_queue: Vec::new(),
            }),
        }
    }
    /// Register a new component type.
    pub fn register<T: Component>(&mut self) {
        let any = RwLock::new(T::Storage::new());
        self.components.insert(TypeId::of::<T>(), Box::new(any));
    }
    /// Unregister a component type.
    pub fn unregister<T: Component>(&mut self) -> Option<T::Storage> {
        self.components.remove(&TypeId::of::<T>()).map(|boxed|
            match boxed.downcast::<RwLock<T::Storage>>() {
                Ok(b) => (*b).into_inner().unwrap(),
                Err(_) => panic!("Unable to downcast the storage type"),
            }
        )
    }
    fn lock<T: Component>(&self) -> &RwLock<T::Storage> {
        let boxed = self.components.get(&TypeId::of::<T>()).unwrap();
        boxed.downcast_ref().unwrap()
    }
    /// Lock a component for reading.
    pub fn read<'a, T: Component>(&'a self) -> RwLockReadGuard<'a, T::Storage> {
        self.lock::<T>().read().unwrap()
    }
    /// Lock a component for writing.
    pub fn write<'a, T: Component>(&'a self) -> RwLockWriteGuard<'a, T::Storage> {
        self.lock::<T>().write().unwrap()
    }
    /// Return the entity iterator.
    pub fn entities<'a>(&'a self) -> EntityIter<'a> {
        EntityIter {
            guard: self.generations.read().unwrap(),
            index: 0,
        }
    }
    fn find_next(&self, base: usize) -> Entity {
        let gens = self.generations.read().unwrap();
        match gens.iter().enumerate().skip(base).find(|&(_, g)| *g <= 0) {
            Some((id, gen)) => Entity(id as Index, 1 - gen),
            None => Entity(gens.len() as Index, 1),
        }
    }
    /// Merge in the appendix, recording all the dynamically created
    /// and deleted entities into the persistent generations vector.
    /// Also removes all the abandoned components.
    pub fn merge(&self) {
        let mut gens = self.generations.write().unwrap();
        let mut app = self.appendix.write().unwrap();
        for ent in app.add_queue.drain(..) {
            while gens.len() <= ent.get_id() {
                gens.push(0);
            }
            assert_eq!(ent.get_gen(), 1 - gens[ent.get_id()]);
            gens[ent.get_id()] = ent.get_gen();
        }
        let mut next = app.next;
        for comp in self.components.values() {
            comp.del_slice(&app.sub_queue);
        }
        for ent in app.sub_queue.drain(..) {
            assert_eq!(ent.get_gen(), gens[ent.get_id()]);
            if ent.get_id() < next.get_id() {
                next = Entity(ent.0, ent.1 + 1);
            }
            gens[ent.get_id()] *= -1;
        }
        app.next = next;
    }
    /// Return the generations array locked for reading. Useful for debugging.
    pub fn get_generations<'a>(&'a self) -> RwLockReadGuard<'a, Vec<Generation>> {
        self.generations.read().unwrap()
    }
}

/// A custom entity iterator for dynamically added entities.
pub struct NewEntityIter<'a> {
    guard: RwLockReadGuard<'a, Appendix>,
    index: usize,
}

impl<'a> Iterator for NewEntityIter<'a> {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        let ent = self.guard.add_queue.get(self.index);
        self.index += 1;
        ent.map(|e| *e)
    }
}

/// World argument for a system closure.
pub struct WorldArg {
    world: Arc<World>,
    pulse: RefCell<Option<Pulse>>,
}

impl WorldArg {
    /// Borrows the world, allowing the system lock some components and get the entity
    /// iterator. Has to be called only once. Fires a pulse at the end.
    pub fn fetch<'a, U, F>(&'a self, f: F) -> U
        where F: FnOnce(&'a World) -> U
    {
        let pulse = self.pulse.borrow_mut().take()
                        .expect("fetch may only be called once.");
        let u = f(&self.world);
        pulse.pulse();
        u
    }
    /// Create a new entity dynamically.
    pub fn create(&self) -> Entity {
        let mut app = self.world.appendix.write().unwrap();
        let ent = app.next;
        app.add_queue.push(ent);
        app.next = self.world.find_next(ent.get_id() + 1);
        ent
    }
    /// Delete an entity dynamically.
    pub fn delete(&self, entity: Entity) {
        let mut app = self.world.appendix.write().unwrap();
        app.sub_queue.push(entity);
    }
    /// Iterate dynamically added entities.
    pub fn new_entities<'a>(&'a self) -> NewEntityIter<'a> {
        NewEntityIter {
            guard: self.world.appendix.read().unwrap(),
            index: 0,
        }
    }
}

/// Helper builder for entities.
pub struct EntityBuilder<'a>(Entity, &'a World);

impl<'a> EntityBuilder<'a> {
    /// Add a component value to the new entity.
    pub fn with<T: Component>(self, value: T) -> EntityBuilder<'a> {
        self.1.write::<T>().insert(self.0, value);
        self
    }
    /// Finish entity construction.
    pub fn build(self) -> Entity {
        self.0
    }
}

pub struct Scheduler {
    world: Arc<World>,
    threads: ThreadPool,
}

impl Scheduler {
    pub fn new(world: World, num_threads: usize) -> Scheduler {
        Scheduler {
            world: Arc::new(world),
            threads: ThreadPool::new(num_threads),
        }
    }
    pub fn get_world(&self) -> &World {
        &self.world
    }
    pub fn run<F>(&mut self, functor: F) where
        F: 'static + Send + FnOnce(WorldArg)
    {
        let (signal, pulse) = Signal::new();
        let world = self.world.clone();
        self.threads.execute(|| {
            functor(WorldArg {
                world: world,
                pulse: RefCell::new(Some(pulse)),
            });
        });
        signal.wait().unwrap();
    }
    pub fn add_entity<'a>(&'a mut self) -> EntityBuilder<'a> {
        let mut appendix = self.world.appendix.write().unwrap();
        let ent = appendix.next;
        assert!(ent.get_gen() > 0);
        if ent.get_gen() == 1 {
            let mut gens = self.world.generations.write().unwrap();
            assert!(gens.len() == ent.get_id());
            gens.push(ent.get_gen());
        }
        appendix.next = self.world.find_next(ent.get_id() + 1);
        EntityBuilder(ent, &self.world)
    }
    pub fn del_entity(&mut self, entity: Entity) {
        for boxed in self.world.components.values() {
            boxed.del_slice(&[entity]);
        }
        let mut gens = self.world.generations.write().unwrap();
        let mut gen = &mut gens[entity.get_id() as usize];
        assert!(*gen > 0);
        let mut app = self.world.appendix.write().unwrap();
        if entity.get_id() < app.next.get_id() {
            app.next = Entity(entity.0, *gen+1);
        }
        *gen *= -1;
    }
    pub fn rest(&mut self) {
        self.world.merge();
    }
}

macro_rules! impl_run {
    ($name:ident [$( $write:ident ),*] [$( $read:ident ),*]) => (impl Scheduler {
        #[allow(non_snake_case, unused_mut)]
        pub fn $name<
            $($write:Component,)* $($read:Component,)*
            F: 'static + Send + FnMut( $(&mut $write,)* $(&$read,)* )
        >(&mut self, functor: F) {
            self.run(|warg| {
                let mut fun = functor;
                let ($(mut $write,)* $($read,)* entities) = warg.fetch(|w|
                    ($(w.write::<$write>(),)*
                     $(w.read::<$read>(),)*
                       w.entities())
                );
                for ent in entities {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
                for ent in warg.new_entities() {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
            });
        }
    })
}

impl_run!( run0w1r [] [R0] );
impl_run!( run0w2r [] [R0, R1] );
impl_run!( run1w0r [W0] [] );
impl_run!( run1w1r [W0] [R0] );
impl_run!( run1w2r [W0] [R0, R1] );
impl_run!( run1w3r [W0] [R0, R1, R2] );
impl_run!( run1w4r [W0] [R0, R1, R2, R3] );
impl_run!( run1w5r [W0] [R0, R1, R2, R3, R4] );
impl_run!( run1w6r [W0] [R0, R1, R2, R3, R4, R5] );
impl_run!( run1w7r [W0] [R0, R1, R2, R3, R5, R6, R7] );
impl_run!( run2w0r [W0, W1] [] );
impl_run!( run2w1r [W0, W1] [R0] );
impl_run!( run2w2r [W0, W1] [R0, R1] );
<|endoftext|>


<commit_before>//! A [TOML]-parsing library
//!
//! This library implements a [TOML] v0.5.0 compatible parser,
//! primarily supporting the [`serde`] library for encoding/decoding
//! various types in Rust.
//!
//! TOML itself is a simple, ergonomic, and readable configuration format:
//!
//! ```toml
//! [package]
//! name = "toml"
//! version = "0.4.2"
//! authors = ["Alex Crichton <alex@alexcrichton.com>"]
//!
//! [dependencies]
//! serde = "1.0"
//! ```
//!
//! The TOML format tends to be relatively common throughout the Rust community
//! for configuration, notably being used by [Cargo], Rust's package manager.
//!
//! ## TOML values
//!
//! A value in TOML is represented with the [`Value`] enum in this crate:
//!
//! ```rust,ignore
//! pub enum Value {
//!     String(String),
//!     Integer(i64),
//!     Float(f64),
//!     Boolean(bool),
//!     Datetime(Datetime),
//!     Array(Array),
//!     Table(Table),
//! }
//! ```
//!
//! TOML is similar to JSON with the notable addition of a [`Datetime`]
//! type. In general, TOML and JSON are interchangeable in terms of
//! formats.
//!
//! ## Parsing TOML
//!
//! The easiest way to parse a TOML document is via the [`Value`] type:
//!
//! ```rust
//! use toml::Value;
//!
//! let value = "foo = 'bar'".parse::<Value>().unwrap();
//!
//! assert_eq!(value["foo"].as_str(), Some("bar"));
//! ```
//!
//! The [`Value`] type implements a number of convenience methods and
//! traits; the example above uses [`FromStr`] to parse a [`str`] into a
//! [`Value`].
//!
//! ## Deserialization and Serialization
//!
//! This crate supports [`serde`] 1.0 with a number of
//! implementations of the `Deserialize`, `Serialize`, `Deserializer`, and
//! `Serializer` traits. Namely, you'll find:
//!
//! * `Deserialize for Value`
//! * `Serialize for Value`
//! * `Deserialize for Datetime`
//! * `Serialize for Datetime`
//! * `Deserializer for de::Deserializer`
//! * `Serializer for ser::Serializer`
//! * `Deserializer for Value`
//!
//! This means that you can use Serde to deserialize/serialize the
//! [`Value`] type as well as the [`Datetime`] type in this crate. You can also
//! use the [`Deserializer`], [`Serializer`], or [`Value`] type itself to act as
//! a deserializer/serializer for arbitrary types.
//!
//! An example of deserializing with TOML is:
//!
//! ```rust
//! use serde_derive::Deserialize;
//!
//! #[derive(Deserialize)]
//! struct Config {
//!     ip: String,
//!     port: Option<u16>,
//!     keys: Keys,
//! }
//!
//! #[derive(Deserialize)]
//! struct Keys {
//!     github: String,
//!     travis: Option<String>,
//! }
//!
//! fn main() {
//!     let config: Config = toml::from_str(r#"
//!         ip = '127.0.0.1'
//!
//!         [keys]
//!         github = 'xxxxxxxxxxxxxxxxx'
//!         travis = 'yyyyyyyyyyyyyyyyy'
//!     "#).unwrap();
//!
//!     assert_eq!(config.ip, "127.0.0.1");
//!     assert_eq!(config.port, None);
//!     assert_eq!(config.keys.github, "xxxxxxxxxxxxxxxxx");
//!     assert_eq!(config.keys.travis.as_ref().unwrap(), "yyyyyyyyyyyyyyyyy");
//! }
//! ```
//!
//! You can serialize types in a similar fashion:
//!
//! ```rust
//! use serde_derive::Serialize;
//!
//! #[derive(Serialize)]
//! struct Config {
//!     ip: String,
//!     port: Option<u16>,
//!     keys: Keys,
//! }
//!
//! #[derive(Serialize)]
//! struct Keys {
//!     github: String,
//!     travis: Option<String>,
//! }
//!
//! fn main() {
//!     let config = Config {
//!         ip: "127.0.0.1".to_string(),
//!         port: None,
//!         keys: Keys {
//!             github: "xxxxxxxxxxxxxxxxx".to_string(),
//!             travis: Some("yyyyyyyyyyyyyyyyy".to_string()),
//!         },
//!     };
//!
//!     let toml = toml::to_string(&config).unwrap();
//! }
//! ```
//!
//! [TOML]: https://github.com/toml-lang/toml
//! [Cargo]: https://crates.io/
//! [`serde`]: https://serde.rs/

#![doc(html_root_url = "https://docs.rs/toml/0.5")]
#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
// Makes rustc abort compilation if there are any unsafe blocks in the crate.
// Presence of this annotation is picked up by tools such as cargo-geiger
// and lets them ensure that there is indeed no unsafe code as opposed to
// something they couldn't detect (e.g. unsafe added via macro expansion, etc).
#![forbid(unsafe_code)]

pub mod map;
pub mod value;
#[doc(no_inline)]
pub use crate::value::Value;
mod datetime;

pub mod ser;
#[doc(no_inline)]
pub use crate::ser::{to_string, to_string_pretty, to_vec, Serializer};
pub mod de;
#[doc(no_inline)]
pub use crate::de::{from_slice, from_str, Deserializer};
mod tokens;

#[doc(hidden)]
pub mod macros;

mod spanned;
#[doc(no_inline)]
pub use crate::spanned::Spanned;

// Just for rustdoc
#[allow(unused_imports)]
use crate::datetime::Datetime;
#[allow(unused_imports)]
use core::str::FromStr;
<commit_msg>Remove `no_inline` from `Spanned` import<commit_after>//! A [TOML]-parsing library
//!
//! This library implements a [TOML] v0.5.0 compatible parser,
//! primarily supporting the [`serde`] library for encoding/decoding
//! various types in Rust.
//!
//! TOML itself is a simple, ergonomic, and readable configuration format:
//!
//! ```toml
//! [package]
//! name = "toml"
//! version = "0.4.2"
//! authors = ["Alex Crichton <alex@alexcrichton.com>"]
//!
//! [dependencies]
//! serde = "1.0"
//! ```
//!
//! The TOML format tends to be relatively common throughout the Rust community
//! for configuration, notably being used by [Cargo], Rust's package manager.
//!
//! ## TOML values
//!
//! A value in TOML is represented with the [`Value`] enum in this crate:
//!
//! ```rust,ignore
//! pub enum Value {
//!     String(String),
//!     Integer(i64),
//!     Float(f64),
//!     Boolean(bool),
//!     Datetime(Datetime),
//!     Array(Array),
//!     Table(Table),
//! }
//! ```
//!
//! TOML is similar to JSON with the notable addition of a [`Datetime`]
//! type. In general, TOML and JSON are interchangeable in terms of
//! formats.
//!
//! ## Parsing TOML
//!
//! The easiest way to parse a TOML document is via the [`Value`] type:
//!
//! ```rust
//! use toml::Value;
//!
//! let value = "foo = 'bar'".parse::<Value>().unwrap();
//!
//! assert_eq!(value["foo"].as_str(), Some("bar"));
//! ```
//!
//! The [`Value`] type implements a number of convenience methods and
//! traits; the example above uses [`FromStr`] to parse a [`str`] into a
//! [`Value`].
//!
//! ## Deserialization and Serialization
//!
//! This crate supports [`serde`] 1.0 with a number of
//! implementations of the `Deserialize`, `Serialize`, `Deserializer`, and
//! `Serializer` traits. Namely, you'll find:
//!
//! * `Deserialize for Value`
//! * `Serialize for Value`
//! * `Deserialize for Datetime`
//! * `Serialize for Datetime`
//! * `Deserializer for de::Deserializer`
//! * `Serializer for ser::Serializer`
//! * `Deserializer for Value`
//!
//! This means that you can use Serde to deserialize/serialize the
//! [`Value`] type as well as the [`Datetime`] type in this crate. You can also
//! use the [`Deserializer`], [`Serializer`], or [`Value`] type itself to act as
//! a deserializer/serializer for arbitrary types.
//!
//! An example of deserializing with TOML is:
//!
//! ```rust
//! use serde_derive::Deserialize;
//!
//! #[derive(Deserialize)]
//! struct Config {
//!     ip: String,
//!     port: Option<u16>,
//!     keys: Keys,
//! }
//!
//! #[derive(Deserialize)]
//! struct Keys {
//!     github: String,
//!     travis: Option<String>,
//! }
//!
//! fn main() {
//!     let config: Config = toml::from_str(r#"
//!         ip = '127.0.0.1'
//!
//!         [keys]
//!         github = 'xxxxxxxxxxxxxxxxx'
//!         travis = 'yyyyyyyyyyyyyyyyy'
//!     "#).unwrap();
//!
//!     assert_eq!(config.ip, "127.0.0.1");
//!     assert_eq!(config.port, None);
//!     assert_eq!(config.keys.github, "xxxxxxxxxxxxxxxxx");
//!     assert_eq!(config.keys.travis.as_ref().unwrap(), "yyyyyyyyyyyyyyyyy");
//! }
//! ```
//!
//! You can serialize types in a similar fashion:
//!
//! ```rust
//! use serde_derive::Serialize;
//!
//! #[derive(Serialize)]
//! struct Config {
//!     ip: String,
//!     port: Option<u16>,
//!     keys: Keys,
//! }
//!
//! #[derive(Serialize)]
//! struct Keys {
//!     github: String,
//!     travis: Option<String>,
//! }
//!
//! fn main() {
//!     let config = Config {
//!         ip: "127.0.0.1".to_string(),
//!         port: None,
//!         keys: Keys {
//!             github: "xxxxxxxxxxxxxxxxx".to_string(),
//!             travis: Some("yyyyyyyyyyyyyyyyy".to_string()),
//!         },
//!     };
//!
//!     let toml = toml::to_string(&config).unwrap();
//! }
//! ```
//!
//! [TOML]: https://github.com/toml-lang/toml
//! [Cargo]: https://crates.io/
//! [`serde`]: https://serde.rs/

#![doc(html_root_url = "https://docs.rs/toml/0.5")]
#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
// Makes rustc abort compilation if there are any unsafe blocks in the crate.
// Presence of this annotation is picked up by tools such as cargo-geiger
// and lets them ensure that there is indeed no unsafe code as opposed to
// something they couldn't detect (e.g. unsafe added via macro expansion, etc).
#![forbid(unsafe_code)]

pub mod map;
pub mod value;
#[doc(no_inline)]
pub use crate::value::Value;
mod datetime;

pub mod ser;
#[doc(no_inline)]
pub use crate::ser::{to_string, to_string_pretty, to_vec, Serializer};
pub mod de;
#[doc(no_inline)]
pub use crate::de::{from_slice, from_str, Deserializer};
mod tokens;

#[doc(hidden)]
pub mod macros;

mod spanned;
pub use crate::spanned::Spanned;

// Just for rustdoc
#[allow(unused_imports)]
use crate::datetime::Datetime;
#[allow(unused_imports)]
use core::str::FromStr;
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! sorted-collections-rs is a library providing useful extension traits and convenience
//! methods for ordered collections in Rust.

#![feature(collections, core)]

#![cfg_attr(test, feature(test))] #[cfg(test)] extern crate test;

pub use sortedmap::SortedMapExt;
pub use sortedset::SortedSetExt;

pub mod sortedmap;
pub mod sortedset;
<commit_msg>Update to latest Rust<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! sorted-collections-rs is a library providing useful extension traits and convenience
//! methods for ordered collections in Rust.

#![feature(collections)]

#![cfg_attr(test, feature(test))] #[cfg(test)] extern crate test;

pub use sortedmap::SortedMapExt;
pub use sortedset::SortedSetExt;

pub mod sortedmap;
pub mod sortedset;
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(lang_items)]

#![feature(alloc)]
#![allow(unknown_lints)]
#![no_std]

extern crate alloc;
#[cfg(not(test))]
extern crate allocator;
extern crate spin;
#[macro_use]
extern crate collections;

#[macro_use]
pub mod linux;

pub mod cli;
pub mod dispatch_table;
pub mod gdt;
pub mod hash_map;
pub mod runtime;
pub mod vmx;

#[no_mangle]
pub extern "C" fn entry(_heap: *mut u8, _heap_size: u64, _: *mut u8, _: u64) -> u32 {
    unsafe {
        linux::printk(cstring!("Hello Linux!\n"));
    }

    gdt::test_load();

    #[cfg(not(test))]
    allocator::init_global_allocator(_heap_size, _heap);
    0
}
<commit_msg>Run runtime tests at entrypoint<commit_after>#![feature(collections)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(lang_items)]

#![feature(alloc)]
#![allow(unknown_lints)]
#![no_std]

extern crate alloc;
#[cfg(not(test))]
extern crate allocator;
extern crate spin;
#[macro_use]
extern crate collections;

#[macro_use]
pub mod linux;

pub mod cli;
pub mod dispatch_table;
pub mod gdt;
pub mod hash_map;
pub mod runtime;
pub mod vmx;

#[no_mangle]
pub extern "C" fn entry(_heap: *mut u8, _heap_size: u64, _: *mut u8, _: u64) -> u32 {
    unsafe {
        linux::printk(cstring!("Hello Linux!\n"));
    }

    #[cfg(feature = "runtime_tests")]
    runtime_tests();

    #[cfg(not(test))]
    allocator::init_global_allocator(_heap_size, _heap);
    0
}

#[cfg(feature = "runtime_tests")]
fn runtime_tests() {
    gdt::runtime_tests::test_load();
}
<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let name = src.read_u32::<BigEndian>().unwrap();
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_parse() {
    use std::io::Cursor;
    let test = vec!('t' as u8, 'e' as u8, 's' as u8, 't' as u8, 0, 0, 0, 8);
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}
<commit_msg>Make initialization slightly nicer.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let name = src.read_u32::<BigEndian>().unwrap();
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    let mut test = "test".to_string().into_bytes();
    for x in [0, 0, 0, 8].iter() {
        test.push(*x);
    }
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}
<|endoftext|>


<commit_before>#![feature(question_mark)]

#[macro_use] extern crate error_type;
#[macro_use] extern crate unborrow;

use std::borrow::Cow;
use std::fs::{self, File, OpenOptions};
use std::io::{self, BufRead, BufReader, Write};
use std::path::Path;

error_type! {
    #[derive(Debug)]
    pub enum Error {
        Io(io::Error) {
            cause;
        },

        Message(Cow<'static, str>) {
            desc (e) &**e;
            from (s: &'static str) s.into();
            from (s: String) s.into();
        }
    }
}

pub type Result<T> = std::result::Result<T, Error>;

fn try_create<P: AsRef<Path>>(path: P, overwrite: bool) -> Result<File> {
    OpenOptions::new()
                .write(true)
                .create(true).truncate(true)
                .create_new(!overwrite)
                .open(path)
                .map_err(Into::into)
}

fn start_cell<W: Write>(inpath: &Path, file: &mut W, pat: &str, n: i32, overwrite: bool) -> Result<File> {
    let name = pat.replace("{}", &n.to_string());
    let mut cell = try_create(&name, overwrite)?;
    writeln!(cell, "% part {} of {}", n, inpath.display())?;
    writeln!(file, "{}", Path::new(&name).file_stem().unwrap().to_str().unwrap())?;
    Ok(cell)
}

pub fn expand<P: AsRef<Path>>(path: P, overwrite: bool) -> Result<()> {
    let inpath = fs::canonicalize(path.as_ref())?;
    let outpat = {
        let mut outpat = inpath.clone();
        let mut stem = outpat.file_stem().ok_or(Error::from("no filename"))?
                             .to_str().ok_or(Error::from("non-Unicode filename"))?
                             .to_string();
        stem.push_str("_{}.");
        stem.push_str(outpat.extension().and_then(|s| s.to_str()).unwrap_or(""));
        outpat.set_file_name(stem);
        outpat.to_str().ok_or(Error::from("non-Unicode path"))?
              .to_string()
    };
    let infile = BufReader::new(File::open(&inpath)?);
    let mut outfile = try_create(outpat.replace("{}", "gen"), overwrite)?;

    println!("Processing cell mode file\n\t\t{}\n\tinto\n\t\t{}\n\tand\n\t\t{}",
             inpath.display(), outpat.replace("{}", "gen"), outpat.replace("{}", "*"));

    let mut outs = 1;
    let mut cells = vec![start_cell(&inpath, &mut outfile, &outpat, 0, overwrite)?];
    for line in infile.lines() {
        let line = line?;
        let trimline = line.trim_left();

        // FIXME users could use semicolons to put multiple statements on one line
        if trimline.starts_with("%%") {
            println!("Found cell break: {}", trimline);

            cells.pop().unwrap();
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
            write!(cells.last_mut().unwrap_or(&mut outfile), "{}", &line[..(line.len() - trimline.len())])?;
            unborrow!(cells.push(start_cell(&inpath, cells.last_mut().unwrap_or(&mut outfile), &outpat, outs, overwrite)?));
            outs += 1;
            writeln!(cells.last_mut().unwrap(), "{}", &line[1..])?;
        } else if trimline.starts_with("end") {
            cells.pop().unwrap();
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
        } else if trimline.starts_with("for")
               || trimline.starts_with("while")
               || trimline.starts_with("parfor")
               || trimline.starts_with("if")
               || trimline.starts_with("try") {
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
            write!(cells.last_mut().unwrap_or(&mut outfile), "{}    ", &line[..(line.len() - trimline.len())])?;
            unborrow!(cells.push(start_cell(&inpath, cells.last_mut().unwrap_or(&mut outfile), &outpat, outs, overwrite)?));
            outs += 1;
        } else if trimline.starts_with("else")
               || trimline.starts_with("elseif")
               || trimline.starts_with("catch") {
            cells.pop().unwrap();
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
            write!(cells.last_mut().unwrap_or(&mut outfile), "{}    ", &line[..(line.len() - trimline.len())])?;
            unborrow!(cells.push(start_cell(&inpath, cells.last_mut().unwrap_or(&mut outfile), &outpat, outs, overwrite)?));
            outs += 1;
        } else if trimline.starts_with("switch") {
            return Err("switch is unimplemented".into());
        } else {
            // FIXME trim left if inside block inside cell
            writeln!(cells.last_mut().unwrap(), "{}", line)?;
        }
    }

    Ok(())
}

<commit_msg>not every line starting with 'end' ends there<commit_after>#![feature(question_mark)]

#[macro_use] extern crate error_type;
#[macro_use] extern crate unborrow;

use std::borrow::Cow;
use std::fs::{self, File, OpenOptions};
use std::io::{self, BufRead, BufReader, Write};
use std::path::Path;

error_type! {
    #[derive(Debug)]
    pub enum Error {
        Io(io::Error) {
            cause;
        },

        Message(Cow<'static, str>) {
            desc (e) &**e;
            from (s: &'static str) s.into();
            from (s: String) s.into();
        }
    }
}

pub type Result<T> = std::result::Result<T, Error>;

fn try_create<P: AsRef<Path>>(path: P, overwrite: bool) -> Result<File> {
    OpenOptions::new()
                .write(true)
                .create(true).truncate(true)
                .create_new(!overwrite)
                .open(path)
                .map_err(Into::into)
}

fn start_cell<W: Write>(inpath: &Path, file: &mut W, pat: &str, n: i32, overwrite: bool) -> Result<File> {
    let name = pat.replace("{}", &n.to_string());
    let mut cell = try_create(&name, overwrite)?;
    writeln!(cell, "% part {} of {}", n, inpath.display())?;
    writeln!(file, "{}", Path::new(&name).file_stem().unwrap().to_str().unwrap())?;
    Ok(cell)
}

pub fn expand<P: AsRef<Path>>(path: P, overwrite: bool) -> Result<()> {
    let inpath = fs::canonicalize(path.as_ref())?;
    let outpat = {
        let mut outpat = inpath.clone();
        let mut stem = outpat.file_stem().ok_or(Error::from("no filename"))?
                             .to_str().ok_or(Error::from("non-Unicode filename"))?
                             .to_string();
        stem.push_str("_{}.");
        stem.push_str(outpat.extension().and_then(|s| s.to_str()).unwrap_or(""));
        outpat.set_file_name(stem);
        outpat.to_str().ok_or(Error::from("non-Unicode path"))?
              .to_string()
    };
    let infile = BufReader::new(File::open(&inpath)?);
    let mut outfile = try_create(outpat.replace("{}", "gen"), overwrite)?;

    println!("Processing cell mode file\n\t\t{}\n\tinto\n\t\t{}\n\tand\n\t\t{}",
             inpath.display(), outpat.replace("{}", "gen"), outpat.replace("{}", "*"));

    let mut outs = 1;
    let mut cells = vec![start_cell(&inpath, &mut outfile, &outpat, 0, overwrite)?];
    for line in infile.lines() {
        let line = line?;
        let trimline = line.trim_left();

        // FIXME users could use semicolons to put multiple statements on one line
        if trimline.starts_with("%%") {
            println!("Found cell break: {}", trimline);

            cells.pop().unwrap();
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
            write!(cells.last_mut().unwrap_or(&mut outfile), "{}", &line[..(line.len() - trimline.len())])?;
            unborrow!(cells.push(start_cell(&inpath, cells.last_mut().unwrap_or(&mut outfile), &outpat, outs, overwrite)?));
            outs += 1;
            writeln!(cells.last_mut().unwrap(), "{}", &line[1..])?;
        } else if trimline == "end" {
            cells.pop().unwrap();
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
        } else if trimline.starts_with("for")
               || trimline.starts_with("while")
               || trimline.starts_with("parfor")
               || trimline.starts_with("if")
               || trimline.starts_with("try") {
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
            write!(cells.last_mut().unwrap_or(&mut outfile), "{}    ", &line[..(line.len() - trimline.len())])?;
            unborrow!(cells.push(start_cell(&inpath, cells.last_mut().unwrap_or(&mut outfile), &outpat, outs, overwrite)?));
            outs += 1;
        } else if trimline.starts_with("else")
               || trimline.starts_with("elseif")
               || trimline.starts_with("catch") {
            cells.pop().unwrap();
            writeln!(cells.last_mut().unwrap_or(&mut outfile), "{}", line)?;
            write!(cells.last_mut().unwrap_or(&mut outfile), "{}    ", &line[..(line.len() - trimline.len())])?;
            unborrow!(cells.push(start_cell(&inpath, cells.last_mut().unwrap_or(&mut outfile), &outpat, outs, overwrite)?));
            outs += 1;
        } else if trimline.starts_with("switch") {
            return Err("switch is unimplemented".into());
        } else {
            // FIXME trim left if inside block inside cell
            writeln!(cells.last_mut().unwrap(), "{}", line)?;
        }
    }

    Ok(())
}

<|endoftext|>


<commit_before>//! A parser for the [TGFF][1] (Task Graphs For Free) format.
//!
//! [1]: http://ziyang.eecs.umich.edu/~dickrp/tgff/

#![allow(unstable)]

#[cfg(test)]
#[macro_use]
extern crate assert;

use std::iter::Peekable;
use std::str::CharIndices;

pub use content::Content;
pub use content::{Graph, Task, Arc, Deadline};
pub use content::{Table, Column};

mod content;

static READ_CAPACITY: usize = 20;

/// An outcome of parsing.
pub type Result<T> = std::result::Result<T, Error>;

/// A parsing error.
pub struct Error {
    /// The line on which the error occurred.
    pub line: usize,
    /// The description of the error.
    pub message: String,
}

struct Parser<'a> {
    line: usize,
    cursor: Peekable<(usize, char), CharIndices<'a>>,
    content: Content,
}

/// Parse a string containing a TGFF file.
///
/// The input string is the content of a TGFF file generated by the `tgff`
/// command-line utility based on the corresponding TGFFOPT file.
pub fn parse(input: &str) -> Result<Content> {
    Parser::new(input).process()
}

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error { line: $parser.line, message: format!($($arg)*) });
    );
);

macro_rules! some(
    ($parser:expr, $result:expr, $($arg:tt)*) => (
        match $result {
            Some(result) => result,
            None => raise!($parser, $($arg)*),
        }
    );
);

impl std::fmt::Debug for Error {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "{} on line {}", self.message, self.line)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "{} on line {}", self.message, self.line)
    }
}

impl<'a> Parser<'a> {
    fn new(input: &'a str) -> Parser<'a> {
        Parser {
            line: 1,
            cursor: input.char_indices().peekable(),
            content: content::new(),
        }
    }

    fn process(&mut self) -> Result<Content> {
        loop {
            match self.peek() {
                Some('@') => try!(self.process_at()),
                Some(_) => raise!(self, "found an unknown statement"),
                None => break,
            }
        }
        Ok(std::mem::replace(&mut self.content, content::new()))
    }

    fn process_at(&mut self) -> Result<()> {
        try!(self.skip_char('@'));

        let name = try!(self.get_token());
        let number = try!(self.get_natural());

        if let Some('{') = self.peek() {
            self.process_block(name, number)
        } else {
            self.content.attributes.insert(name, number);
            Ok(())
        }
    }

    fn process_block(&mut self, name: String, id: usize) -> Result<()> {
        try!(self.skip_char('{'));
        if let Some('#') = self.peek() {
            try!(self.process_table(name, id));
        } else {
            try!(self.process_graph(name, id));
        }
        try!(self.skip_char('}'));
        Ok(())
    }

    fn process_graph(&mut self, name: String, id: usize) -> Result<()> {
        let mut graph = content::new_graph(name, id);

        loop {
            match self.read_token() {
                Some(ref token) => match token.as_slice() {
                    "TASK" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.tasks.push(content::new_task(id, kind));
                    },
                    "ARC" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("FROM"));
                        let from = try!(self.get_id());
                        try!(self.skip_str("TO"));
                        let to = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.arcs.push(content::new_arc(id, from, to, kind));
                    },
                    "HARD_DEADLINE" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("ON"));
                        let on = try!(self.get_id());
                        try!(self.skip_str("AT"));
                        let at = try!(self.get_natural());
                        graph.deadlines.push(content::new_deadline(id, on, at));
                    },
                    _ => {
                        let value = try!(self.get_natural());
                        graph.attributes.insert(token.clone(), value);
                    },
                },
                None => break,
            }
        }

        self.content.graphs.push(graph);
        Ok(())
    }

    fn process_table(&mut self, name: String, id: usize) -> Result<()> {
        let mut table = content::new_table(name, id);

        try!(self.skip_char('#'));

        let mut names = vec![];
        loop {
            match self.read_token() {
                Some(token) => names.push(token),
                None => break,
            }
        }
        for name in names.into_iter() {
            table.attributes.insert(name, try!(self.get_real()));
        }

        try!(self.skip_comment());
        try!(self.skip_char('#'));

        loop {
            match self.read_token() {
                Some(name) => table.columns.push(content::new_column(name)),
                None => break,
            }
        }
        let cols = table.columns.len();
        loop {
            match self.peek() {
                Some('}') | None => break,
                _ => {},
            }
            for i in range(0, cols) {
                table.columns[i].data.push(try!(self.get_real()));
            }
        }

        self.content.tables.push(table);
        Ok(())
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            None => None,
        }
    }

    fn skip(&mut self, accept: &Fn(usize, char) -> bool) -> usize {
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        count
    }

    fn skip_char(&mut self, expected: char) -> Result<()> {
        match self.next() {
            Some(c) => {
                if c == expected {
                    self.skip_void();
                    return Ok(());
                }
            },
            None => {},
        }
        raise!(self, "expected `{}`", expected);
    }

    fn skip_str(&mut self, expected: &str) -> Result<()> {
        let len = expected.len();
        if self.skip(&|i, c| i < len && c == expected.char_at(i)) != len {
            raise!(self, "expected `{}`", expected);
        }
        self.skip_void();
        Ok(())
    }

    #[inline]
    fn skip_void(&mut self) {
        self.skip(&|_, c| c == ' ' || c == '\t' || c == '\n');
    }

    fn skip_comment(&mut self) -> Result<()> {
        if self.skip(&|i, c| i == 0 && c == '#' || (i > 0) && c == '-') < 2 {
            raise!(self, "expected a comment line");
        }
        self.skip_void();
        Ok(())
    }

    fn read(&mut self, accept: &Fn(usize, char) -> bool) -> Option<String> {
        let mut result = std::string::String::with_capacity(READ_CAPACITY);
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    result.push(c);
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        if count == 0 {
            None
        } else {
            Some(result)
        }
    }

    fn read_token(&mut self) -> Option<String> {
        let result = self.read(&|i, c| {
            match c {
                'A'...'Z' | 'a'...'z' if i == 0 => true,
                'A'...'Z' | 'a'...'z' | '_' | '0'...'9' if i > 0 => true,
                _ => false,
            }
        });
        self.skip_void();
        result
    }

    fn read_id(&mut self) -> Option<usize> {
        match self.read_token() {
            Some(ref token) => match token.as_slice().split('_').nth(1) {
                Some(id) => std::num::from_str_radix(id, 10),
                None => None,
            },
            None => None,
        }
    }

    fn read_natural(&mut self) -> Option<usize> {
        let result = match self.read(&|_, c| c >= '0' && c <= '9') {
            Some(ref number) => std::num::from_str_radix(number.as_slice(), 10),
            None => None,
        };
        self.skip_void();
        result
    }

    fn read_real(&mut self) -> Option<f64> {
        let result = match self.read(&|_, c| {
            match c {
                '+' | '-' | '.' | '0'...'9' | 'e' | 'E' => true,
                _ => false,
            }
        }) {
            Some(ref number) => number.as_slice().parse(),
            None => None,
        };
        self.skip_void();
        result
    }

    fn get_token(&mut self) -> Result<String> {
        match self.read_token() {
            Some(token) => Ok(token),
            None => raise!(self, "expected a token"),
        }
    }

    fn get_id(&mut self) -> Result<usize> {
        match self.read_id() {
            Some(id) => Ok(id),
            None => raise!(self, "expected an id"),
        }
    }

    fn get_natural(&mut self) -> Result<usize> {
        match self.read_natural() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a natural number"),
        }
    }

    fn get_real(&mut self) -> Result<f64> {
        match self.read_real() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a real number"),
        }
    }
}

impl<'a> std::iter::Iterator for Parser<'a> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, '\n')) => {
                self.line += 1;
                Some('\n')
            },
            Some((_, c)) => Some(c),
            None => None,
        }
    }
}

#[cfg(test)]
mod tests {
    macro_rules! parser(
        ($input:expr) => (super::Parser::new($input));
    );

    #[test]
    fn process_at() {
        assert_ok!(parser!("@abc 12").process_at());
        assert_err!(parser!("@ ").process_at());
        assert_err!(parser!("@abc").process_at());
    }

    #[test]
    fn process_block() {
        assert_ok!(parser!("{}").process_block(String::new(), 0));
    }

    #[test]
    fn process_graph() {
        let mut parser = parser!("TASK t0_0\tTYPE 2   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref task = parser.content.graphs[0].tasks[0];
            assert_eq!(task.id, 0);
            assert_eq!(task.kind, 2);
        }

        parser = parser!("ARC a0_42 \tFROM t0_0  TO  t0_1 TYPE 35   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref arc = parser.content.graphs[0].arcs[0];
            assert_eq!(arc.id, 42);
            assert_eq!(arc.from, 0);
            assert_eq!(arc.to, 1);
            assert_eq!(arc.kind, 35);
        }

        parser = parser!("HARD_DEADLINE d0_9 ON t0_12 AT 1000   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref deadline = parser.content.graphs[0].deadlines[0];
            assert_eq!(deadline.id, 9);
            assert_eq!(deadline.on, 12);
            assert_eq!(deadline.at, 1000);
        }
    }

    #[test]
    fn process_table() {
        let mut parser = parser!("# foo\n 70.07\n#--\n# bar baz\n1 2 3 4 ");
        assert_ok!(parser.process_table(String::new(), 0));
        let ref table = parser.content.tables[0];
        assert_eq!(table.attributes["foo".to_string()], 70.07);
        assert_eq!(table.columns[0].name, "bar".to_string());
        assert_eq!(table.columns[1].name, "baz".to_string());
        assert_eq!(table.columns[0].data, vec![1.0, 3.0]);
        assert_eq!(table.columns[1].data, vec![2.0, 4.0]);
    }

    #[test]
    fn skip_char() {
        let mut parser = parser!("#  \t\n  abc");
        assert_ok!(parser.skip_char('#'));
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_str() {
        let mut parser = parser!("abc  \t\n  xyz");
        assert_ok!(parser.skip_str("abc"));
        assert_eq!(parser.next().unwrap(), 'x');
    }

    #[test]
    fn skip_void() {
        let mut parser = parser!("  \t  abc");
        parser.skip_void();
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_comment() {
        let mut parser = parser!("#--------------   \n abc");
        assert_ok!(parser.skip_comment());
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn get_token() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_token().unwrap(),
                           String::from_str($output))
            );
        );
        test!("AZ xyz", "AZ");
        test!("az xyz", "az");
        test!("AZ_az_09 xyz", "AZ_az_09");
    }

    #[test]
    fn get_id() {
        assert_eq!(parser!("t0_42").get_id().unwrap(), 42);
    }

    #[test]
    fn get_natural() {
        assert_eq!(parser!("09").get_natural().unwrap(), 9);
    }

    #[test]
    fn get_real() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_real().unwrap(), $output)
            );
        );
        test!("-1", -1.0);
        test!("0.1", 0.1);
        test!("1.2e3", 1.2e3);
        test!("1.2e+3", 1.2e3);
        test!("-1.2e-3", -1.2e-3);
    }
}
<commit_msg>Delegated Display::fmt to Debug::fmt<commit_after>//! A parser for the [TGFF][1] (Task Graphs For Free) format.
//!
//! [1]: http://ziyang.eecs.umich.edu/~dickrp/tgff/

#![allow(unstable)]

#[cfg(test)]
#[macro_use]
extern crate assert;

use std::fmt;
use std::iter::Peekable;
use std::str::CharIndices;

pub use content::Content;
pub use content::{Graph, Task, Arc, Deadline};
pub use content::{Table, Column};

mod content;

static READ_CAPACITY: usize = 20;

/// An outcome of parsing.
pub type Result<T> = std::result::Result<T, Error>;

/// A parsing error.
pub struct Error {
    /// The line on which the error occurred.
    pub line: usize,
    /// The description of the error.
    pub message: String,
}

struct Parser<'a> {
    line: usize,
    cursor: Peekable<(usize, char), CharIndices<'a>>,
    content: Content,
}

/// Parse a string containing a TGFF file.
///
/// The input string is the content of a TGFF file generated by the `tgff`
/// command-line utility based on the corresponding TGFFOPT file.
pub fn parse(input: &str) -> Result<Content> {
    Parser::new(input).process()
}

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error { line: $parser.line, message: format!($($arg)*) });
    );
);

macro_rules! some(
    ($parser:expr, $result:expr, $($arg:tt)*) => (
        match $result {
            Some(result) => result,
            None => raise!($parser, $($arg)*),
        }
    );
);

impl fmt::Debug for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{} on line {}", self.message, self.line)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, formatter)
    }
}

impl<'a> Parser<'a> {
    fn new(input: &'a str) -> Parser<'a> {
        Parser {
            line: 1,
            cursor: input.char_indices().peekable(),
            content: content::new(),
        }
    }

    fn process(&mut self) -> Result<Content> {
        loop {
            match self.peek() {
                Some('@') => try!(self.process_at()),
                Some(_) => raise!(self, "found an unknown statement"),
                None => break,
            }
        }
        Ok(std::mem::replace(&mut self.content, content::new()))
    }

    fn process_at(&mut self) -> Result<()> {
        try!(self.skip_char('@'));

        let name = try!(self.get_token());
        let number = try!(self.get_natural());

        if let Some('{') = self.peek() {
            self.process_block(name, number)
        } else {
            self.content.attributes.insert(name, number);
            Ok(())
        }
    }

    fn process_block(&mut self, name: String, id: usize) -> Result<()> {
        try!(self.skip_char('{'));
        if let Some('#') = self.peek() {
            try!(self.process_table(name, id));
        } else {
            try!(self.process_graph(name, id));
        }
        try!(self.skip_char('}'));
        Ok(())
    }

    fn process_graph(&mut self, name: String, id: usize) -> Result<()> {
        let mut graph = content::new_graph(name, id);

        loop {
            match self.read_token() {
                Some(ref token) => match token.as_slice() {
                    "TASK" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.tasks.push(content::new_task(id, kind));
                    },
                    "ARC" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("FROM"));
                        let from = try!(self.get_id());
                        try!(self.skip_str("TO"));
                        let to = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.arcs.push(content::new_arc(id, from, to, kind));
                    },
                    "HARD_DEADLINE" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("ON"));
                        let on = try!(self.get_id());
                        try!(self.skip_str("AT"));
                        let at = try!(self.get_natural());
                        graph.deadlines.push(content::new_deadline(id, on, at));
                    },
                    _ => {
                        let value = try!(self.get_natural());
                        graph.attributes.insert(token.clone(), value);
                    },
                },
                None => break,
            }
        }

        self.content.graphs.push(graph);
        Ok(())
    }

    fn process_table(&mut self, name: String, id: usize) -> Result<()> {
        let mut table = content::new_table(name, id);

        try!(self.skip_char('#'));

        let mut names = vec![];
        loop {
            match self.read_token() {
                Some(token) => names.push(token),
                None => break,
            }
        }
        for name in names.into_iter() {
            table.attributes.insert(name, try!(self.get_real()));
        }

        try!(self.skip_comment());
        try!(self.skip_char('#'));

        loop {
            match self.read_token() {
                Some(name) => table.columns.push(content::new_column(name)),
                None => break,
            }
        }
        let cols = table.columns.len();
        loop {
            match self.peek() {
                Some('}') | None => break,
                _ => {},
            }
            for i in range(0, cols) {
                table.columns[i].data.push(try!(self.get_real()));
            }
        }

        self.content.tables.push(table);
        Ok(())
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            None => None,
        }
    }

    fn skip(&mut self, accept: &Fn(usize, char) -> bool) -> usize {
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        count
    }

    fn skip_char(&mut self, expected: char) -> Result<()> {
        match self.next() {
            Some(c) => {
                if c == expected {
                    self.skip_void();
                    return Ok(());
                }
            },
            None => {},
        }
        raise!(self, "expected `{}`", expected);
    }

    fn skip_str(&mut self, expected: &str) -> Result<()> {
        let len = expected.len();
        if self.skip(&|i, c| i < len && c == expected.char_at(i)) != len {
            raise!(self, "expected `{}`", expected);
        }
        self.skip_void();
        Ok(())
    }

    #[inline]
    fn skip_void(&mut self) {
        self.skip(&|_, c| c == ' ' || c == '\t' || c == '\n');
    }

    fn skip_comment(&mut self) -> Result<()> {
        if self.skip(&|i, c| i == 0 && c == '#' || (i > 0) && c == '-') < 2 {
            raise!(self, "expected a comment line");
        }
        self.skip_void();
        Ok(())
    }

    fn read(&mut self, accept: &Fn(usize, char) -> bool) -> Option<String> {
        let mut result = std::string::String::with_capacity(READ_CAPACITY);
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    result.push(c);
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        if count == 0 {
            None
        } else {
            Some(result)
        }
    }

    fn read_token(&mut self) -> Option<String> {
        let result = self.read(&|i, c| {
            match c {
                'A'...'Z' | 'a'...'z' if i == 0 => true,
                'A'...'Z' | 'a'...'z' | '_' | '0'...'9' if i > 0 => true,
                _ => false,
            }
        });
        self.skip_void();
        result
    }

    fn read_id(&mut self) -> Option<usize> {
        match self.read_token() {
            Some(ref token) => match token.as_slice().split('_').nth(1) {
                Some(id) => std::num::from_str_radix(id, 10),
                None => None,
            },
            None => None,
        }
    }

    fn read_natural(&mut self) -> Option<usize> {
        let result = match self.read(&|_, c| c >= '0' && c <= '9') {
            Some(ref number) => std::num::from_str_radix(number.as_slice(), 10),
            None => None,
        };
        self.skip_void();
        result
    }

    fn read_real(&mut self) -> Option<f64> {
        let result = match self.read(&|_, c| {
            match c {
                '+' | '-' | '.' | '0'...'9' | 'e' | 'E' => true,
                _ => false,
            }
        }) {
            Some(ref number) => number.as_slice().parse(),
            None => None,
        };
        self.skip_void();
        result
    }

    fn get_token(&mut self) -> Result<String> {
        match self.read_token() {
            Some(token) => Ok(token),
            None => raise!(self, "expected a token"),
        }
    }

    fn get_id(&mut self) -> Result<usize> {
        match self.read_id() {
            Some(id) => Ok(id),
            None => raise!(self, "expected an id"),
        }
    }

    fn get_natural(&mut self) -> Result<usize> {
        match self.read_natural() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a natural number"),
        }
    }

    fn get_real(&mut self) -> Result<f64> {
        match self.read_real() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a real number"),
        }
    }
}

impl<'a> std::iter::Iterator for Parser<'a> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, '\n')) => {
                self.line += 1;
                Some('\n')
            },
            Some((_, c)) => Some(c),
            None => None,
        }
    }
}

#[cfg(test)]
mod tests {
    macro_rules! parser(
        ($input:expr) => (super::Parser::new($input));
    );

    #[test]
    fn process_at() {
        assert_ok!(parser!("@abc 12").process_at());
        assert_err!(parser!("@ ").process_at());
        assert_err!(parser!("@abc").process_at());
    }

    #[test]
    fn process_block() {
        assert_ok!(parser!("{}").process_block(String::new(), 0));
    }

    #[test]
    fn process_graph() {
        let mut parser = parser!("TASK t0_0\tTYPE 2   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref task = parser.content.graphs[0].tasks[0];
            assert_eq!(task.id, 0);
            assert_eq!(task.kind, 2);
        }

        parser = parser!("ARC a0_42 \tFROM t0_0  TO  t0_1 TYPE 35   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref arc = parser.content.graphs[0].arcs[0];
            assert_eq!(arc.id, 42);
            assert_eq!(arc.from, 0);
            assert_eq!(arc.to, 1);
            assert_eq!(arc.kind, 35);
        }

        parser = parser!("HARD_DEADLINE d0_9 ON t0_12 AT 1000   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref deadline = parser.content.graphs[0].deadlines[0];
            assert_eq!(deadline.id, 9);
            assert_eq!(deadline.on, 12);
            assert_eq!(deadline.at, 1000);
        }
    }

    #[test]
    fn process_table() {
        let mut parser = parser!("# foo\n 70.07\n#--\n# bar baz\n1 2 3 4 ");
        assert_ok!(parser.process_table(String::new(), 0));
        let ref table = parser.content.tables[0];
        assert_eq!(table.attributes["foo".to_string()], 70.07);
        assert_eq!(table.columns[0].name, "bar".to_string());
        assert_eq!(table.columns[1].name, "baz".to_string());
        assert_eq!(table.columns[0].data, vec![1.0, 3.0]);
        assert_eq!(table.columns[1].data, vec![2.0, 4.0]);
    }

    #[test]
    fn skip_char() {
        let mut parser = parser!("#  \t\n  abc");
        assert_ok!(parser.skip_char('#'));
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_str() {
        let mut parser = parser!("abc  \t\n  xyz");
        assert_ok!(parser.skip_str("abc"));
        assert_eq!(parser.next().unwrap(), 'x');
    }

    #[test]
    fn skip_void() {
        let mut parser = parser!("  \t  abc");
        parser.skip_void();
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_comment() {
        let mut parser = parser!("#--------------   \n abc");
        assert_ok!(parser.skip_comment());
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn get_token() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_token().unwrap(),
                           String::from_str($output))
            );
        );
        test!("AZ xyz", "AZ");
        test!("az xyz", "az");
        test!("AZ_az_09 xyz", "AZ_az_09");
    }

    #[test]
    fn get_id() {
        assert_eq!(parser!("t0_42").get_id().unwrap(), 42);
    }

    #[test]
    fn get_natural() {
        assert_eq!(parser!("09").get_natural().unwrap(), 9);
    }

    #[test]
    fn get_real() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_real().unwrap(), $output)
            );
        );
        test!("-1", -1.0);
        test!("0.1", 0.1);
        test!("1.2e3", 1.2e3);
        test!("1.2e+3", 1.2e3);
        test!("-1.2e-3", -1.2e-3);
    }
}
<|endoftext|>


<commit_before>//! oppgave - A simple Redis-based task queue
//!
//!
//! ## Example: Producer
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let producer = Queue::new("default".into(), con);
//!
//! producer.push(Job{ id: 42 });
//! ```
//!
//! ## Example: Worker
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let worker = Queue::new("default".into(), con);
//!
//! while let Some(task) = worker.next() {
//!     println!("Working with Job {}", job.id);
//! }
//! ```

#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![deny(missing_docs)]

extern crate rustc_serialize;
extern crate redis;
extern crate libc;

use std::{str, thread};
use std::cell::Cell;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

/// Return the PID of the calling process.
/// TODO: Does this work on Windows?
fn getpid() -> i32 {
    unsafe { libc::getpid() as i32 }
}

/// Task objects that can be reconstructed from the JSON stored in Redis
///
/// Implemented for all `Decodable` objects by default.
pub trait TaskDecodable where Self: Sized {
    /// Decode the given Redis value into a task
    ///
    /// This should decode the string value into a proper task.
    /// The string value is encoded as JSON.
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

/// Task objects that can be encoded to JSON to be stored in Redis
///
/// Implemented for all `Encodable` objects by default.
pub trait TaskEncodable {
    /// Encode the value into a Blob to insert into Redis
    ///
    /// It should encode the value into a JSON string.
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match *value {
            Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                json::decode(&s).map_err(|_| From::from((ErrorKind::TypeError, "JSON decode failed")))

            },
            _ => {
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

/// A wrapper of the fetched task
///
/// Pops a task from the backup on drop.
pub struct TaskGuard<'a, T: 'a> {
    task: T,
    queue: &'a Queue,
    failed: Cell<bool>,
}

impl<'a, T> TaskGuard<'a, T> {
    /// Stop the underlying queue
    pub fn stop(&self) {
        self.queue.stop();
    }

    /// Fail the current task and don't remove it from the backup queue
    pub fn fail(&self) {
        self.failed.set(true);
    }

    /// Get access to the underlying task
    pub fn inner(&self) -> &T {
        &self.task
    }

    /// Get access to the wrapper queue
    pub fn queue(&self) -> &Queue {
        self.queue
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        if !self.failed.get() {
            // Pop job from backup queue
            let backup = &self.queue.backup_queue[..];
            let _ : () = self.queue.client.lpop(backup).expect("LPOP from backup queue failed");
        }
    }
}

/// A Queue allows to push new tasks or wait for them
///
/// Allows for reliable job processing.
///
/// On fetch jobs are moved to a backup queue.
/// They are popped from the backup queue, when the returned task guard is dropped.
///
/// ## Example
///
/// ```rust,ignore
/// #[derive(RustcDecodable, RustcEncodable)]
/// struct Job { id: u64 }
///
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// let producer = Queue::new("default".into(), con);
///
/// producer.push(Job{ id: 42 });
/// ```
pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    client: redis::Connection,
}

impl Queue {
    /// Create a new Queue for the given name
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let qname = format!("oppgave:{}", name);
        let backup_queue = format!("{}:{}:{}",
                                   qname,
                                   getpid(),
                                   thread::current().name().unwrap_or("default".into()));

        Queue {
            queue_name: qname,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    /// Stop processing the queue
    ///
    /// On the next `.next()` call `None` will be returned.
    pub fn stop(&self) {
        self.stopped.set(true);
    }

    /// Check if queue processing is stopped
    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    /// Get the full queue name
    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    /// Get the full backup queue name
    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    /// Get the number of remaining tasks in the queue
    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    /// Push a new task to the queue
    pub fn push<T: TaskEncodable>(&self, task: T) -> RedisResult<()> {
        self.client.lpush(self.queue(), task.encode_task())
    }

    /// Grab the next task from the queue
    ///
    /// This method blocks and waits until a new task is available.
    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        match T::decode_task(&v) {
            Err(e) => Some(Err(e)),
            Ok(task) => Some(Ok(TaskGuard{task: task, queue: self, failed: Cell::new(false)}))
        }
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::{Queue, TaskGuard};

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueue() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();

        let worker = Queue::new("enqueue".into(), con2);
        let _ : () = con.del(worker.queue()).unwrap();

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53}).unwrap();

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }

    #[test]
    fn does_not_drop_failed() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("failure".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.del(worker.backup_queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();

        {
            let task : TaskGuard<Job> = worker.next().unwrap().unwrap();
            task.fail();
        }

        let len : u32 = con.llen(worker.backup_queue()).unwrap();
        assert_eq!(1, len);
    }
}
<commit_msg>docs: It is not necessary to have JSON<commit_after>//! oppgave - A simple Redis-based task queue
//!
//!
//! ## Example: Producer
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let producer = Queue::new("default".into(), con);
//!
//! producer.push(Job{ id: 42 });
//! ```
//!
//! ## Example: Worker
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let worker = Queue::new("default".into(), con);
//!
//! while let Some(task) = worker.next() {
//!     println!("Working with Job {}", job.id);
//! }
//! ```

#![cfg_attr(feature = "clippy", allow(unstable_features))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![deny(missing_docs)]

extern crate rustc_serialize;
extern crate redis;
extern crate libc;

use std::{str, thread};
use std::cell::Cell;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

/// Return the PID of the calling process.
/// TODO: Does this work on Windows?
fn getpid() -> i32 {
    unsafe { libc::getpid() as i32 }
}

/// Task objects that can be reconstructed from the data stored in Redis
///
/// Implemented for all `Decodable` objects by default by relying on JSON encoding.
pub trait TaskDecodable where Self: Sized {
    /// Decode the given Redis value into a task
    ///
    /// This should decode the string value into a proper task.
    /// The string value is encoded as JSON.
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

/// Task objects that can be encoded to a string to be stored in Redis
///
/// Implemented for all `Encodable` objects by default by encoding as JSON.
pub trait TaskEncodable {
    /// Encode the value into a Blob to insert into Redis
    ///
    /// It should encode the value into a string.
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match *value {
            Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                json::decode(&s).map_err(|_| From::from((ErrorKind::TypeError, "JSON decode failed")))

            },
            _ => {
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

/// A wrapper of the fetched task
///
/// Pops a task from the backup on drop.
pub struct TaskGuard<'a, T: 'a> {
    task: T,
    queue: &'a Queue,
    failed: Cell<bool>,
}

impl<'a, T> TaskGuard<'a, T> {
    /// Stop the underlying queue
    pub fn stop(&self) {
        self.queue.stop();
    }

    /// Fail the current task and don't remove it from the backup queue
    pub fn fail(&self) {
        self.failed.set(true);
    }

    /// Get access to the underlying task
    pub fn inner(&self) -> &T {
        &self.task
    }

    /// Get access to the wrapper queue
    pub fn queue(&self) -> &Queue {
        self.queue
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        if !self.failed.get() {
            // Pop job from backup queue
            let backup = &self.queue.backup_queue[..];
            let _ : () = self.queue.client.lpop(backup).expect("LPOP from backup queue failed");
        }
    }
}

/// A Queue allows to push new tasks or wait for them
///
/// Allows for reliable job processing.
///
/// On fetch jobs are moved to a backup queue.
/// They are popped from the backup queue, when the returned task guard is dropped.
///
/// ## Example
///
/// ```rust,ignore
/// #[derive(RustcDecodable, RustcEncodable)]
/// struct Job { id: u64 }
///
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// let producer = Queue::new("default".into(), con);
///
/// producer.push(Job{ id: 42 });
/// ```
pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    client: redis::Connection,
}

impl Queue {
    /// Create a new Queue for the given name
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let qname = format!("oppgave:{}", name);
        let backup_queue = format!("{}:{}:{}",
                                   qname,
                                   getpid(),
                                   thread::current().name().unwrap_or("default".into()));

        Queue {
            queue_name: qname,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    /// Stop processing the queue
    ///
    /// On the next `.next()` call `None` will be returned.
    pub fn stop(&self) {
        self.stopped.set(true);
    }

    /// Check if queue processing is stopped
    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    /// Get the full queue name
    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    /// Get the full backup queue name
    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    /// Get the number of remaining tasks in the queue
    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    /// Push a new task to the queue
    pub fn push<T: TaskEncodable>(&self, task: T) -> RedisResult<()> {
        self.client.lpush(self.queue(), task.encode_task())
    }

    /// Grab the next task from the queue
    ///
    /// This method blocks and waits until a new task is available.
    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        match T::decode_task(&v) {
            Err(e) => Some(Err(e)),
            Ok(task) => Some(Ok(TaskGuard{task: task, queue: self, failed: Cell::new(false)}))
        }
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::{Queue, TaskGuard};

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueue() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();

        let worker = Queue::new("enqueue".into(), con2);
        let _ : () = con.del(worker.queue()).unwrap();

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53}).unwrap();

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }

    #[test]
    fn does_not_drop_failed() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("failure".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.del(worker.backup_queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();

        {
            let task : TaskGuard<Job> = worker.next().unwrap().unwrap();
            task.fail();
        }

        let len : u32 = con.llen(worker.backup_queue()).unwrap();
        assert_eq!(1, len);
    }
}
<|endoftext|>