<commit_before>/*!
Simple persistent generic HashMap/Key-value store.

Basic usage:

```
extern crate kv_cab;

use kv_cab::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./db.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get("key".to_string()));
    let _ = test_store.remove("key".to_string());
}
```

Usage with user defined Key and Value types:

```
extern crate kv_cab;
extern crate rustc_serialize;

use kv_cab::KV;

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
enum MyKey {
    String(String),
    Int(i32),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
enum MyValue {
    String(String),
    Int(i32),
}

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./db.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(MyKey::Int(1i32)));
    let _ = test_store.remove(MyKey::Int(1i32));
}
```

*/

#![deny(missing_docs)]

extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
extern crate fs2;

use std::collections::HashMap;
use std::fs::{ File, OpenOptions };
use std::io::prelude::*;
use std::io::SeekFrom;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

use fs2::FileExt;

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 10;

/// Definition of a macro for retrying an operation
macro_rules! retry {
    ($i:ident, $b:block) => (
        for $i in 0..MAX_RETRIES {
            if $i != 0 {
                std::thread::park_timeout(std::time::Duration::new(0u64, 1000u32));
            }

            $b
        }
    )
}

/// Macro for what to do on last retry
macro_rules! last_retry {
    ($i:ident, $b:stmt) => (
        if $i >= MAX_RETRIES - 1 {
            $b;
        }
    )
}

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, KVError>;

/// Errors that KV might have
#[derive(Debug, PartialEq)]
pub enum KVError {
    /// Could not decode the cab from disk
    CouldntDecode,
    /// Couldn't encode the hashmap for writing to disk
    CouldntEncode,
    /// Could not write to the cab on disk
    CouldntWrite,
    /// Failed to read the cab from disk
    FailedToRead,
    /// Could not flush the data to disk
    CouldntFlush,
    /// Could not open the file from disk
    CouldntOpen,
    /// Could not load the file from disk
    CouldntLoad,
    /// Failed to write lock the cab
    CouldntWriteLock,
    /// Failed to read lock the cab
    CouldntReadLock,
    /// Failed to unlock the cab
    CouldntUnlock,
    /// Failed to set SeekFrom::Start
    CouldntSeekToStart,
}

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> Result<KV<K,V>, KVError> {
        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: KV::<K, V>::retry_get_file(p).unwrap(),
        };

        match store.load_from_persist(false) {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                return Err(e);
            },
        };

        Ok(store)
    }

    /// Retry to get a reference to the cab file at path p and create if doesn't exist
    fn retry_get_file(p:&'static str) -> Result<File, KVError> {
        retry!(i, {
            match OpenOptions::new().read(true).write(true).create(true).open(p) {
                Ok(f) => { return Ok(f); },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntOpen));
                    continue;
                }
            };
        });

        Err(KVError::CouldntOpen)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            return Err(e);
        }
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(false) {
            return Err(e);
        }
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            return Err(e);
        }
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(false) {
            return Err(e);
        }
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // attempt to write to the cab
        retry!(i, {
            // check that can write to the cab
            if let Err(e) = self.file.lock_exclusive() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntWriteLock));
                continue;
            }

            // encode the cab as a u8 vec
            let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
                Ok(bv) => bv,
                Err(e) => {
                    error!("encode: {}", e);
                    return Err(KVError::CouldntEncode);
                },
            };

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // write the bytes to it
            if let Err(e) = self.file.write_all(byte_vec.as_slice()) {
                error!("file.write_all/retry: {}", e);
                last_retry!(i, return Err(KVError::CouldntWrite));
                continue;
            }

            // flush to disk
            if let Err(e) = self.file.flush() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntFlush));
                continue;
            }

            // unlock the file after write has completed
            if let Err(e) = self.file.unlock() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntUnlock));
                continue;
            }
            return Ok(true);
        });

        Err(KVError::CouldntWrite)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self, already_locked:bool) -> KVResult {
        retry!(i, {
            // byte vec to read into
            let mut byte_vec = Vec::new();

            // wait/lock the cab and read the bytes
            if !already_locked {
                if let Err(e) = self.file.lock_shared() {
                    error!("{}", e);
                    return Err(KVError::CouldntReadLock);
                }
            }

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // read the file into the buffer
            match self.file.read_to_end(&mut byte_vec) {
                Ok(count) => {
                    // don't attempt to decode as empty
                    if count == 0 {
                        if !already_locked {
                            if let Err(e) = self.file.unlock() {
                                error!("{}", e);
                                last_retry!(i, return Err(KVError::CouldntUnlock));
                            }
                        }
                        return Ok(true);
                    }
                },
                Err(e) => {
                    error!("{}", e);
                    return Err(KVError::FailedToRead);
                },
            }

            // decode u8 vec back into HashMap
            match decode(byte_vec.as_slice()) {
                Ok(f) => {
                    // assign read HashMap back to self
                    self.cab = f;
                    if !already_locked {
                        if let Err(e) = self.file.unlock() {
                            error!("{}", e);
                            last_retry!(i, return Err(KVError::CouldntUnlock));
                        }
                    }
                    return Ok(true);
                },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntDecode));
                    continue;
                },
            };
        });

        Err(KVError::CouldntLoad)
    }
}
<commit_msg>Update docs to the same as README<commit_after>/*!
Simple persistent generic HashMap/Key-value store, using file locking to limit writing between threads.

This is in a beta state at the moment.

Basic usage:

```
extern crate kv_cab;

use kv_cab::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./db.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get("key".to_string()));
    let _ = test_store.remove("key".to_string());
}
```

Usage with user defined Key and Value types:

```
extern crate kv_cab;
extern crate rustc_serialize;

use kv_cab::KV;

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
enum MyKey {
    String(String),
    Int(i32),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
enum MyValue {
    String(String),
    Int(i32),
}

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./db.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(MyKey::Int(1i32)));
    let _ = test_store.remove(MyKey::Int(1i32));
}
```

*/

#![deny(missing_docs)]

extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
extern crate fs2;

use std::collections::HashMap;
use std::fs::{ File, OpenOptions };
use std::io::prelude::*;
use std::io::SeekFrom;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

use fs2::FileExt;

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 10;

/// Definition of a macro for retrying an operation
macro_rules! retry {
    ($i:ident, $b:block) => (
        for $i in 0..MAX_RETRIES {
            if $i != 0 {
                std::thread::park_timeout(std::time::Duration::new(0u64, 1000u32));
            }

            $b
        }
    )
}

/// Macro for what to do on last retry
macro_rules! last_retry {
    ($i:ident, $b:stmt) => (
        if $i >= MAX_RETRIES - 1 {
            $b;
        }
    )
}

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, KVError>;

/// Errors that KV might have
#[derive(Debug, PartialEq)]
pub enum KVError {
    /// Could not decode the cab from disk
    CouldntDecode,
    /// Couldn't encode the hashmap for writing to disk
    CouldntEncode,
    /// Could not write to the cab on disk
    CouldntWrite,
    /// Failed to read the cab from disk
    FailedToRead,
    /// Could not flush the data to disk
    CouldntFlush,
    /// Could not open the file from disk
    CouldntOpen,
    /// Could not load the file from disk
    CouldntLoad,
    /// Failed to write lock the cab
    CouldntWriteLock,
    /// Failed to read lock the cab
    CouldntReadLock,
    /// Failed to unlock the cab
    CouldntUnlock,
    /// Failed to set SeekFrom::Start
    CouldntSeekToStart,
}

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> Result<KV<K,V>, KVError> {
        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: KV::<K, V>::retry_get_file(p).unwrap(),
        };

        match store.load_from_persist(false) {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                return Err(e);
            },
        };

        Ok(store)
    }

    /// Retry to get a reference to the cab file at path p and create if doesn't exist
    fn retry_get_file(p:&'static str) -> Result<File, KVError> {
        retry!(i, {
            match OpenOptions::new().read(true).write(true).create(true).open(p) {
                Ok(f) => { return Ok(f); },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntOpen));
                    continue;
                }
            };
        });

        Err(KVError::CouldntOpen)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            return Err(e);
        }
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(false) {
            return Err(e);
        }
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            return Err(e);
        }
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(false) {
            return Err(e);
        }
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // attempt to write to the cab
        retry!(i, {
            // check that can write to the cab
            if let Err(e) = self.file.lock_exclusive() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntWriteLock));
                continue;
            }

            // encode the cab as a u8 vec
            let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
                Ok(bv) => bv,
                Err(e) => {
                    error!("encode: {}", e);
                    return Err(KVError::CouldntEncode);
                },
            };

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // write the bytes to it
            if let Err(e) = self.file.write_all(byte_vec.as_slice()) {
                error!("file.write_all/retry: {}", e);
                last_retry!(i, return Err(KVError::CouldntWrite));
                continue;
            }

            // flush to disk
            if let Err(e) = self.file.flush() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntFlush));
                continue;
            }

            // unlock the file after write has completed
            if let Err(e) = self.file.unlock() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntUnlock));
                continue;
            }
            return Ok(true);
        });

        Err(KVError::CouldntWrite)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self, already_locked:bool) -> KVResult {
        retry!(i, {
            // byte vec to read into
            let mut byte_vec = Vec::new();

            // wait/lock the cab and read the bytes
            if !already_locked {
                if let Err(e) = self.file.lock_shared() {
                    error!("{}", e);
                    return Err(KVError::CouldntReadLock);
                }
            }

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // read the file into the buffer
            match self.file.read_to_end(&mut byte_vec) {
                Ok(count) => {
                    // don't attempt to decode as empty
                    if count == 0 {
                        if !already_locked {
                            if let Err(e) = self.file.unlock() {
                                error!("{}", e);
                                last_retry!(i, return Err(KVError::CouldntUnlock));
                            }
                        }
                        return Ok(true);
                    }
                },
                Err(e) => {
                    error!("{}", e);
                    return Err(KVError::FailedToRead);
                },
            }

            // decode u8 vec back into HashMap
            match decode(byte_vec.as_slice()) {
                Ok(f) => {
                    // assign read HashMap back to self
                    self.cab = f;
                    if !already_locked {
                        if let Err(e) = self.file.unlock() {
                            error!("{}", e);
                            last_retry!(i, return Err(KVError::CouldntUnlock));
                        }
                    }
                    return Ok(true);
                },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntDecode));
                    continue;
                },
            };
        });

        Err(KVError::CouldntLoad)
    }
}
<|endoftext|>


<commit_before>/* 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 http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(globs, link_args, managed_boxes, phase, unsafe_destructor)]

#![allow(non_uppercase_statics, non_camel_case_types, non_snake_case_functions)]

#![reexport_test_harness_main = "test_main"]

extern crate green;
extern crate libc;
#[phase(plugin, link)]
extern crate log;
#[cfg(test)]
extern crate rustuv;
extern crate serialize;

use libc::c_uint;
use libc::types::common::c99::uint32_t;
use jsapi::{JSBool, JSContext, JSPropertyOp, JSStrictPropertyOp, JSEnumerateOp,
            JSObject, jsid, JSResolveOp, JSConvertOp, JSFinalizeOp, JSTraceOp,
            JSProto_LIMIT, JSHandleObject, JSCheckAccessOp, JSNative, JSHasInstanceOp};
use jsapi::JS_ComputeThis;
use jsval::JSVal;

// These are just macros in jsapi.h
pub use jsapi::JS_Init as JS_NewRuntime;
pub use jsapi::JS_Finish as JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
pub use jsapi::bindgen::JS_Lock as JS_LockRuntime;
pub use jsapi::bindgen::JS_Unlock as JS_UnlockRuntime;
*/

pub use jsfriendapi::JSJitInfo;

pub mod jsapi;
pub mod linkhack;
pub mod rust;
pub mod glue;
pub mod trace;
pub mod jsval;
pub mod jsfriendapi;

// FIXME: Add the remaining options
pub static JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
pub static JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
pub static JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
pub static JSOPTION_METHODJIT: uint32_t = (1u32 << 14) as u32;
pub static JSOPTION_TYPE_INFERENCE: uint32_t = (1u32 << 18) as u32;

pub static default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub static default_stacksize: uint = 8192u;
pub static ERR: JSBool = 0_i32;

pub static JSID_TYPE_STRING: i64 = 0;
pub static JSID_TYPE_INT: i64 = 1;
pub static JSID_TYPE_VOID: i64 = 2;
pub static JSID_TYPE_OBJECT: i64 = 4;
pub static JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6;
pub static JSID_TYPE_MASK: i64 = 7;

pub static JSID_VOID: jsid = JSID_TYPE_VOID as jsid;

pub static JSFUN_CONSTRUCTOR: u32 = 0x200; /* native that can be called as a ctor */

pub static JSPROP_ENUMERATE: c_uint = 0x01;
pub static JSPROP_READONLY: c_uint  = 0x02;
pub static JSPROP_PERMANENT: c_uint = 0x04;
pub static JSPROP_GETTER: c_uint = 0x10;
pub static JSPROP_SETTER: c_uint = 0x20;
pub static JSPROP_SHARED: c_uint =    0x40;
pub static JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

pub static JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub static JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub static JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1u << JSCLASS_RESERVED_SLOTS_WIDTH as uint) - 1) as c_uint;

pub static JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub static JSCLASS_IS_GLOBAL: c_uint = (1<<((JSCLASS_HIGH_FLAGS_SHIFT as uint)+1));

pub static JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSProto_LIMIT * 3 + 24;

pub static JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub static JSCLASS_USERBIT1: u32 = 1 << 7;

pub static JSSLOT_PROXY_PRIVATE: u32 = 1;

pub static JSRESOLVE_QUALIFIED: u32 = 0x01;
pub static JSRESOLVE_ASSIGNING: u32 = 0x02;
pub static JSRESOLVE_DETECTING: u32 = 0x04;

pub enum JSGCTraceKind {
    JSTRACE_OBJECT,
    JSTRACE_STRING,
    JSTRACE_SCRIPT
}

pub fn JSCLASS_HAS_RESERVED_SLOTS(n: c_uint) -> c_uint {
    (n & JSCLASS_RESERVED_SLOTS_MASK) << (JSCLASS_RESERVED_SLOTS_SHIFT as uint)
}

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

pub unsafe fn JS_SET_RVAL(_cx: *mut JSContext, vp: *mut JSVal, v: JSVal) {
    *vp = v;
}

#[inline(alwyas)]
pub unsafe fn JS_THIS_OBJECT(cx: *mut JSContext, vp: *mut JSVal) -> *mut JSObject {
    let r =
        if (*(vp.offset(1))).is_primitive() {
            JS_ComputeThis(cx, vp)
        } else {
            *(vp.offset(1))
        };
    r.to_object_or_null()
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// Run tests with libgreen instead of libnative.
#[cfg(test)]
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, rustuv::event_loop, test_main)
}

pub type JSObjectOp = extern "C" fn(*mut JSContext, JSHandleObject) -> *mut JSObject;

pub struct Class {
    pub name: *const libc::c_char,
    pub flags: uint32_t,
    pub addProperty: JSPropertyOp,
    pub delProperty: JSPropertyOp,
    pub getProperty: JSPropertyOp,
    pub setProperty: JSStrictPropertyOp,
    pub enumerate: JSEnumerateOp,
    pub resolve: JSResolveOp,
    pub convert: JSConvertOp,
    pub finalize: JSFinalizeOp,
    pub checkAccess: JSCheckAccessOp,
    pub call: JSNative,
    pub hasInstance: JSHasInstanceOp,
    pub construct: JSNative,
    pub trace: JSTraceOp,

    pub ext: ClassExtension,
    pub ops: ObjectOps,
}

pub struct ClassExtension {
    pub equality: *const u8,
    pub outerObject: Option<JSObjectOp>,
    pub innerObject: Option<JSObjectOp>,
    pub iteratorObject: *const u8,
    pub unused: *const u8,
    pub isWrappedNative: *const u8,
}

pub struct ObjectOps {
    pub lookupGeneric: *const u8,
    pub lookupProperty: *const u8,
    pub lookupElement: *const u8,
    pub lookupSpecial: *const u8,
    pub defineGeneric: *const u8,
    pub defineProperty: *const u8,
    pub defineElement: *const u8,
    pub defineSpecial: *const u8,
    pub getGeneric: *const u8,
    pub getProperty: *const u8,
    pub getElement: *const u8,
    pub getElementIfPresent: *const u8,
    pub getSpecial: *const u8,
    pub setGeneric: *const u8,
    pub setProperty: *const u8,
    pub setElement: *const u8,
    pub setSpecial: *const u8,
    pub getGenericAttributes: *const u8,
    pub getPropertyAttributes: *const u8,
    pub getElementAttributes: *const u8,
    pub getSpecialAttributes: *const u8,
    pub setGenericAttributes: *const u8,
    pub setPropertyAttributes: *const u8,
    pub setElementAttributes: *const u8,
    pub setSpecialAttributes: *const u8,
    pub deleteProperty: *const u8,
    pub deleteElement: *const u8,
    pub deleteSpecial: *const u8,

    pub enumerate: *const u8,
    pub typeOf: *const u8,
    pub thisObject: Option<JSObjectOp>,
    pub clear: *const u8,
}
<commit_msg>Turn off the awful warning stream.<commit_after>/* 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 http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(globs, link_args, managed_boxes, phase, unsafe_destructor)]

#![allow(non_uppercase_statics, non_camel_case_types, non_snake_case, ctypes)]

#![reexport_test_harness_main = "test_main"]

extern crate green;
extern crate libc;
#[phase(plugin, link)]
extern crate log;
#[cfg(test)]
extern crate rustuv;
extern crate serialize;

use libc::c_uint;
use libc::types::common::c99::uint32_t;
use jsapi::{JSBool, JSContext, JSPropertyOp, JSStrictPropertyOp, JSEnumerateOp,
            JSObject, jsid, JSResolveOp, JSConvertOp, JSFinalizeOp, JSTraceOp,
            JSProto_LIMIT, JSHandleObject, JSCheckAccessOp, JSNative, JSHasInstanceOp};
use jsapi::JS_ComputeThis;
use jsval::JSVal;

// These are just macros in jsapi.h
pub use jsapi::JS_Init as JS_NewRuntime;
pub use jsapi::JS_Finish as JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
pub use jsapi::bindgen::JS_Lock as JS_LockRuntime;
pub use jsapi::bindgen::JS_Unlock as JS_UnlockRuntime;
*/

pub use jsfriendapi::JSJitInfo;

pub mod jsapi;
pub mod linkhack;
pub mod rust;
pub mod glue;
pub mod trace;
pub mod jsval;
pub mod jsfriendapi;

// FIXME: Add the remaining options
pub static JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
pub static JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
pub static JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
pub static JSOPTION_METHODJIT: uint32_t = (1u32 << 14) as u32;
pub static JSOPTION_TYPE_INFERENCE: uint32_t = (1u32 << 18) as u32;

pub static default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub static default_stacksize: uint = 8192u;
pub static ERR: JSBool = 0_i32;

pub static JSID_TYPE_STRING: i64 = 0;
pub static JSID_TYPE_INT: i64 = 1;
pub static JSID_TYPE_VOID: i64 = 2;
pub static JSID_TYPE_OBJECT: i64 = 4;
pub static JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6;
pub static JSID_TYPE_MASK: i64 = 7;

pub static JSID_VOID: jsid = JSID_TYPE_VOID as jsid;

pub static JSFUN_CONSTRUCTOR: u32 = 0x200; /* native that can be called as a ctor */

pub static JSPROP_ENUMERATE: c_uint = 0x01;
pub static JSPROP_READONLY: c_uint  = 0x02;
pub static JSPROP_PERMANENT: c_uint = 0x04;
pub static JSPROP_GETTER: c_uint = 0x10;
pub static JSPROP_SETTER: c_uint = 0x20;
pub static JSPROP_SHARED: c_uint =    0x40;
pub static JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

pub static JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub static JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub static JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1u << JSCLASS_RESERVED_SLOTS_WIDTH as uint) - 1) as c_uint;

pub static JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub static JSCLASS_IS_GLOBAL: c_uint = (1<<((JSCLASS_HIGH_FLAGS_SHIFT as uint)+1));

pub static JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSProto_LIMIT * 3 + 24;

pub static JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub static JSCLASS_USERBIT1: u32 = 1 << 7;

pub static JSSLOT_PROXY_PRIVATE: u32 = 1;

pub static JSRESOLVE_QUALIFIED: u32 = 0x01;
pub static JSRESOLVE_ASSIGNING: u32 = 0x02;
pub static JSRESOLVE_DETECTING: u32 = 0x04;

pub enum JSGCTraceKind {
    JSTRACE_OBJECT,
    JSTRACE_STRING,
    JSTRACE_SCRIPT
}

pub fn JSCLASS_HAS_RESERVED_SLOTS(n: c_uint) -> c_uint {
    (n & JSCLASS_RESERVED_SLOTS_MASK) << (JSCLASS_RESERVED_SLOTS_SHIFT as uint)
}

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

pub unsafe fn JS_SET_RVAL(_cx: *mut JSContext, vp: *mut JSVal, v: JSVal) {
    *vp = v;
}

#[inline(alwyas)]
pub unsafe fn JS_THIS_OBJECT(cx: *mut JSContext, vp: *mut JSVal) -> *mut JSObject {
    let r =
        if (*(vp.offset(1))).is_primitive() {
            JS_ComputeThis(cx, vp)
        } else {
            *(vp.offset(1))
        };
    r.to_object_or_null()
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// Run tests with libgreen instead of libnative.
#[cfg(test)]
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, rustuv::event_loop, test_main)
}

pub type JSObjectOp = extern "C" fn(*mut JSContext, JSHandleObject) -> *mut JSObject;

pub struct Class {
    pub name: *const libc::c_char,
    pub flags: uint32_t,
    pub addProperty: JSPropertyOp,
    pub delProperty: JSPropertyOp,
    pub getProperty: JSPropertyOp,
    pub setProperty: JSStrictPropertyOp,
    pub enumerate: JSEnumerateOp,
    pub resolve: JSResolveOp,
    pub convert: JSConvertOp,
    pub finalize: JSFinalizeOp,
    pub checkAccess: JSCheckAccessOp,
    pub call: JSNative,
    pub hasInstance: JSHasInstanceOp,
    pub construct: JSNative,
    pub trace: JSTraceOp,

    pub ext: ClassExtension,
    pub ops: ObjectOps,
}

pub struct ClassExtension {
    pub equality: *const u8,
    pub outerObject: Option<JSObjectOp>,
    pub innerObject: Option<JSObjectOp>,
    pub iteratorObject: *const u8,
    pub unused: *const u8,
    pub isWrappedNative: *const u8,
}

pub struct ObjectOps {
    pub lookupGeneric: *const u8,
    pub lookupProperty: *const u8,
    pub lookupElement: *const u8,
    pub lookupSpecial: *const u8,
    pub defineGeneric: *const u8,
    pub defineProperty: *const u8,
    pub defineElement: *const u8,
    pub defineSpecial: *const u8,
    pub getGeneric: *const u8,
    pub getProperty: *const u8,
    pub getElement: *const u8,
    pub getElementIfPresent: *const u8,
    pub getSpecial: *const u8,
    pub setGeneric: *const u8,
    pub setProperty: *const u8,
    pub setElement: *const u8,
    pub setSpecial: *const u8,
    pub getGenericAttributes: *const u8,
    pub getPropertyAttributes: *const u8,
    pub getElementAttributes: *const u8,
    pub getSpecialAttributes: *const u8,
    pub setGenericAttributes: *const u8,
    pub setPropertyAttributes: *const u8,
    pub setElementAttributes: *const u8,
    pub setSpecialAttributes: *const u8,
    pub deleteProperty: *const u8,
    pub deleteElement: *const u8,
    pub deleteSpecial: *const u8,

    pub enumerate: *const u8,
    pub typeOf: *const u8,
    pub thisObject: Option<JSObjectOp>,
    pub clear: *const u8,
}
<|endoftext|>


<commit_before>pub mod vector;
pub mod particle;
pub use vector::*;
pub use particle::*;
<commit_msg>add some notes to the crate documentation<commit_after>//! Please do not "use zoom::*" or the zoom::Box type will override std::boxed::Box!
//!
//! This crate creates traits for driving particle physics functions and doing simple
//! vector geometry. It also contains various particle interactions in the particle module, which
//! is publically used in zoom.

pub mod vector;
pub mod particle;
pub use vector::*;
pub use particle::*;
<|endoftext|>


<commit_before>//! # Test CLI Applications
//!
//! This crate's goal is to provide you some very easy tools to test your CLI
//! applications. It can currently execute child processes and validate their
//! exit status as well as stdout and stderr output against your assertions.
//!
//! Include the crate like
//!
//! ```rust
//! #[macro_use] // <-- import the convenience macro (optional)
//! extern crate assert_cli;
//! # fn main() { }
//! ```
//!
//! ## Basic Examples
//!
//! Here's a trivial example:
//!
//! ```rust
//! assert_cli::Assert::command(&["echo", "42"])
//!     .prints("42")
//!     .unwrap();
//! ```
//!
//! And here is one that will fail:
//!
//! ```rust,should_panic
//! assert_cli::Assert::command(&["echo", "42"])
//!     .prints_exactly("1337")
//!     .unwrap();
//! ```
//!
//! this will show a nice, colorful diff in your terminal, like this:
//!
//! ```diff
//! -1337
//! +42
//! ```
//!
//! ## `assert_cmd!` Macro
//!
//! Alternatively, you can use the `assert_cmd!` macro to construct the command more conveniently,
//! but please carefully read the limitations below, or this may seriously go wrong.
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! assert_cmd!(echo "42").prints("42").unwrap();
//! # }
//! ```
//!
//! **Tips**
//!
//! - Don't forget to import the crate with `#[macro_use]`. ;-)
//! - Enclose arguments in the `assert_cmd!` macro in quotes `"`,
//!   if there are special characters, which the macro doesn't accept, e.g.
//!   `assert_cmd!(cat "foo.txt")`.
//!
//! ## Exit Status
//!
//! All assertion default to checking that the command exited with success.
//!
//! However, when you expect a command to fail, you can express it like this:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! assert_cmd!(cat "non-existing-file")
//!     .fails()
//!     .and()
//!     .prints_error("non-existing-file")
//!     .unwrap();
//! # }
//! ```
//!
//! Some notes on this:
//!
//! - Use `fails_with` to assert a specific exit status.
//! - There is also a `succeeds` method, but this is already the implicit default
//!   and can usually be omitted.
//! - We can inspect the output of **stderr** with `prints_error` and `prints_error_exactly`.
//! - The `and` method has no effect, other than to make everything more readable.
//!   Feel free to use it. :-)
//!
//! ## Assert CLI Crates
//!
//! If you are testing a Rust binary crate, you can start with
//! `Assert::main_binary()` to use `cargo run` as command. Or, if you want to
//! run a specific binary (if you have more than one), use
//! `Assert::cargo_binary`.
//!
//! ## Don't Panic!
//!
//! If you don't want it to panic when the assertions are not met, simply call
//! `.execute` instead of `.unwrap` to get a `Result`:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! let x = assert_cmd!(echo "1337").prints_exactly("42").execute();
//! assert!(x.is_err());
//! # }
//! ```

#![deny(warnings, missing_docs)]
#![allow(unused_doc_comment)]

extern crate difference;
#[macro_use] extern crate error_chain;
extern crate rustc_serialize;

use std::process::Command;

mod errors;
use errors::*;

#[macro_use] mod macros;
pub use macros::flatten_escaped_string;

mod output;
use output::{OutputAssertion, StdErr, StdOut};

mod diff;

/// Assertions for a specific command.
#[derive(Debug)]
pub struct Assert {
    cmd: Vec<String>,
    expect_success: Option<bool>,
    expect_exit_code: Option<i32>,
    expect_stdout: Option<OutputAssertion<StdOut>>,
    expect_stderr: Option<OutputAssertion<StdErr>>,
}

impl std::default::Default for Assert {
    /// Construct an assert using `cargo run --` as command.
    ///
    /// Defaults to asserting _successful_ execution.
    fn default() -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--"]
                .into_iter().map(String::from).collect(),
            expect_success: Some(true),
            expect_exit_code: None,
            expect_stdout: None,
            expect_stderr: None,
        }
    }
}

impl Assert {
    /// Run the crate's main binary.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn main_binary() -> Self {
        Assert::default()
    }

    /// Run a specific binary of the current crate.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn cargo_binary(name: &str) -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--bin", name, "--"]
                .into_iter().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Run a custom command.
    ///
    /// Defaults to asserting _successful_ execution.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "1337"])
    ///     .unwrap();
    /// ```
    pub fn command(cmd: &[&str]) -> Self {
        Assert {
            cmd: cmd.into_iter().cloned().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Add arguments to the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo"])
    ///     .with_args(&["42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn with_args(mut self, args: &[&str]) -> Self {
        self.cmd.extend(args.into_iter().cloned().map(String::from));
        self
    }

    /// Small helper to make chains more readable.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn and(self) -> Self {
        self
    }

    /// Expect the command to be executed successfully.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .unwrap();
    /// ```
    pub fn succeeds(mut self) -> Self {
        self.expect_exit_code = None;
        self.expect_success = Some(true);
        self
    }

    /// Expect the command to fail.
    ///
    /// Note: This does not include shell failures like `command not found`. I.e. the
    ///       command must _run_ and fail for this assertion to pass.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn fails(mut self) -> Self {
        self.expect_success = Some(false);
        self
    }

    /// Expect the command to fail and return a specific error code.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn fails_with(mut self, expect_exit_code: i32) -> Self {
        self.expect_success = Some(false);
        self.expect_exit_code = Some(expect_exit_code);
        self
    }

    /// Expect the command's output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn prints<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            kind: StdOut,
        });
        self
    }

    /// Expect the command to output **exactly** this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints_exactly("42")
    ///     .unwrap();
    /// ```
    pub fn prints_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            kind: StdOut,
        });
        self
    }

    /// Expect the command's stderr output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn prints_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            kind: StdErr,
        });
        self
    }

    /// Expect the command to output **exactly** this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn prints_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            kind: StdErr,
        });
        self
    }

    /// Execute the command and check the assertions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// let test = assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .execute();
    /// assert!(test.is_ok());
    /// ```
    pub fn execute(self) -> Result<()> {
        let cmd = &self.cmd[0];
        let args: Vec<_> = self.cmd.iter().skip(1).collect();
        let mut command = Command::new(cmd);
        let command = command.args(&args);
        let output = command.output()?;

        if let Some(expect_success) = self.expect_success {
            if expect_success != output.status.success() {
                bail!(ErrorKind::StatusMismatch(
                    self.cmd.clone(),
                    expect_success,
                ));
            }
        }

        if self.expect_exit_code.is_some() &&
            self.expect_exit_code != output.status.code() {
            bail!(ErrorKind::ExitCodeMismatch(
                self.cmd.clone(),
                self.expect_exit_code,
                output.status.code(),
            ));
        }

        if let Some(ref ouput_assertion) = self.expect_stdout {
            ouput_assertion.execute(&output)
                .map_err(|e| ErrorKind::StdoutMismatch(self.cmd.clone(), e))?;
        }

        if let Some(ref ouput_assertion) = self.expect_stderr {
            ouput_assertion.execute(&output)
                .map_err(|e| ErrorKind::StderrMismatch(self.cmd.clone(), e))?;
        }

        Ok(())
    }

    /// Execute the command, check the assertions, and panic when they fail.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic="Assert CLI failure"
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .fails()
    ///     .unwrap(); // panics
    /// ```
    pub fn unwrap(self) {
        if let Err(err) = self.execute() {
            panic!("{}", err);
        }
    }
}
<commit_msg>Ugh, lints<commit_after>//! # Test CLI Applications
//!
//! This crate's goal is to provide you some very easy tools to test your CLI
//! applications. It can currently execute child processes and validate their
//! exit status as well as stdout and stderr output against your assertions.
//!
//! Include the crate like
//!
//! ```rust
//! #[macro_use] // <-- import the convenience macro (optional)
//! extern crate assert_cli;
//! # fn main() { }
//! ```
//!
//! ## Basic Examples
//!
//! Here's a trivial example:
//!
//! ```rust
//! assert_cli::Assert::command(&["echo", "42"])
//!     .prints("42")
//!     .unwrap();
//! ```
//!
//! And here is one that will fail:
//!
//! ```rust,should_panic
//! assert_cli::Assert::command(&["echo", "42"])
//!     .prints_exactly("1337")
//!     .unwrap();
//! ```
//!
//! this will show a nice, colorful diff in your terminal, like this:
//!
//! ```diff
//! -1337
//! +42
//! ```
//!
//! ## `assert_cmd!` Macro
//!
//! Alternatively, you can use the `assert_cmd!` macro to construct the command more conveniently,
//! but please carefully read the limitations below, or this may seriously go wrong.
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! assert_cmd!(echo "42").prints("42").unwrap();
//! # }
//! ```
//!
//! **Tips**
//!
//! - Don't forget to import the crate with `#[macro_use]`. ;-)
//! - Enclose arguments in the `assert_cmd!` macro in quotes `"`,
//!   if there are special characters, which the macro doesn't accept, e.g.
//!   `assert_cmd!(cat "foo.txt")`.
//!
//! ## Exit Status
//!
//! All assertion default to checking that the command exited with success.
//!
//! However, when you expect a command to fail, you can express it like this:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! assert_cmd!(cat "non-existing-file")
//!     .fails()
//!     .and()
//!     .prints_error("non-existing-file")
//!     .unwrap();
//! # }
//! ```
//!
//! Some notes on this:
//!
//! - Use `fails_with` to assert a specific exit status.
//! - There is also a `succeeds` method, but this is already the implicit default
//!   and can usually be omitted.
//! - We can inspect the output of **stderr** with `prints_error` and `prints_error_exactly`.
//! - The `and` method has no effect, other than to make everything more readable.
//!   Feel free to use it. :-)
//!
//! ## Assert CLI Crates
//!
//! If you are testing a Rust binary crate, you can start with
//! `Assert::main_binary()` to use `cargo run` as command. Or, if you want to
//! run a specific binary (if you have more than one), use
//! `Assert::cargo_binary`.
//!
//! ## Don't Panic!
//!
//! If you don't want it to panic when the assertions are not met, simply call
//! `.execute` instead of `.unwrap` to get a `Result`:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! let x = assert_cmd!(echo "1337").prints_exactly("42").execute();
//! assert!(x.is_err());
//! # }
//! ```

#![deny(missing_docs)]

extern crate difference;
#[macro_use] extern crate error_chain;
extern crate rustc_serialize;

use std::process::Command;

mod errors;
use errors::*;

#[macro_use] mod macros;
pub use macros::flatten_escaped_string;

mod output;
use output::{OutputAssertion, StdErr, StdOut};

mod diff;

/// Assertions for a specific command.
#[derive(Debug)]
pub struct Assert {
    cmd: Vec<String>,
    expect_success: Option<bool>,
    expect_exit_code: Option<i32>,
    expect_stdout: Option<OutputAssertion<StdOut>>,
    expect_stderr: Option<OutputAssertion<StdErr>>,
}

impl std::default::Default for Assert {
    /// Construct an assert using `cargo run --` as command.
    ///
    /// Defaults to asserting _successful_ execution.
    fn default() -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--"]
                .into_iter().map(String::from).collect(),
            expect_success: Some(true),
            expect_exit_code: None,
            expect_stdout: None,
            expect_stderr: None,
        }
    }
}

impl Assert {
    /// Run the crate's main binary.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn main_binary() -> Self {
        Assert::default()
    }

    /// Run a specific binary of the current crate.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn cargo_binary(name: &str) -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--bin", name, "--"]
                .into_iter().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Run a custom command.
    ///
    /// Defaults to asserting _successful_ execution.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "1337"])
    ///     .unwrap();
    /// ```
    pub fn command(cmd: &[&str]) -> Self {
        Assert {
            cmd: cmd.into_iter().cloned().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Add arguments to the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo"])
    ///     .with_args(&["42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn with_args(mut self, args: &[&str]) -> Self {
        self.cmd.extend(args.into_iter().cloned().map(String::from));
        self
    }

    /// Small helper to make chains more readable.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn and(self) -> Self {
        self
    }

    /// Expect the command to be executed successfully.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .unwrap();
    /// ```
    pub fn succeeds(mut self) -> Self {
        self.expect_exit_code = None;
        self.expect_success = Some(true);
        self
    }

    /// Expect the command to fail.
    ///
    /// Note: This does not include shell failures like `command not found`. I.e. the
    ///       command must _run_ and fail for this assertion to pass.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn fails(mut self) -> Self {
        self.expect_success = Some(false);
        self
    }

    /// Expect the command to fail and return a specific error code.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn fails_with(mut self, expect_exit_code: i32) -> Self {
        self.expect_success = Some(false);
        self.expect_exit_code = Some(expect_exit_code);
        self
    }

    /// Expect the command's output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn prints<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            kind: StdOut,
        });
        self
    }

    /// Expect the command to output **exactly** this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints_exactly("42")
    ///     .unwrap();
    /// ```
    pub fn prints_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            kind: StdOut,
        });
        self
    }

    /// Expect the command's stderr output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn prints_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            kind: StdErr,
        });
        self
    }

    /// Expect the command to output **exactly** this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn prints_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            kind: StdErr,
        });
        self
    }

    /// Execute the command and check the assertions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// let test = assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .execute();
    /// assert!(test.is_ok());
    /// ```
    pub fn execute(self) -> Result<()> {
        let cmd = &self.cmd[0];
        let args: Vec<_> = self.cmd.iter().skip(1).collect();
        let mut command = Command::new(cmd);
        let command = command.args(&args);
        let output = command.output()?;

        if let Some(expect_success) = self.expect_success {
            if expect_success != output.status.success() {
                bail!(ErrorKind::StatusMismatch(
                    self.cmd.clone(),
                    expect_success,
                ));
            }
        }

        if self.expect_exit_code.is_some() &&
            self.expect_exit_code != output.status.code() {
            bail!(ErrorKind::ExitCodeMismatch(
                self.cmd.clone(),
                self.expect_exit_code,
                output.status.code(),
            ));
        }

        if let Some(ref ouput_assertion) = self.expect_stdout {
            ouput_assertion.execute(&output)
                .map_err(|e| ErrorKind::StdoutMismatch(self.cmd.clone(), e))?;
        }

        if let Some(ref ouput_assertion) = self.expect_stderr {
            ouput_assertion.execute(&output)
                .map_err(|e| ErrorKind::StderrMismatch(self.cmd.clone(), e))?;
        }

        Ok(())
    }

    /// Execute the command, check the assertions, and panic when they fail.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic="Assert CLI failure"
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .fails()
    ///     .unwrap(); // panics
    /// ```
    pub fn unwrap(self) {
        if let Err(err) = self.execute() {
            panic!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2021, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A library for passing arbitrary file descriptors when spawning child processes.
//!
//! # Example
//!
//! ```rust
//! use command_fds::{CommandFdExt, FdMapping};
//! use std::fs::File;
//! use std::os::unix::io::AsRawFd;
//! use std::process::Command;
//!
//! // Open a file.
//! let file = File::open("Cargo.toml").unwrap();
//!
//! // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
//! let mut command = Command::new("ls");
//! command.arg("-l").arg("/proc/self/fd");
//! command
//!     .fd_mappings(vec![
//!         // Map `file` as FD 3 in the child process.
//!         FdMapping {
//!             parent_fd: file.as_raw_fd(),
//!             child_fd: 3,
//!         },
//!         // Map this process's stdin as FD 5 in the child process.
//!         FdMapping {
//!             parent_fd: 0,
//!             child_fd: 5,
//!         },
//!     ])
//!     .unwrap();
//!
//! // Spawn the child process.
//! let mut child = command.spawn().unwrap();
//! child.wait().unwrap();
//! ```

use nix::fcntl::{fcntl, FcntlArg};
use nix::unistd::dup2;
use std::cmp::max;
use std::io::{self, ErrorKind};
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use thiserror::Error;

/// A mapping from a file descriptor in the parent to a file descriptor in the child, to be applied
/// when spawning a child process.
///
/// The parent_fd must be kept open until after the child is spawned.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FdMapping {
    pub parent_fd: RawFd,
    pub child_fd: RawFd,
}

/// Error setting up FD mappings, because there were two or more mappings for the same child FD.
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
#[error("Two or more mappings for the same child FD")]
pub struct FdMappingCollision;

/// Extension to add file descriptor mappings to a [`Command`].
pub trait CommandFdExt {
    /// Adds the given set of file descriptor to the command.
    ///
    /// Calling this more than once on the same command may result in unexpected behaviour.
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision>;
}

impl CommandFdExt for Command {
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision> {
        // Validate that there are no conflicting mappings to the same child FD.
        let mut child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
        child_fds.sort_unstable();
        child_fds.dedup();
        if child_fds.len() != mappings.len() {
            return Err(FdMappingCollision);
        }

        // Register the callback to apply the mappings after forking but before execing.
        unsafe {
            self.pre_exec(move || map_fds(&mappings));
        }

        Ok(())
    }
}

fn map_fds(mappings: &[FdMapping]) -> io::Result<()> {
    if mappings.is_empty() {
        // No need to do anything, and finding first_unused_fd would fail.
        return Ok(());
    }

    // Find the first FD which is higher than any parent or child FD in the mapping, so we can
    // safely use it and higher FDs as temporary FDs. There may be other files open with these FDs,
    // so we still need to ensure we don't conflict with them.
    let first_safe_fd = mappings
        .iter()
        .map(|mapping| max(mapping.parent_fd, mapping.child_fd))
        .max()
        .unwrap()
        + 1;

    // If any parent FDs conflict with child FDs, then first duplicate them to a temporary FD which
    // is clear of either range.
    let child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
    let mappings = mappings
        .iter()
        .map(|mapping| {
            Ok(if child_fds.contains(&mapping.parent_fd) {
                let temporary_fd =
                    fcntl(mapping.parent_fd, FcntlArg::F_DUPFD_CLOEXEC(first_safe_fd))?;
                FdMapping {
                    parent_fd: temporary_fd,
                    child_fd: mapping.child_fd,
                }
            } else {
                mapping.to_owned()
            })
        })
        .collect::<nix::Result<Vec<_>>>()
        .map_err(nix_to_io_error)?;

    // Now we can actually duplicate FDs to the desired child FDs.
    for mapping in mappings {
        // This closes child_fd if it is already open as something else, and clears the FD_CLOEXEC
        // flag on child_fd.
        dup2(mapping.parent_fd, mapping.child_fd).map_err(nix_to_io_error)?;
    }

    Ok(())
}

/// Convert a [`nix::Error`] to a [`std::io::Error`].
fn nix_to_io_error(error: nix::Error) -> io::Error {
    if let nix::Error::Sys(errno) = error {
        io::Error::from_raw_os_error(errno as i32)
    } else {
        io::Error::new(ErrorKind::Other, error)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;
    use std::fs::File;
    use std::os::unix::io::AsRawFd;
    use std::process::Output;
    use std::str;

    #[test]
    fn conflicting_mappings() {
        let mut command = Command::new("ls");

        // The same mapping can't be included twice.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
            ]),
            Err(FdMappingCollision)
        );

        // Mapping two different FDs to the same FD isn't allowed either.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 6,
                },
            ]),
            Err(FdMappingCollision)
        );
    }

    #[test]
    fn no_mappings() {
        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        assert_eq!(command.fd_mappings(vec![]), Ok(()));

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3]);
    }

    #[test]
    fn one_mapping() {
        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file an otherwise unused FD.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 5,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, 5]);
    }

    #[test]
    fn swap_mappings() {
        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        let fd2 = file2.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    parent_fd: fd1,
                    child_fd: fd2,
                },
                FdMapping {
                    parent_fd: fd2,
                    child_fd: fd1,
                },
            ]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, fd1, fd2]);
    }

    #[test]
    fn map_stdin() {
        let mut command = Command::new("cat");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file to stdin.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 0,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        assert!(output.status.success());
        assert_eq!(output.stdout, b"test 1");
    }

    /// Parse the output of ls into a set of filenames
    fn parse_ls_output(output: &[u8]) -> HashSet<String> {
        str::from_utf8(output)
            .unwrap()
            .split_terminator("\n")
            .map(str::to_owned)
            .collect()
    }

    /// Check that the output of `ls /proc/self/fd` contains the expected set of FDs.
    fn expect_fds(output: &Output, expected_fds: &[RawFd]) {
        assert!(output.status.success());
        let expected_fds: HashSet<String> = expected_fds.iter().map(RawFd::to_string).collect();
        assert_eq!(parse_ls_output(&output.stdout), expected_fds);
    }
}
<commit_msg>Close excess FDs before each test.<commit_after>// Copyright 2021, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A library for passing arbitrary file descriptors when spawning child processes.
//!
//! # Example
//!
//! ```rust
//! use command_fds::{CommandFdExt, FdMapping};
//! use std::fs::File;
//! use std::os::unix::io::AsRawFd;
//! use std::process::Command;
//!
//! // Open a file.
//! let file = File::open("Cargo.toml").unwrap();
//!
//! // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
//! let mut command = Command::new("ls");
//! command.arg("-l").arg("/proc/self/fd");
//! command
//!     .fd_mappings(vec![
//!         // Map `file` as FD 3 in the child process.
//!         FdMapping {
//!             parent_fd: file.as_raw_fd(),
//!             child_fd: 3,
//!         },
//!         // Map this process's stdin as FD 5 in the child process.
//!         FdMapping {
//!             parent_fd: 0,
//!             child_fd: 5,
//!         },
//!     ])
//!     .unwrap();
//!
//! // Spawn the child process.
//! let mut child = command.spawn().unwrap();
//! child.wait().unwrap();
//! ```

use nix::fcntl::{fcntl, FcntlArg};
use nix::unistd::dup2;
use std::cmp::max;
use std::io::{self, ErrorKind};
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use thiserror::Error;

/// A mapping from a file descriptor in the parent to a file descriptor in the child, to be applied
/// when spawning a child process.
///
/// The parent_fd must be kept open until after the child is spawned.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FdMapping {
    pub parent_fd: RawFd,
    pub child_fd: RawFd,
}

/// Error setting up FD mappings, because there were two or more mappings for the same child FD.
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
#[error("Two or more mappings for the same child FD")]
pub struct FdMappingCollision;

/// Extension to add file descriptor mappings to a [`Command`].
pub trait CommandFdExt {
    /// Adds the given set of file descriptor to the command.
    ///
    /// Calling this more than once on the same command may result in unexpected behaviour.
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision>;
}

impl CommandFdExt for Command {
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision> {
        // Validate that there are no conflicting mappings to the same child FD.
        let mut child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
        child_fds.sort_unstable();
        child_fds.dedup();
        if child_fds.len() != mappings.len() {
            return Err(FdMappingCollision);
        }

        // Register the callback to apply the mappings after forking but before execing.
        unsafe {
            self.pre_exec(move || map_fds(&mappings));
        }

        Ok(())
    }
}

fn map_fds(mappings: &[FdMapping]) -> io::Result<()> {
    if mappings.is_empty() {
        // No need to do anything, and finding first_unused_fd would fail.
        return Ok(());
    }

    // Find the first FD which is higher than any parent or child FD in the mapping, so we can
    // safely use it and higher FDs as temporary FDs. There may be other files open with these FDs,
    // so we still need to ensure we don't conflict with them.
    let first_safe_fd = mappings
        .iter()
        .map(|mapping| max(mapping.parent_fd, mapping.child_fd))
        .max()
        .unwrap()
        + 1;

    // If any parent FDs conflict with child FDs, then first duplicate them to a temporary FD which
    // is clear of either range.
    let child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
    let mappings = mappings
        .iter()
        .map(|mapping| {
            Ok(if child_fds.contains(&mapping.parent_fd) {
                let temporary_fd =
                    fcntl(mapping.parent_fd, FcntlArg::F_DUPFD_CLOEXEC(first_safe_fd))?;
                FdMapping {
                    parent_fd: temporary_fd,
                    child_fd: mapping.child_fd,
                }
            } else {
                mapping.to_owned()
            })
        })
        .collect::<nix::Result<Vec<_>>>()
        .map_err(nix_to_io_error)?;

    // Now we can actually duplicate FDs to the desired child FDs.
    for mapping in mappings {
        // This closes child_fd if it is already open as something else, and clears the FD_CLOEXEC
        // flag on child_fd.
        dup2(mapping.parent_fd, mapping.child_fd).map_err(nix_to_io_error)?;
    }

    Ok(())
}

/// Convert a [`nix::Error`] to a [`std::io::Error`].
fn nix_to_io_error(error: nix::Error) -> io::Error {
    if let nix::Error::Sys(errno) = error {
        io::Error::from_raw_os_error(errno as i32)
    } else {
        io::Error::new(ErrorKind::Other, error)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nix::unistd::close;
    use std::collections::HashSet;
    use std::fs::{read_dir, File};
    use std::os::unix::io::AsRawFd;
    use std::process::Output;
    use std::str;

    #[test]
    fn conflicting_mappings() {
        close_excess_fds();

        let mut command = Command::new("ls");

        // The same mapping can't be included twice.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
            ]),
            Err(FdMappingCollision)
        );

        // Mapping two different FDs to the same FD isn't allowed either.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 6,
                },
            ]),
            Err(FdMappingCollision)
        );
    }

    #[test]
    fn no_mappings() {
        close_excess_fds();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        assert_eq!(command.fd_mappings(vec![]), Ok(()));

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3]);
    }

    #[test]
    fn one_mapping() {
        close_excess_fds();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file an otherwise unused FD.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 5,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, 5]);
    }

    #[test]
    fn swap_mappings() {
        close_excess_fds();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        let fd2 = file2.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    parent_fd: fd1,
                    child_fd: fd2,
                },
                FdMapping {
                    parent_fd: fd2,
                    child_fd: fd1,
                },
            ]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, fd1, fd2]);
    }

    #[test]
    fn map_stdin() {
        close_excess_fds();

        let mut command = Command::new("cat");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file to stdin.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 0,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        assert!(output.status.success());
        assert_eq!(output.stdout, b"test 1");
    }

    /// Parse the output of ls into a set of filenames
    fn parse_ls_output(output: &[u8]) -> HashSet<String> {
        str::from_utf8(output)
            .unwrap()
            .split_terminator("\n")
            .map(str::to_owned)
            .collect()
    }

    /// Check that the output of `ls /proc/self/fd` contains the expected set of FDs.
    fn expect_fds(output: &Output, expected_fds: &[RawFd]) {
        assert!(output.status.success());
        let expected_fds: HashSet<String> = expected_fds.iter().map(RawFd::to_string).collect();
        assert_eq!(parse_ls_output(&output.stdout), expected_fds);
    }

    /// Close all file descriptors apart from stdin, stdout and stderr.
    ///
    /// This is necessary because GitHub Actions opens a bunch of others for some reason.
    fn close_excess_fds() {
        let dir = read_dir("/proc/self/fd").unwrap();
        for entry in dir {
            let entry = entry.unwrap();
            let fd: RawFd = entry.file_name().to_str().unwrap().parse().unwrap();
            if fd > 3 {
                close(fd).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>First cut implementation.<commit_after>#[derive(Clone,Debug)]
pub struct PresortedVec<T> {
    unsorted: Vec<T>,
    sorted: Vec<T>,
    permutation: Vec<usize>,
    is_sorted: bool,
}

impl<T> PresortedVec<T>
where T: Ord + Clone {
    pub fn new() -> PresortedVec<T> {
        PresortedVec {
            unsorted: Vec::new(),
            sorted: Vec::new(),
            permutation: Vec::new(),
            is_sorted: true,
        }
    }
    pub fn sorted(&mut self) -> &[T] {
        if !self.is_sorted {
            self.sorted.clear();
            self.permutation.resize(self.unsorted.len(), 0);
            let mut pairs: Vec<(T, usize)> = self.unsorted.iter().enumerate().map(|(x,y)| (y.clone(),x)).collect();
            pairs.sort();
            for (sorted_index, (value, index)) in pairs.drain(..).enumerate() {
                self.permutation[index] = sorted_index;
                self.sorted.push(value);
            }
            self.is_sorted = true;
        }
        &*self.sorted
    }
    pub fn unsorted(&self) -> &[T] {
        &*self.unsorted
    }
    pub fn get(&self, index: usize) -> Option<&T> {
        self.unsorted.get(index)
    }
    pub fn last(&self) -> Option<&T> {
        self.unsorted.last()
    }
    pub fn set(&mut self, index: usize, value: T) {
        if self.is_sorted {
            let sorted_index = self.permutation[index];
            let sorted_before = self.sorted.get(sorted_index.wrapping_sub(1)).map(|before| before <= &value).unwrap_or(true);
            let sorted_after = self.sorted.get(sorted_index.wrapping_add(1)).map(|after| &value <= after).unwrap_or(true);
            if sorted_before && sorted_after {
                self.sorted[sorted_index] = value.clone();
            } else {
                self.is_sorted = false;
            }
        }
        self.unsorted[index] = value;
    }
    pub fn push(&mut self, value: T) {
        if self.is_sorted {
            let sorted_index = self.sorted.len();
            let sorted_before = self.sorted.get(sorted_index.wrapping_sub(1)).map(|before| before <= &value).unwrap_or(true);
            if sorted_before {
                self.permutation.push(sorted_index);
                self.sorted.push(value.clone());
            } else {
                self.is_sorted = false;
            }
        }
        self.unsorted.push(value);
    }
    pub fn len(&self) -> usize {
        self.unsorted.len()
    }
    pub fn truncate(&mut self, length: usize) {
        self.unsorted.truncate(length);
        self.is_sorted = false;
    }
}
<|endoftext|>


<commit_before>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
    fn append(&mut self, e: Element) {
        self.elements.push(e)
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(module {}\n", self.name));
        for e in &self.elements {
            try!(write!(f, "{}\n", e))
        };
        write!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Layer => write!(f, "(layer)"),
            Element::Descr => write!(f, "(desc)"),
            Element::FpText => write!(f, "(fp_text)"),
            Element::Pad => write!(f, "(pad)"),
            Element::FpPoly => write!(f, "(fp_poly)"),
            Element::FpLine => write!(f, "(fp_line)"),
            Element::FpCircle => write!(f, "(fp_circle)"),
        }
    }
}

fn parse_element(s: &Sexp) -> ERes<Element> {
    Ok(Element::Layer)
}

fn parse_module_list(v: Vec<Sexp>) -> ERes<Module> {
    let mut module = (match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => return err("expecting module name")
            }
        }
        _ => err("expecting module")
    }).unwrap();
    for e in &v[2..] {
        let el = try!(parse_element(e));
        module.append(el)
    }
    Ok(module)
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => err("IOError") // TODO...
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<commit_msg>more parsing work<commit_after>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
    fn append(&mut self, e: Element) {
        self.elements.push(e)
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(module {}\n", self.name));
        for e in &self.elements {
            try!(write!(f, "{}\n", e))
        };
        write!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Layer => write!(f, "(layer)"),
            Element::Descr => write!(f, "(descr)"),
            Element::FpText => write!(f, "(fp_text)"),
            Element::Pad => write!(f, "(pad)"),
            Element::FpPoly => write!(f, "(fp_poly)"),
            Element::FpLine => write!(f, "(fp_line)"),
            Element::FpCircle => write!(f, "(fp_circle)"),
        }
    }
}

fn parse_layer(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Layer)
}
fn parse_descr(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Descr)
}
fn parse_fp_text(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpText)
}
fn parse_pad(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Pad)
}
fn parse_fp_poly(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpPoly)
}
fn parse_fp_line(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpLine)
}
fn parse_fp_circle(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpCircle)
}

fn parse_element_list(v: &Vec<Sexp>) -> ERes<Element> {
    match v[0] {
        Sexp::Atom(Atom::S(ref s)) => {
            match &s[..] {
                "layer" => parse_layer(v),
                "descr" => parse_descr(v),
                "fp_text" => parse_fp_text(v),
                "pad" => parse_pad(v),
                "fp_poly" => parse_fp_poly(v),
                "fp_line" => parse_fp_line(v),
                "fp_circle" => parse_fp_circle(v),
                _ => err("unknown element in module")
            }
        }
        _ => err("expecting atom")
    }
}

fn parse_element(s: &Sexp) -> ERes<Element> {
    match *s {
        Sexp::List(ref v) => parse_element_list(&v),
        _ => err("expecting element list in module")
    }
}

fn parse_module_list(v: &Vec<Sexp>) -> ERes<Module> {
    let mut module = (match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => return err("expecting module name")
            }
        }
        _ => err("expecting module")
    }).unwrap();
    for e in &v[2..] {
        let el = try!(parse_element(e));
        module.append(el)
    }
    Ok(module)
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(&v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => err("IOError") // TODO...
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate pest;
#[macro_use]
extern crate pest_derive;

#[cfg(debug_assertions)]
const _GRAMMER: &'static str = include_str!("grammer.pest");

#[derive(Parser)]
#[grammar = "grammer.pest"]
struct TurtleParser;

#[test]
fn collection_test() {
    parses_to! {
        parser: TurtleParser,
        input: "(<http://www.example.com> ([ ]))",
        rule: Rule::collection,
        tokens: [
            collection(0, 32, [
                object(1, 25, [
                    iri(1, 25, [ iriref(1, 25) ])
                ]),
                object(26, 31, [
                    collection(26, 31, [
                        object(27, 30, [ blank_node(27, 30, [ anon(27, 30) ]) ])
                    ])
                ])
            ])
        ]
    };
}

#[test]
fn numeric_literal_test() {
    parses_to! {
        parser: TurtleParser,
        input: "+10",
        rule: Rule::numeric_literal,
        tokens: [
            numeric_literal(0, 3, [
                integer(0, 3)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "+1.0",
        rule: Rule::numeric_literal,
        tokens: [
            numeric_literal(0, 4, [
                decimal(0, 4)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "+1.0e-9",
        rule: Rule::numeric_literal,
        tokens: [
            numeric_literal(0, 7, [
                double(0, 7)
            ])
        ]
    };
}

#[test]
fn rdf_literal_test() {
    parses_to! {
        parser: TurtleParser,
        input: r#""test"@en"#,
        rule: Rule::rdf_literal,
        tokens: [
            rdf_literal(0, 9, [
                string(0, 6, [
                    string_literal_quote(0, 6)
                ]),
                langtag(6, 9)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#""test"^^<http://www.example.com>"#,
        rule: Rule::rdf_literal,
        tokens: [
            rdf_literal(0, 32, [
                string(0, 6, [
                    string_literal_quote(0, 6)
                ]),
                iri(8, 32, [
                    iriref(8, 32)
                ])
            ])
        ]
    };
}

#[test]
fn boolean_literal_test() {
    parses_to! {
        parser: TurtleParser,
        input: "true",
        rule: Rule::boolean_literal,
        tokens: [
            boolean_literal(0, 4)
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "false",
        rule: Rule::boolean_literal,
        tokens: [
            boolean_literal(0, 5)
        ]
    };
}

#[test]
fn string_test() {
    parses_to! {
        parser: TurtleParser,
        input: r#""test""#,
        rule: Rule::string,
        tokens: [
            string(0, 6, [
                string_literal_quote(0, 6)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#"'test'"#,
        rule: Rule::string,
        tokens: [
            string(0, 6, [
                string_literal_single_quote(0, 6)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#""""test"test""""#,
        rule: Rule::string,
        tokens: [
            string(0, 15, [
                string_literal_long_quote(0, 15)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#"'''test'test'''"#,
        rule: Rule::string,
        tokens: [
            string(0, 15, [
                string_literal_long_single_quote(0, 15)
            ])
        ]
    };
}

#[test]
fn iri_test() {
    parses_to! {
        parser: TurtleParser,
        input: "<http://www.example.com>",
        rule: Rule::iri,
        tokens: [
            iri(0, 24, [
                iriref(0, 24)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "foaf:Person",
        rule: Rule::iri,
        tokens: [
            iri(0, 11, [
                prefixed_name(0, 11, [
                    pname_ln(0, 11)
                ])
            ])
        ]
    };
}

#[test]
fn prefixd_name_test() {
    parses_to! {
        parser: TurtleParser,
        input: "foaf:",
        rule: Rule::prefixed_name,
        tokens: [
            prefixed_name(0, 5, [
                pname_ns(0, 5)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "foaf:Person",
        rule: Rule::prefixed_name,
        tokens: [
            prefixed_name(0, 11, [
                pname_ln(0, 11)
            ])
        ]
    };
}

#[test]
fn blank_node_test() {
    parses_to! {
        parser: TurtleParser,
        input: "_:blank",
        rule: Rule::blank_node,
        tokens: [
            blank_node(0, 7, [
                blank_node_label(0, 7)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "[     ]",
        rule: Rule::blank_node,
        tokens: [
            blank_node(0, 7, [
                anon(0, 7)
            ])
        ]
    };
}
<commit_msg>Add blank_node_property_list_test<commit_after>#[macro_use]
extern crate pest;
#[macro_use]
extern crate pest_derive;

#[cfg(debug_assertions)]
const _GRAMMER: &'static str = include_str!("grammer.pest");

#[derive(Parser)]
#[grammar = "grammer.pest"]
struct TurtleParser;

#[test]
fn blank_node_property_list_test() {
    parses_to! {
        parser: TurtleParser,
        input: "[<http://verb> <http://object1>, <http://object2>; a <http://object3>]",
        rule: Rule::blank_node_property_list,
        tokens: [
            blank_node_property_list(0, 70, [
                predicate_object_list(1, 69, [
                    verb(1, 14, [ predicate(1, 14, [ iri(1, 14, [ iriref(1, 14)]) ]) ]),
                    object_list(15, 49, [
                        object(15, 31, [ iri(15, 31, [ iriref(15, 31)]) ]),
                        object(33, 49, [ iri(33, 49, [ iriref(33, 49)]) ])
                    ]),
                    verb(51, 52),
                    object_list(53, 69, [
                        object(53, 69, [ iri(53, 69, [ iriref(53, 69)]) ])
                    ])
                ])
            ])
        ]
    };
}

#[test]
fn collection_test() {
    parses_to! {
        parser: TurtleParser,
        input: "(<http://www.example.com> ([ ]))",
        rule: Rule::collection,
        tokens: [
            collection(0, 32, [
                object(1, 25, [
                    iri(1, 25, [ iriref(1, 25) ])
                ]),
                object(26, 31, [
                    collection(26, 31, [
                        object(27, 30, [ blank_node(27, 30, [ anon(27, 30) ]) ])
                    ])
                ])
            ])
        ]
    };
}

#[test]
fn numeric_literal_test() {
    parses_to! {
        parser: TurtleParser,
        input: "+10",
        rule: Rule::numeric_literal,
        tokens: [
            numeric_literal(0, 3, [
                integer(0, 3)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "+1.0",
        rule: Rule::numeric_literal,
        tokens: [
            numeric_literal(0, 4, [
                decimal(0, 4)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "+1.0e-9",
        rule: Rule::numeric_literal,
        tokens: [
            numeric_literal(0, 7, [
                double(0, 7)
            ])
        ]
    };
}

#[test]
fn rdf_literal_test() {
    parses_to! {
        parser: TurtleParser,
        input: r#""test"@en"#,
        rule: Rule::rdf_literal,
        tokens: [
            rdf_literal(0, 9, [
                string(0, 6, [
                    string_literal_quote(0, 6)
                ]),
                langtag(6, 9)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#""test"^^<http://www.example.com>"#,
        rule: Rule::rdf_literal,
        tokens: [
            rdf_literal(0, 32, [
                string(0, 6, [
                    string_literal_quote(0, 6)
                ]),
                iri(8, 32, [
                    iriref(8, 32)
                ])
            ])
        ]
    };
}

#[test]
fn boolean_literal_test() {
    parses_to! {
        parser: TurtleParser,
        input: "true",
        rule: Rule::boolean_literal,
        tokens: [
            boolean_literal(0, 4)
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "false",
        rule: Rule::boolean_literal,
        tokens: [
            boolean_literal(0, 5)
        ]
    };
}

#[test]
fn string_test() {
    parses_to! {
        parser: TurtleParser,
        input: r#""test""#,
        rule: Rule::string,
        tokens: [
            string(0, 6, [
                string_literal_quote(0, 6)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#"'test'"#,
        rule: Rule::string,
        tokens: [
            string(0, 6, [
                string_literal_single_quote(0, 6)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#""""test"test""""#,
        rule: Rule::string,
        tokens: [
            string(0, 15, [
                string_literal_long_quote(0, 15)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: r#"'''test'test'''"#,
        rule: Rule::string,
        tokens: [
            string(0, 15, [
                string_literal_long_single_quote(0, 15)
            ])
        ]
    };
}

#[test]
fn iri_test() {
    parses_to! {
        parser: TurtleParser,
        input: "<http://www.example.com>",
        rule: Rule::iri,
        tokens: [
            iri(0, 24, [
                iriref(0, 24)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "foaf:Person",
        rule: Rule::iri,
        tokens: [
            iri(0, 11, [
                prefixed_name(0, 11, [
                    pname_ln(0, 11)
                ])
            ])
        ]
    };
}

#[test]
fn prefixd_name_test() {
    parses_to! {
        parser: TurtleParser,
        input: "foaf:",
        rule: Rule::prefixed_name,
        tokens: [
            prefixed_name(0, 5, [
                pname_ns(0, 5)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "foaf:Person",
        rule: Rule::prefixed_name,
        tokens: [
            prefixed_name(0, 11, [
                pname_ln(0, 11)
            ])
        ]
    };
}

#[test]
fn blank_node_test() {
    parses_to! {
        parser: TurtleParser,
        input: "_:blank",
        rule: Rule::blank_node,
        tokens: [
            blank_node(0, 7, [
                blank_node_label(0, 7)
            ])
        ]
    };

    parses_to! {
        parser: TurtleParser,
        input: "[     ]",
        rule: Rule::blank_node,
        tokens: [
            blank_node(0, 7, [
                anon(0, 7)
            ])
        ]
    };
}
<|endoftext|>


<commit_before>//! Additive and multiplicative identities

#![deny(missing_docs, warnings)]
#![feature(macro_rules)]

/// Multiplicative identity
pub trait One {
    /// Returns one
    fn one() -> Self;
}

/// Additive identity
pub trait Zero {
    /// Returns zero
    fn zero() -> Self;
}

macro_rules! float {
    ($($ty:ty),+) => {$(
        impl One for $ty { fn one() -> $ty { 1. } }
        impl Zero for $ty { fn zero() -> $ty { 0. } })+
    }
}

float!(f32, f64)

macro_rules! int {
    ($($ty:ty),+) => {$(
        impl One for $ty { fn one() -> $ty { 1 } }
        impl Zero for $ty { fn zero() -> $ty { 0 } })+
    }
}

int!(i8, i16, i32, i64, int, u8, u16, u32, u64)
<commit_msg>fix(lib): adapt to changes in macro parsing<commit_after>//! Additive and multiplicative identities

#![deny(missing_docs, warnings)]
#![feature(macro_rules)]

/// Multiplicative identity
pub trait One {
    /// Returns one
    fn one() -> Self;
}

/// Additive identity
pub trait Zero {
    /// Returns zero
    fn zero() -> Self;
}

macro_rules! float {
    ($($ty:ty),+) => {$(
        impl One for $ty { fn one() -> $ty { 1. } }
        impl Zero for $ty { fn zero() -> $ty { 0. } })+
    }
}

float!(f32, f64);

macro_rules! int {
    ($($ty:ty),+) => {$(
        impl One for $ty { fn one() -> $ty { 1 } }
        impl Zero for $ty { fn zero() -> $ty { 0 } })+
    }
}

int!(i8, i16, i32, i64, int, u8, u16, u32, u64);
<|endoftext|>