<commit_before>
//! A different way of thinking about states.
//!
//! All objects are stored in a state.

use HashMap = collections::HashMap;

/// Keeps track of the current state of objects.
pub struct StateMachine<Object> {
    current: State<CurrentState<Object>>,
    states: State<State<Object>>,
}

impl<T> StateMachine<T> {
    /// Returns the current value of object by looking up in correct state.
    #[inline(always)]
    pub fn val<'a>(&'a self, obj: uint) -> &'a T {
        let &CurrentState{ state: state } = self.current.objects.get(&obj);
        self.states.objects.get(&state).objects.get(&obj)
    }
}

/// Stores the current state of an object.
struct CurrentState<Object> {
    state: uint,
}

/// Contains objects.
pub struct State<Object> {
    objects: HashMap<uint, Object>,
}

impl<T> State<T> {
    /// Moves an object from one state to another.
    pub fn move_to(&mut self, to: &mut State<T>, obj: uint) {
        let pop = self.objects.pop(&obj);
        match pop {
            None => {},
            Some(val) => { to.objects.insert(obj, val); }
        }
    }
}

/// Updates on delta information.
///
/// For any type implementing this trait,
/// there is a `State<T>` and `StateMachine<T>`
/// which also implements this trait.
pub trait UpdateDelta<D> {
    /// Updates all the objects with delta information.
    fn update(&mut self, delta: &D);
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for State<T> {
    fn update(&mut self, delta: &D) {
        for (_, obj) in self.objects.mut_iter() {
            obj.update(delta);
        }
    }
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for StateMachine<T> {
    fn update(&mut self, delta: &D) {
        for (_, state) in self.states.objects.mut_iter() {
            state.update(delta);
        }
    }
}

<commit_msg>Added tracking of update functions<commit_after>
//! A different way of thinking about states.
//!
//! All objects are stored in a state.

use HashMap = collections::HashMap;

pub type UpdateFunction<T, D> = fn (obj: &mut T, delta: &D);

/// Keeps track of the current state of objects.
/// Also keeps an update function per state.
/// This is because otherwise all states require same logic.
pub struct StateMachine<Object, Delta> {
    current: State<CurrentState<Object>>,
    states: State<State<Object>>,
    update_functions: State<UpdateFunction<Object, Delta>>
}

impl<T, D> StateMachine<T, D> {
    /// Adds a new state.
    pub fn add_state(
            &mut self,
            state_id: uint,
            state: State<T>,
            update: Option<UpdateFunction<T, D>>
    ) {
        self.states.objects.insert(state_id, state);
        match update {
            None => {},
            Some(fun) => { self.update_functions.objects.insert(state_id, fun); }
        }
    }

    /// Returns the current value of object by looking up in correct state.
    #[inline(always)]
    pub fn val<'a>(&'a self, obj: uint) -> &'a T {
        let &CurrentState{ state: state } = self.current.objects.get(&obj);
        self.states.objects.get(&state).objects.get(&obj)
    }
}

/// Stores the current state of an object.
struct CurrentState<Object> {
    state: uint,
}

/// Contains objects.
pub struct State<Object> {
    objects: HashMap<uint, Object>,
}

impl<T> State<T> {
    /// Moves an object from one state to another.
    pub fn move_to(&mut self, to: &mut State<T>, obj: uint) {
        let pop = self.objects.pop(&obj);
        match pop {
            None => {},
            Some(val) => { to.objects.insert(obj, val); }
        }
    }
}

/// Updates on delta information.
///
/// For any type implementing this trait,
/// there is a `State<T>` and `StateMachine<T>`
/// which also implements this trait.
pub trait UpdateDelta<D> {
    /// Updates all the objects with delta information.
    fn update(&mut self, delta: &D);
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for State<T> {
    fn update(&mut self, delta: &D) {
        for (_, obj) in self.objects.mut_iter() {
            obj.update(delta);
        }
    }
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for StateMachine<T, D> {
    fn update(&mut self, delta: &D) {
        for (id_state, state) in self.states.objects.mut_iter() {
            match self.update_functions.objects.find(id_state) {
                    None => {},
                    Some(fun) => {
                        for (_, obj) in state.objects.mut_iter() {
                            (*fun)(obj, delta);
                        }
                    }
            }
        }
    }
}

<|endoftext|>


<commit_before>const CLEARV: u8 = 0b0000_0000;
const BOLD: u8 = 0b0000_0001;
const UNDERLINE: u8 = 0b0000_0010;
const REVERSED: u8 = 0b0000_0100;
const ITALIC: u8 = 0b0000_1000;
const BLINK: u8 = 0b0001_0000;
const HIDDEN: u8 = 0b0010_0000;
const DIMMED: u8 = 0b0100_0000;
const STRIKETHROUGH: u8 = 0b1000_0000;

static STYLES: [(u8, Styles); 8] = [
    (BOLD, Styles::Bold),
    (DIMMED, Styles::Dimmed),
    (UNDERLINE, Styles::Underline),
    (REVERSED, Styles::Reversed),
    (ITALIC, Styles::Italic),
    (BLINK, Styles::Blink),
    (HIDDEN, Styles::Hidden),
    (STRIKETHROUGH, Styles::Strikethrough),
];

pub static CLEAR: Style = Style(CLEARV);

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Style(u8);

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Styles {
    Clear,
    Bold,
    Dimmed,
    Underline,
    Reversed,
    Italic,
    Blink,
    Hidden,
    Strikethrough,
}

impl Styles {
    fn to_str<'a>(self) -> &'a str {
        match self {
            Styles::Clear => "", // unreachable, but we don't want to panic
            Styles::Bold => "1",
            Styles::Dimmed => "2",
            Styles::Italic => "3",
            Styles::Underline => "4",
            Styles::Blink => "5",
            Styles::Reversed => "7",
            Styles::Hidden => "8",
            Styles::Strikethrough => "9",
        }
    }

    fn to_u8(self) -> u8 {
        match self {
            Styles::Clear => CLEARV,
            Styles::Bold => BOLD,
            Styles::Dimmed => DIMMED,
            Styles::Italic => ITALIC,
            Styles::Underline => UNDERLINE,
            Styles::Blink => BLINK,
            Styles::Reversed => REVERSED,
            Styles::Hidden => HIDDEN,
            Styles::Strikethrough => STRIKETHROUGH,
        }
    }

    fn from_u8(u: u8) -> Option<Vec<Styles>> {
        if u == CLEARV {
            return None;
        }

        let res: Vec<Styles> = STYLES
            .into_iter()
            .filter(|&&(ref mask, _)| (0 != (u & mask)))
            .map(|&(_, value)| value)
            .collect();
        if res.is_empty() {
            None
        } else {
            Some(res)
        }
    }
}

impl Style {
    pub fn to_str(self) -> String {
        let styles = match Styles::from_u8(self.0) {
            None => return String::new(),
            Some(s) => s,
        };
        let mut res = String::new();
        let mut first = true;

        for style in styles.iter().map(|s| s.to_str()) {
            if first {
                res.push_str(style);
                first = false;
                continue;
            } else {
                res.push(';');
                res.push_str(style)
            }
        }
        res
    }

    pub fn new(from: Styles) -> Style {
        Style(from.to_u8())
    }

    pub fn from_both(one: Style, two: Styles) -> Style {
        Style(one.0 | two.to_u8())
    }
}

#[cfg(test)]
mod tests {

    mod u8_to_styles_invalid_is_none {
        use super::super::CLEARV;
        use super::super::{Style, Styles};

        #[test]
        fn empty_is_none() {
            assert_eq!(None, Styles::from_u8(CLEARV))
        }

    }

    mod u8_to_styles_isomorphism {
        use super::super::Styles;
        use super::super::{
            BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE,
        };

        macro_rules! value_isomorph {
            ($name:ident, $value:expr) => {
                #[test]
                fn $name() {
                    let u = Styles::from_u8($value);
                    assert!(
                        u.is_some(),
                        "{}: Styles::from_u8 -> None",
                        stringify!($value)
                    );
                    let u = u.unwrap();
                    assert!(
                        u.len() == 1,
                        "{}: Styles::from_u8 found {} styles (expected 1)",
                        stringify!($value),
                        u.len()
                    );
                    assert!(
                        u[0].to_u8() == $value,
                        "{}: to_u8() doesn't match its const value",
                        stringify!($value)
                    );
                }
            };
        }

        value_isomorph!(bold, BOLD);
        value_isomorph!(underline, UNDERLINE);
        value_isomorph!(reversed, REVERSED);
        value_isomorph!(italic, ITALIC);
        value_isomorph!(blink, BLINK);
        value_isomorph!(hidden, HIDDEN);
        value_isomorph!(dimmed, DIMMED);
        value_isomorph!(strikethrough, STRIKETHROUGH);
    }

    mod styles_combine_complex {
        use super::super::Styles::*;
        use super::super::{Style, Styles};
        use super::super::{
            BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE,
        };

        fn style_from_multiples(styles: &[Styles]) -> Style {
            let mut res = Style::new(styles[0]);
            for s in &styles[1..] {
                res = Style::from_both(res, *s)
            }
            res
        }

        macro_rules! test_aggreg {
            ($styles:expr, $expect:expr) => {{
                let v = style_from_multiples($styles);
                let r = Styles::from_u8(v.0).expect("should find styles");
                assert_eq!(&$expect as &[Styles], &r[..])
            }};
        }

        #[test]
        fn aggreg1() {
            let styles: &[Styles] = &[Bold, Bold, Bold];
            test_aggreg!(styles, [Bold])
        }

        #[test]
        fn aggreg2() {
            let styles: &[Styles] = &[Italic, Italic, Bold, Bold];
            test_aggreg!(styles, [Bold, Italic])
        }

        #[test]
        fn aggreg3() {
            let styles: &[Styles] = &[Bold, Italic, Bold];
            test_aggreg!(styles, [Bold, Italic])
        }

        macro_rules! test_combine {
            ($styles:expr) => {{
                let v = style_from_multiples($styles);
                let r = Styles::from_u8(v.0).expect("should find styles");
                assert_eq!($styles, &r[..])
            }};
        }

        #[test]
        fn two1() {
            let s: &[Styles] = &[Bold, Underline];
            test_combine!(s)
        }

        #[test]
        fn two2() {
            let s: &[Styles] = &[Underline, Italic];
            test_combine!(s)
        }

        #[test]
        fn two3() {
            let s: &[Styles] = &[Bold, Italic];
            test_combine!(s)
        }

        #[test]
        fn three1() {
            let s: &[Styles] = &[Bold, Underline, Italic];
            test_combine!(s)
        }

        #[test]
        fn three2() {
            let s: &[Styles] = &[Dimmed, Underline, Italic];
            test_combine!(s)
        }

        #[test]
        fn four() {
            let s: &[Styles] = &[Dimmed, Underline, Italic, Hidden];
            test_combine!(s)
        }

        #[test]
        fn five() {
            let s: &[Styles] = &[Dimmed, Underline, Italic, Blink, Hidden];
            test_combine!(s)
        }

        #[test]
        fn six() {
            let s: &[Styles] = &[Bold, Dimmed, Underline, Italic, Blink, Hidden];
            test_combine!(s)
        }

        #[test]
        fn all() {
            let s: &[Styles] = &[
                Bold,
                Dimmed,
                Underline,
                Reversed,
                Italic,
                Blink,
                Hidden,
                Strikethrough,
            ];
            test_combine!(s)
        }

    }
}
<commit_msg>Use `join` instead of a `first` flag.<commit_after>const CLEARV: u8 = 0b0000_0000;
const BOLD: u8 = 0b0000_0001;
const UNDERLINE: u8 = 0b0000_0010;
const REVERSED: u8 = 0b0000_0100;
const ITALIC: u8 = 0b0000_1000;
const BLINK: u8 = 0b0001_0000;
const HIDDEN: u8 = 0b0010_0000;
const DIMMED: u8 = 0b0100_0000;
const STRIKETHROUGH: u8 = 0b1000_0000;

static STYLES: [(u8, Styles); 8] = [
    (BOLD, Styles::Bold),
    (DIMMED, Styles::Dimmed),
    (UNDERLINE, Styles::Underline),
    (REVERSED, Styles::Reversed),
    (ITALIC, Styles::Italic),
    (BLINK, Styles::Blink),
    (HIDDEN, Styles::Hidden),
    (STRIKETHROUGH, Styles::Strikethrough),
];

pub static CLEAR: Style = Style(CLEARV);

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Style(u8);

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Styles {
    Clear,
    Bold,
    Dimmed,
    Underline,
    Reversed,
    Italic,
    Blink,
    Hidden,
    Strikethrough,
}

impl Styles {
    fn to_str<'a>(self) -> &'a str {
        match self {
            Styles::Clear => "", // unreachable, but we don't want to panic
            Styles::Bold => "1",
            Styles::Dimmed => "2",
            Styles::Italic => "3",
            Styles::Underline => "4",
            Styles::Blink => "5",
            Styles::Reversed => "7",
            Styles::Hidden => "8",
            Styles::Strikethrough => "9",
        }
    }

    fn to_u8(self) -> u8 {
        match self {
            Styles::Clear => CLEARV,
            Styles::Bold => BOLD,
            Styles::Dimmed => DIMMED,
            Styles::Italic => ITALIC,
            Styles::Underline => UNDERLINE,
            Styles::Blink => BLINK,
            Styles::Reversed => REVERSED,
            Styles::Hidden => HIDDEN,
            Styles::Strikethrough => STRIKETHROUGH,
        }
    }

    fn from_u8(u: u8) -> Option<Vec<Styles>> {
        if u == CLEARV {
            return None;
        }

        let res: Vec<Styles> = STYLES
            .into_iter()
            .filter(|&&(ref mask, _)| (0 != (u & mask)))
            .map(|&(_, value)| value)
            .collect();
        if res.is_empty() {
            None
        } else {
            Some(res)
        }
    }
}

impl Style {
    pub fn to_str(self) -> String {
        let styles = Styles::from_u8(self.0).unwrap_or(Vec::new());
        styles
            .iter()
            .map(|s| s.to_str())
            .collect::<Vec<&str>>()
            .join(";")
    }

    pub fn new(from: Styles) -> Style {
        Style(from.to_u8())
    }

    pub fn from_both(one: Style, two: Styles) -> Style {
        Style(one.0 | two.to_u8())
    }
}

#[cfg(test)]
mod tests {

    mod u8_to_styles_invalid_is_none {
        use super::super::CLEARV;
        use super::super::{Style, Styles};

        #[test]
        fn empty_is_none() {
            assert_eq!(None, Styles::from_u8(CLEARV))
        }

    }

    mod u8_to_styles_isomorphism {
        use super::super::Styles;
        use super::super::{
            BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE,
        };

        macro_rules! value_isomorph {
            ($name:ident, $value:expr) => {
                #[test]
                fn $name() {
                    let u = Styles::from_u8($value);
                    assert!(
                        u.is_some(),
                        "{}: Styles::from_u8 -> None",
                        stringify!($value)
                    );
                    let u = u.unwrap();
                    assert!(
                        u.len() == 1,
                        "{}: Styles::from_u8 found {} styles (expected 1)",
                        stringify!($value),
                        u.len()
                    );
                    assert!(
                        u[0].to_u8() == $value,
                        "{}: to_u8() doesn't match its const value",
                        stringify!($value)
                    );
                }
            };
        }

        value_isomorph!(bold, BOLD);
        value_isomorph!(underline, UNDERLINE);
        value_isomorph!(reversed, REVERSED);
        value_isomorph!(italic, ITALIC);
        value_isomorph!(blink, BLINK);
        value_isomorph!(hidden, HIDDEN);
        value_isomorph!(dimmed, DIMMED);
        value_isomorph!(strikethrough, STRIKETHROUGH);
    }

    mod styles_combine_complex {
        use super::super::Styles::*;
        use super::super::{Style, Styles};
        use super::super::{
            BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE,
        };

        fn style_from_multiples(styles: &[Styles]) -> Style {
            let mut res = Style::new(styles[0]);
            for s in &styles[1..] {
                res = Style::from_both(res, *s)
            }
            res
        }

        macro_rules! test_aggreg {
            ($styles:expr, $expect:expr) => {{
                let v = style_from_multiples($styles);
                let r = Styles::from_u8(v.0).expect("should find styles");
                assert_eq!(&$expect as &[Styles], &r[..])
            }};
        }

        #[test]
        fn aggreg1() {
            let styles: &[Styles] = &[Bold, Bold, Bold];
            test_aggreg!(styles, [Bold])
        }

        #[test]
        fn aggreg2() {
            let styles: &[Styles] = &[Italic, Italic, Bold, Bold];
            test_aggreg!(styles, [Bold, Italic])
        }

        #[test]
        fn aggreg3() {
            let styles: &[Styles] = &[Bold, Italic, Bold];
            test_aggreg!(styles, [Bold, Italic])
        }

        macro_rules! test_combine {
            ($styles:expr) => {{
                let v = style_from_multiples($styles);
                let r = Styles::from_u8(v.0).expect("should find styles");
                assert_eq!($styles, &r[..])
            }};
        }

        #[test]
        fn two1() {
            let s: &[Styles] = &[Bold, Underline];
            test_combine!(s)
        }

        #[test]
        fn two2() {
            let s: &[Styles] = &[Underline, Italic];
            test_combine!(s)
        }

        #[test]
        fn two3() {
            let s: &[Styles] = &[Bold, Italic];
            test_combine!(s)
        }

        #[test]
        fn three1() {
            let s: &[Styles] = &[Bold, Underline, Italic];
            test_combine!(s)
        }

        #[test]
        fn three2() {
            let s: &[Styles] = &[Dimmed, Underline, Italic];
            test_combine!(s)
        }

        #[test]
        fn four() {
            let s: &[Styles] = &[Dimmed, Underline, Italic, Hidden];
            test_combine!(s)
        }

        #[test]
        fn five() {
            let s: &[Styles] = &[Dimmed, Underline, Italic, Blink, Hidden];
            test_combine!(s)
        }

        #[test]
        fn six() {
            let s: &[Styles] = &[Bold, Dimmed, Underline, Italic, Blink, Hidden];
            test_combine!(s)
        }

        #[test]
        fn all() {
            let s: &[Styles] = &[
                Bold,
                Dimmed,
                Underline,
                Reversed,
                Italic,
                Blink,
                Hidden,
                Strikethrough,
            ];
            test_combine!(s)
        }

    }
}
<|endoftext|>


<commit_before>macro_rules! generate_test {
    ( $(($m: ident $nbits: ident => $($block: ident)*)) * ) => {
        $(
            mod $m {
                $(
                    mod $block {
                        mod struct_static {
                            use ::{NbitsVec, $nbits, Nbits};
                            use ::std::mem::size_of;
                            type NV = NbitsVec<$nbits, $block>;
                            #[test]
                            fn unit_bits() {
                                assert_eq!(NV::unit_bits(), $nbits::bits());
                            }
                            #[test]
                            fn buf_unit_bits() {
                                assert_eq!(NV::buf_unit_bits(), size_of::<$block>() * 8);
                            }
                            #[test]
                            fn bit_index_to_buf() {
                                assert_eq!(NV::bit_index_to_buf(0), (0, 0));
                                assert_eq!(NV::bit_index_to_buf(1), (0, 1));
                                let buf_unit_bits = NV::buf_unit_bits();
                                for i in 3..79 {
                                    assert_eq!(NV::bit_index_to_buf(i),
                                                (i / buf_unit_bits, i % buf_unit_bits));
                                }
                            }
                        }
                        mod public_api {
                            use ::{NbitsVec, $nbits, Nbits};
                            type NV = NbitsVec<$nbits, $block>;
                            #[test]
                            fn new() {
                                let vec = NV::new();
                                assert_eq!(vec.capacity(), 0);
                                assert_eq!(vec.len(), 0);
                                assert_eq!(vec.used_buf_cap(), 0);
                                assert_eq!(vec.buf_cap(), 0);
                            }
                            #[test]
                            fn push_pop() {
                                let mut vec = NV::new();
                                vec.push(1);
                                assert!(vec.capacity() > 1);
                                assert_eq!(vec.len(), 1);
                                assert_eq!(vec.used_buf_cap(), 1);
                                assert_eq!(vec.buf_cap(), 1);
                                println!("{:?}", vec);
                                assert_eq!(vec.pop(), Some(1));
                                println!("Push...");
                                for _i in 0..100 {
                                    vec.push(1);
                                }
                                for _i in 0..100 {
                                    println!("{}", _i);
                                    assert_eq!(vec.pop(), Some(1));
                                }
                            }
                            #[test]
                            fn resize() {
                                let mut vec = NV::new();
                                vec.resize(100, 1);
                                assert_eq!(vec.len(), 100);
                                assert!(vec.capacity() >= 100);
                                let bigger_cap = vec.capacity();
                                vec.resize(10, 0);
                                assert_eq!(vec.len(), 10);
                                assert!(vec.capacity() < bigger_cap);
                            }
                            #[test]
                            fn resize_large() {
                                let mut vec = NV::new();
                                const LEN: usize = 10000;
                                vec.resize(LEN, 1);
                                vec.resize(LEN * 2, 2);
                                vec.resize(LEN * 3, 3);
                            }
                        }
                    }
                 )*
            }
         )*
    }
}

generate_test! {
    (n1 N1 => u8 u16 u32 u64 usize)
    (n2 N2 => u8 u16 u32 u64 usize)
    (n3 N3 => u8 u16 u32 u64 usize)
    (n4 N4 => u8 u16 u32 u64 usize)
}
<commit_msg>Add test for element getter/setter.<commit_after>macro_rules! generate_test {
    ( $(($m: ident $nbits: ident => $($block: ident)*)) * ) => {
        $(
            mod $m {
                $(
                    mod $block {
                        mod struct_static {
                            use ::{NbitsVec, $nbits, Nbits};
                            use ::std::mem::size_of;
                            type NV = NbitsVec<$nbits, $block>;
                            #[test]
                            fn unit_bits() {
                                assert_eq!(NV::unit_bits(), $nbits::bits());
                            }
                            #[test]
                            fn buf_unit_bits() {
                                assert_eq!(NV::buf_unit_bits(), size_of::<$block>() * 8);
                            }
                            #[test]
                            fn bit_index_to_buf() {
                                assert_eq!(NV::bit_index_to_buf(0), (0, 0));
                                assert_eq!(NV::bit_index_to_buf(1), (0, 1));
                                let buf_unit_bits = NV::buf_unit_bits();
                                for i in 3..79 {
                                    assert_eq!(NV::bit_index_to_buf(i),
                                                (i / buf_unit_bits, i % buf_unit_bits));
                                }
                            }
                        }
                        mod public_api {
                            use ::{NbitsVec, $nbits};
                            type NV = NbitsVec<$nbits, $block>;
                            #[test]
                            fn new() {
                                let vec = NV::new();
                                assert_eq!(vec.capacity(), 0);
                                assert_eq!(vec.len(), 0);
                                assert_eq!(vec.used_buf_cap(), 0);
                                assert_eq!(vec.buf_cap(), 0);
                            }
                            #[test]
                            fn push_pop() {
                                let mut vec = NV::new();
                                vec.push(1);
                                assert!(vec.capacity() > 1);
                                assert_eq!(vec.len(), 1);
                                assert_eq!(vec.used_buf_cap(), 1);
                                assert_eq!(vec.buf_cap(), 1);
                                println!("{:?}", vec);
                                assert_eq!(vec.pop(), Some(1));
                                println!("Push...");
                                for _i in 0..100 {
                                    vec.push(1);
                                }
                                for _i in 0..100 {
                                    println!("{}", _i);
                                    assert_eq!(vec.pop(), Some(1));
                                }
                            }
                            #[test]
                            fn resize() {
                                let mut vec = NV::new();
                                vec.resize(100, 1);
                                assert_eq!(vec.len(), 100);
                                assert!(vec.capacity() >= 100);
                                let bigger_cap = vec.capacity();
                                vec.resize(10, 0);
                                assert_eq!(vec.len(), 10);
                                assert!(vec.capacity() < bigger_cap);
                            }
                            #[test]
                            fn resize_large() {
                                let mut vec = NV::new();
                                const LEN: usize = 10000;
                                vec.resize(LEN, 1);
                                vec.resize(LEN * 2, 2);
                                vec.resize(LEN * 3, 3);
                            }
                            #[test]
                            fn get_set() {
                                let mut vec = NV::new();
                                vec.resize(100, 0b1111);
                                for i in 0..100 {
                                    vec.set(i, 0);
                                }
                                for i in 0..100 {
                                    let v = vec.get(i);
                                    assert_eq!(v, 0);
                                }
                            }
                        }
                    }
                 )*
            }
         )*
    }
}

generate_test! {
    (n1 N1 => u8 u16 u32 u64 usize)
    (n2 N2 => u8 u16 u32 u64 usize)
    (n3 N3 => u8 u16 u32 u64 usize)
    (n4 N4 => u8 u16 u32 u64 usize)
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops;
use std::slice;
use std::vec;

use features::Features;

/// A sentence with the CoNLL-X annotation layers.
///
/// This data type is a small wrapper around `Vec<Token>` that provides some
/// extra convenience. For example, the implementation of the `Display` trait
/// outputs the sentence in CoNLL-X format.
#[derive(Clone, Debug,PartialEq)]
pub struct Sentence {
    tokens: Vec<Token>,
}

impl Sentence {
    /// Create a new `Sentence` from a vector of tokens.
    pub fn new(tokens: Vec<Token>) -> Sentence {
        Sentence { tokens: tokens }
    }

    /// Get the underlying vector of tokens.
    pub fn as_tokens(&self) -> &Vec<Token> {
        &self.tokens
    }

    /// Get an iterator over the sentence tokens.
    pub fn iter(&self) -> slice::Iter<Token> {
        self.tokens.iter()
    }

    /// Get a mutable iterator over the sentence tokens.
    pub fn iter_mut(&mut self) -> slice::IterMut<Token> {
        self.tokens.iter_mut()
    }
}

impl fmt::Display for Sentence {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let last_id = self.tokens.len() - 1;

        for (id, token) in self.iter().enumerate() {
            if id == last_id {
                write!(f, "{}\t{}", id + 1, token)?
            } else {
                write!(f, "{}\t{}\n", id + 1, token)?
            }
        }

        Ok(())
    }
}

impl ops::Index<usize> for Sentence {
    type Output = Token;
    fn index(&self, index: usize) -> &Token {
        &self.tokens[index]
    }
}

impl ops::IndexMut<usize> for Sentence {
    fn index_mut(&mut self, index: usize) -> &mut Token {
        &mut self.tokens[index]
    }
}

impl IntoIterator for Sentence {
    type Item = Token;
    type IntoIter = vec::IntoIter<Token>;

    fn into_iter(self) -> vec::IntoIter<Token> {
        self.tokens.into_iter()
    }
}

impl<'a> IntoIterator for &'a Sentence {
    type Item = &'a Token;
    type IntoIter = slice::Iter<'a, Token>;

    fn into_iter(self) -> slice::Iter<'a, Token> {
        self.iter()
    }
}

impl<'a> IntoIterator for &'a mut Sentence {
    type Item = &'a mut Token;
    type IntoIter = slice::IterMut<'a, Token>;

    fn into_iter(mut self) -> slice::IterMut<'a, Token> {
        self.iter_mut()
    }
}

/// A builder for `Token`s.
///
/// The `Token` type stores a CoNLL-X token. However, since this format
/// permits a large number of fields, construction of a token can get
/// tedious. This builder provides a fluent interface for creating `Token`s.
pub struct TokenBuilder {
    token: Token,
}

impl TokenBuilder {
    /// Create a `Token` builder with all fields set to absent.
    pub fn new() -> TokenBuilder {
        Default::default()
    }

    /// Set the word form or punctuation symbol.
    pub fn form<S>(mut self, form: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_form(Some(form));
        self
    }

    /// Set the lemma or stem of the word form.
    pub fn lemma<S>(mut self, lemma: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_lemma(Some(lemma));
        self
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn cpos<S>(mut self, cpos: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_cpos(Some(cpos));
        self
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn pos<S>(mut self, pos: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_pos(Some(pos));
        self
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn features(mut self, features: Features) -> TokenBuilder {
        self.token.set_features(Some(features));
        self
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(mut self, head: usize) -> TokenBuilder {
        self.token.set_head(Some(head));
        self
    }

    /// Set the dependency relation to the head of this token.
    pub fn head_rel<S>(mut self, head_rel: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_head_rel(Some(head_rel));
        self
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(mut self, p_head: usize) -> TokenBuilder {
        self.token.set_p_head(Some(p_head));
        self
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn p_head_rel<S>(mut self, p_head_rel: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_p_head_rel(Some(p_head_rel));
        self
    }

    pub fn token(self) -> Token {
        self.token
    }
}

impl Default for TokenBuilder {
    fn default() -> Self {
        TokenBuilder { token: Default::default() }
    }
}

/// A token with the CoNLL-X annotation layers.
///
/// The fields of CoNLLX tokens are described at:
///
/// http://ilk.uvt.nl/conll/
///
/// This type provides exactly the same fields, except for the ID field
/// (since it can be derived from the sentence position of the token).
/// If a particular field is absent (*_* in the CoNLL-X format), its
/// value is `None`.
#[derive(Clone,Debug,PartialEq)]
pub struct Token {
    form: Option<String>,
    lemma: Option<String>,
    cpos: Option<String>,
    pos: Option<String>,
    features: Option<Features>,
    head: Option<usize>,
    head_rel: Option<String>,
    p_head: Option<usize>,
    p_head_rel: Option<String>,
}

impl Token {
    /// Create a new token where all the fields are absent.
    pub fn new() -> Token {
        Default::default()
    }

    /// Get the word form or punctuation symbol.
    pub fn form(&self) -> Option<&str> {
        self.form.as_ref().map(String::as_ref)
    }

    /// Get the lemma or stem of the word form.
    pub fn lemma(&self) -> Option<&str> {
        self.lemma.as_ref().map(String::as_ref)
    }

    /// Get the coarse-grained part-of-speech tag.
    pub fn cpos(&self) -> Option<&str> {
        self.cpos.as_ref().map(String::as_ref)
    }

    /// Get the fine-grained part-of-speech tag.
    pub fn pos(&self) -> Option<&str> {
        self.pos.as_ref().map(String::as_ref)
    }

    /// Get the syntactic and/or morphological features of the token.
    pub fn features(&self) -> Option<&Features> {
        self.features.as_ref()
    }

    /// Get the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(&self) -> Option<usize> {
        self.head
    }

    /// Get the dependency relation to the head of this token.
    pub fn head_rel(&self) -> Option<&str> {
        self.head_rel.as_ref().map(String::as_ref)
    }

    /// Get the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(&self) -> Option<usize> {
        self.p_head
    }

    /// Get the dependency relation to the projective head of this token.
    pub fn p_head_rel(&self) -> Option<&str> {
        self.p_head_rel.as_ref().map(String::as_ref)
    }

    /// Set the word form or punctuation symbol.
    pub fn set_form<S>(&mut self, form: Option<S>)
        where S: Into<String>
    {
        self.form = form.map(|i| i.into())
    }

    /// Set the lemma or stem of the word form.
    pub fn set_lemma<S>(&mut self, lemma: Option<S>)
        where S: Into<String>
    {
        self.lemma = lemma.map(|i| i.into())
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn set_cpos<S>(&mut self, cpos: Option<S>)
        where S: Into<String>
    {
        self.cpos = cpos.map(|i| i.into())
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn set_pos<S>(&mut self, pos: Option<S>)
        where S: Into<String>
    {
        self.pos = pos.map(|i| i.into())
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn set_features(&mut self, features: Option<Features>) {
        self.features = features
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn set_head(&mut self, head: Option<usize>) {
        self.head = head
    }

    /// Set the dependency relation to the head of this token.
    pub fn set_head_rel<S>(&mut self, head_rel: Option<S>)
        where S: Into<String>
    {
        self.head_rel = head_rel.map(|i| i.into())
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn set_p_head(&mut self, p_head: Option<usize>) {
        self.p_head = p_head
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn set_p_head_rel<S>(&mut self, p_head_rel: Option<S>)
        where S: Into<String>
    {
        self.p_head_rel = p_head_rel.map(|i| i.into())
    }
}

impl Default for Token {
    fn default() -> Self {
        Token {
            form: None,
            lemma: None,
            cpos: None,
            pos: None,
            features: None,
            head: None,
            head_rel: None,
            p_head: None,
            p_head_rel: None,
        }
    }
}

pub const EMPTY_TOKEN: &'static str = "_";

impl fmt::Display for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let head_str = self.head.as_ref().map(|n| n.to_string());
        let p_head_str = self.p_head.as_ref().map(|n| n.to_string());

        write!(f,
               "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
               self.form.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.lemma.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.cpos.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.pos.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.features.as_ref().map(|s| s.as_str()).unwrap_or(EMPTY_TOKEN),
               head_str.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.head_rel.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.p_head.clone().map(|n| n.to_string()).unwrap_or(EMPTY_TOKEN.to_string()),
               p_head_str.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN))
    }
}
<commit_msg>Sentence:as_tokens: return Token slice.<commit_after>use std::fmt;
use std::ops;
use std::slice;
use std::vec;

use features::Features;

/// A sentence with the CoNLL-X annotation layers.
///
/// This data type is a small wrapper around `Vec<Token>` that provides some
/// extra convenience. For example, the implementation of the `Display` trait
/// outputs the sentence in CoNLL-X format.
#[derive(Clone, Debug,PartialEq)]
pub struct Sentence {
    tokens: Vec<Token>,
}

impl Sentence {
    /// Create a new `Sentence` from a vector of tokens.
    pub fn new(tokens: Vec<Token>) -> Sentence {
        Sentence { tokens: tokens }
    }

    /// Get the underlying vector of tokens.
    pub fn as_tokens(&self) -> &[Token] {
        &self.tokens
    }

    /// Get an iterator over the sentence tokens.
    pub fn iter(&self) -> slice::Iter<Token> {
        self.tokens.iter()
    }

    /// Get a mutable iterator over the sentence tokens.
    pub fn iter_mut(&mut self) -> slice::IterMut<Token> {
        self.tokens.iter_mut()
    }
}

impl fmt::Display for Sentence {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let last_id = self.tokens.len() - 1;

        for (id, token) in self.iter().enumerate() {
            if id == last_id {
                write!(f, "{}\t{}", id + 1, token)?
            } else {
                write!(f, "{}\t{}\n", id + 1, token)?
            }
        }

        Ok(())
    }
}

impl ops::Index<usize> for Sentence {
    type Output = Token;
    fn index(&self, index: usize) -> &Token {
        &self.tokens[index]
    }
}

impl ops::IndexMut<usize> for Sentence {
    fn index_mut(&mut self, index: usize) -> &mut Token {
        &mut self.tokens[index]
    }
}

impl IntoIterator for Sentence {
    type Item = Token;
    type IntoIter = vec::IntoIter<Token>;

    fn into_iter(self) -> vec::IntoIter<Token> {
        self.tokens.into_iter()
    }
}

impl<'a> IntoIterator for &'a Sentence {
    type Item = &'a Token;
    type IntoIter = slice::Iter<'a, Token>;

    fn into_iter(self) -> slice::Iter<'a, Token> {
        self.iter()
    }
}

impl<'a> IntoIterator for &'a mut Sentence {
    type Item = &'a mut Token;
    type IntoIter = slice::IterMut<'a, Token>;

    fn into_iter(mut self) -> slice::IterMut<'a, Token> {
        self.iter_mut()
    }
}

/// A builder for `Token`s.
///
/// The `Token` type stores a CoNLL-X token. However, since this format
/// permits a large number of fields, construction of a token can get
/// tedious. This builder provides a fluent interface for creating `Token`s.
pub struct TokenBuilder {
    token: Token,
}

impl TokenBuilder {
    /// Create a `Token` builder with all fields set to absent.
    pub fn new() -> TokenBuilder {
        Default::default()
    }

    /// Set the word form or punctuation symbol.
    pub fn form<S>(mut self, form: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_form(Some(form));
        self
    }

    /// Set the lemma or stem of the word form.
    pub fn lemma<S>(mut self, lemma: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_lemma(Some(lemma));
        self
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn cpos<S>(mut self, cpos: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_cpos(Some(cpos));
        self
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn pos<S>(mut self, pos: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_pos(Some(pos));
        self
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn features(mut self, features: Features) -> TokenBuilder {
        self.token.set_features(Some(features));
        self
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(mut self, head: usize) -> TokenBuilder {
        self.token.set_head(Some(head));
        self
    }

    /// Set the dependency relation to the head of this token.
    pub fn head_rel<S>(mut self, head_rel: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_head_rel(Some(head_rel));
        self
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(mut self, p_head: usize) -> TokenBuilder {
        self.token.set_p_head(Some(p_head));
        self
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn p_head_rel<S>(mut self, p_head_rel: S) -> TokenBuilder
        where S: Into<String>
    {
        self.token.set_p_head_rel(Some(p_head_rel));
        self
    }

    pub fn token(self) -> Token {
        self.token
    }
}

impl Default for TokenBuilder {
    fn default() -> Self {
        TokenBuilder { token: Default::default() }
    }
}

/// A token with the CoNLL-X annotation layers.
///
/// The fields of CoNLLX tokens are described at:
///
/// http://ilk.uvt.nl/conll/
///
/// This type provides exactly the same fields, except for the ID field
/// (since it can be derived from the sentence position of the token).
/// If a particular field is absent (*_* in the CoNLL-X format), its
/// value is `None`.
#[derive(Clone,Debug,PartialEq)]
pub struct Token {
    form: Option<String>,
    lemma: Option<String>,
    cpos: Option<String>,
    pos: Option<String>,
    features: Option<Features>,
    head: Option<usize>,
    head_rel: Option<String>,
    p_head: Option<usize>,
    p_head_rel: Option<String>,
}

impl Token {
    /// Create a new token where all the fields are absent.
    pub fn new() -> Token {
        Default::default()
    }

    /// Get the word form or punctuation symbol.
    pub fn form(&self) -> Option<&str> {
        self.form.as_ref().map(String::as_ref)
    }

    /// Get the lemma or stem of the word form.
    pub fn lemma(&self) -> Option<&str> {
        self.lemma.as_ref().map(String::as_ref)
    }

    /// Get the coarse-grained part-of-speech tag.
    pub fn cpos(&self) -> Option<&str> {
        self.cpos.as_ref().map(String::as_ref)
    }

    /// Get the fine-grained part-of-speech tag.
    pub fn pos(&self) -> Option<&str> {
        self.pos.as_ref().map(String::as_ref)
    }

    /// Get the syntactic and/or morphological features of the token.
    pub fn features(&self) -> Option<&Features> {
        self.features.as_ref()
    }

    /// Get the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn head(&self) -> Option<usize> {
        self.head
    }

    /// Get the dependency relation to the head of this token.
    pub fn head_rel(&self) -> Option<&str> {
        self.head_rel.as_ref().map(String::as_ref)
    }

    /// Get the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn p_head(&self) -> Option<usize> {
        self.p_head
    }

    /// Get the dependency relation to the projective head of this token.
    pub fn p_head_rel(&self) -> Option<&str> {
        self.p_head_rel.as_ref().map(String::as_ref)
    }

    /// Set the word form or punctuation symbol.
    pub fn set_form<S>(&mut self, form: Option<S>)
        where S: Into<String>
    {
        self.form = form.map(|i| i.into())
    }

    /// Set the lemma or stem of the word form.
    pub fn set_lemma<S>(&mut self, lemma: Option<S>)
        where S: Into<String>
    {
        self.lemma = lemma.map(|i| i.into())
    }

    /// Set the coarse-grained part-of-speech tag.
    pub fn set_cpos<S>(&mut self, cpos: Option<S>)
        where S: Into<String>
    {
        self.cpos = cpos.map(|i| i.into())
    }

    /// Set the fine-grained part-of-speech tag.
    pub fn set_pos<S>(&mut self, pos: Option<S>)
        where S: Into<String>
    {
        self.pos = pos.map(|i| i.into())
    }

    /// Set the syntactic and/or morphological features of the token.
    pub fn set_features(&mut self, features: Option<Features>) {
        self.features = features
    }

    /// Set the head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree.
    pub fn set_head(&mut self, head: Option<usize>) {
        self.head = head
    }

    /// Set the dependency relation to the head of this token.
    pub fn set_head_rel<S>(&mut self, head_rel: Option<S>)
        where S: Into<String>
    {
        self.head_rel = head_rel.map(|i| i.into())
    }

    /// Set the projective head of the token. This is the sentence position
    /// of the head **plus one**. If the head is 0, the token the root
    /// of the dependency tree. The dependency structure resulting from the
    /// projective heads must be projective.
    pub fn set_p_head(&mut self, p_head: Option<usize>) {
        self.p_head = p_head
    }

    /// Set the dependency relation to the projective head of this token.
    pub fn set_p_head_rel<S>(&mut self, p_head_rel: Option<S>)
        where S: Into<String>
    {
        self.p_head_rel = p_head_rel.map(|i| i.into())
    }
}

impl Default for Token {
    fn default() -> Self {
        Token {
            form: None,
            lemma: None,
            cpos: None,
            pos: None,
            features: None,
            head: None,
            head_rel: None,
            p_head: None,
            p_head_rel: None,
        }
    }
}

pub const EMPTY_TOKEN: &'static str = "_";

impl fmt::Display for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let head_str = self.head.as_ref().map(|n| n.to_string());
        let p_head_str = self.p_head.as_ref().map(|n| n.to_string());

        write!(f,
               "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
               self.form.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.lemma.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.cpos.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.pos.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.features.as_ref().map(|s| s.as_str()).unwrap_or(EMPTY_TOKEN),
               head_str.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.head_rel.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN),
               self.p_head.clone().map(|n| n.to_string()).unwrap_or(EMPTY_TOKEN.to_string()),
               p_head_str.as_ref().map(|s| s.as_ref()).unwrap_or(EMPTY_TOKEN))
    }
}
<|endoftext|>


<commit_before>// Simple types that rely mainly on themselves
// Useful in many places
use std::cmp::*;

use self::WashArgs::*;

#[derive(Clone)]
pub enum WashArgs {
    Flat(String),
    Long(Vec<WashArgs>),
    Empty
}

#[derive(Clone)]
pub enum InputValue {
    Long(Vec<InputValue>),
    Function(String, Vec<InputValue>),
    Short(String),
    Literal(String),
    Split(String),
    // There is but one blemish on this otherwise
    // beautiful, perfect data type:
    // Empty lists are Long(Short(""))
    // There is not really any way around this
    // which wouldn't have a special case in the
    // data type, and the only way to get a list
    // with an empty short is to type an empty list
    // so this solution isn't terrible
}

impl InputValue {
    pub fn is_empty(&self) -> bool {
        use self::InputValue::*;
        match self {
            &Long(ref v) => v.is_empty(),
            &Function(ref n, ref v) => n.is_empty() && v.is_empty(),
            &Literal(ref v) | &Split(ref v) | &Short(ref v) => v.is_empty(),
        }
    }

    pub fn clear(&mut self) {
        *self = InputValue::Short(String::new());
    }

    #[cfg(test)]
    pub fn print(&self) {
        use self::InputValue::*;
        match self {
            &Short(ref v) => {
                print!("Short({})\n", v);
            },
            &Literal(ref v) => {
                print!("Literal({})\n", v);
            },
            &Split(ref v) => {
                print!("Split({})\n", v);
            },
            &Long(ref v) => {
                print!("Long(");
                for item in v.clone().iter() {
                    item.print();
                }
                print!(")\n");
            },
            &Function(ref n, ref v) => {
                print!("Function({}, (", n);
                for item in v.clone().iter() {
                    item.print();
                }
                print!("))\n");
            }
        }
    }
}

impl PartialEq for InputValue {
    fn eq(&self, other:&InputValue) -> bool {
        use self::InputValue::*;
        match self {
            &Long(ref v) => match other {
                &Long(ref ov) => return v == ov,
                _ => return false
            },
            &Function(ref n, ref v) => match other {
                &Function(ref on, ref ov) => return n == on && v == ov,
                _ => return false
            },
            &Short(ref s) => match other {
                &Short(ref os) => return s == os,
                _ => return false
            },
            &Literal(ref s) => match other {
                &Literal(ref os) => return s == os,
                _ => return false
            },
            &Split(ref s) => match other {
                &Split(ref os) => return s == os,
                _ => return false
            }
        }
    }
}

impl PartialEq for WashArgs {
    fn eq(&self, other:&WashArgs) -> bool {
        match self {
            &Long(ref v) => match other {
                &Long(ref ov) => return v == ov,
                _ => return false
            },
            &Flat(ref s) => match other {
                &Flat(ref os) => return s == os,
                _ => return false
            },
            &Empty => match other {
                &Empty => return true,
                _ => return false
            }
        }
    }
}

impl WashArgs {
    pub fn flatten_vec(&self) -> Vec<String> {
        match self {
            &Flat(ref s) => vec![s.clone()],
            &Long(ref v) => {
                let mut out:Vec<String> = vec![];
                for item in v.iter() {
                    out = vec![out, item.flatten_vec()].concat();
                }
                return out;
            },
            &Empty => vec![]
        }
    }

    pub fn flatten_with(&self, with:&str) -> String {
        match self {
            &Flat(ref s) => s.clone(),
            &Long(ref v) => {
                let mut out = String::new();
                for item in v.iter() {
                    out.push_str(item.flatten_with(with).as_slice());
                    out.push_str(with);
                }
                // remove last NL
                out.pop();
                return out;
            },
            &Empty => {
                return String::new();
            }
        }
    }

    pub fn flatten_with_inner(&self, outer:&str, inner:&str) -> String {
        match self {
            &Flat(ref s) => s.clone(),
            &Long(ref v) => {
                let mut out = String::new();
                for item in v.iter() {
                    out.push_str(item.flatten_with(inner).as_slice());
                    out.push_str(outer);
                }
                // remove last NL
                out.pop();
                return out;
            },
            &Empty => {
                return String::new();
            }
        }
    }

    pub fn flatten(&self) -> String {
        return self.flatten_with("\n");
    }

    pub fn len(&self) -> usize {
        match self {
            &Flat(_) => 1,
            &Long(ref v) => v.len(),
            &Empty => 0
        }
    }

    pub fn is_empty(&self) -> bool {
        match self {
            &Flat(_) | &Long(_) => false,
            &Empty => true
        }
    }

    pub fn is_flat(&self) -> bool {
        match self {
            &Flat(_) => true,
            _ => false
        }
    }

    pub fn get(&self, index:usize) -> WashArgs {
        if index >= self.len() {
            return Empty;
        }
        match self {
            &Flat(ref v) => Flat(v.clone()),
            &Long(ref v) => v[index].clone(),
            &Empty => Empty
        }
    }

    pub fn get_flat(&self, index:usize) -> String {
        match self.get(index) {
            Flat(ref v) => v.clone(),
            Long(_) | Empty => "".to_string()
        }
    }

    pub fn slice(&self, u_from:isize, u_to:isize) -> WashArgs {
        let from = min(max(0, u_from) as usize, self.len()) as usize;
        let to = {
            match u_to {
                v if v < 0 => self.len(),
                _ => min(from, self.len())
            }
        };
        if to <= from {
            return Long(vec![]);
        }
        match self {
            &Flat(_) => Empty,
            &Empty => Empty,
            &Long(ref v) => Long(v[from..to].to_vec())
        }
    }
}
<commit_msg>Remove irrelevant comment<commit_after>// Simple types that rely mainly on themselves
// Useful in many places
use std::cmp::*;

use self::WashArgs::*;

#[derive(Clone)]
pub enum WashArgs {
    Flat(String),
    Long(Vec<WashArgs>),
    Empty
}

#[derive(Clone)]
pub enum InputValue {
    Long(Vec<InputValue>),
    Function(String, Vec<InputValue>),
    Short(String),
    Literal(String),
    Split(String),
}

impl InputValue {
    pub fn is_empty(&self) -> bool {
        use self::InputValue::*;
        match self {
            &Long(ref v) => v.is_empty(),
            &Function(ref n, ref v) => n.is_empty() && v.is_empty(),
            &Literal(ref v) | &Split(ref v) | &Short(ref v) => v.is_empty(),
        }
    }

    pub fn clear(&mut self) {
        *self = InputValue::Short(String::new());
    }

    #[cfg(test)]
    pub fn print(&self) {
        use self::InputValue::*;
        match self {
            &Short(ref v) => {
                print!("Short({})\n", v);
            },
            &Literal(ref v) => {
                print!("Literal({})\n", v);
            },
            &Split(ref v) => {
                print!("Split({})\n", v);
            },
            &Long(ref v) => {
                print!("Long(");
                for item in v.clone().iter() {
                    item.print();
                }
                print!(")\n");
            },
            &Function(ref n, ref v) => {
                print!("Function({}, (", n);
                for item in v.clone().iter() {
                    item.print();
                }
                print!("))\n");
            }
        }
    }
}

impl PartialEq for InputValue {
    fn eq(&self, other:&InputValue) -> bool {
        use self::InputValue::*;
        match self {
            &Long(ref v) => match other {
                &Long(ref ov) => return v == ov,
                _ => return false
            },
            &Function(ref n, ref v) => match other {
                &Function(ref on, ref ov) => return n == on && v == ov,
                _ => return false
            },
            &Short(ref s) => match other {
                &Short(ref os) => return s == os,
                _ => return false
            },
            &Literal(ref s) => match other {
                &Literal(ref os) => return s == os,
                _ => return false
            },
            &Split(ref s) => match other {
                &Split(ref os) => return s == os,
                _ => return false
            }
        }
    }
}

impl PartialEq for WashArgs {
    fn eq(&self, other:&WashArgs) -> bool {
        match self {
            &Long(ref v) => match other {
                &Long(ref ov) => return v == ov,
                _ => return false
            },
            &Flat(ref s) => match other {
                &Flat(ref os) => return s == os,
                _ => return false
            },
            &Empty => match other {
                &Empty => return true,
                _ => return false
            }
        }
    }
}

impl WashArgs {
    pub fn flatten_vec(&self) -> Vec<String> {
        match self {
            &Flat(ref s) => vec![s.clone()],
            &Long(ref v) => {
                let mut out:Vec<String> = vec![];
                for item in v.iter() {
                    out = vec![out, item.flatten_vec()].concat();
                }
                return out;
            },
            &Empty => vec![]
        }
    }

    pub fn flatten_with(&self, with:&str) -> String {
        match self {
            &Flat(ref s) => s.clone(),
            &Long(ref v) => {
                let mut out = String::new();
                for item in v.iter() {
                    out.push_str(item.flatten_with(with).as_slice());
                    out.push_str(with);
                }
                // remove last NL
                out.pop();
                return out;
            },
            &Empty => {
                return String::new();
            }
        }
    }

    pub fn flatten_with_inner(&self, outer:&str, inner:&str) -> String {
        match self {
            &Flat(ref s) => s.clone(),
            &Long(ref v) => {
                let mut out = String::new();
                for item in v.iter() {
                    out.push_str(item.flatten_with(inner).as_slice());
                    out.push_str(outer);
                }
                // remove last NL
                out.pop();
                return out;
            },
            &Empty => {
                return String::new();
            }
        }
    }

    pub fn flatten(&self) -> String {
        return self.flatten_with("\n");
    }

    pub fn len(&self) -> usize {
        match self {
            &Flat(_) => 1,
            &Long(ref v) => v.len(),
            &Empty => 0
        }
    }

    pub fn is_empty(&self) -> bool {
        match self {
            &Flat(_) | &Long(_) => false,
            &Empty => true
        }
    }

    pub fn is_flat(&self) -> bool {
        match self {
            &Flat(_) => true,
            _ => false
        }
    }

    pub fn get(&self, index:usize) -> WashArgs {
        if index >= self.len() {
            return Empty;
        }
        match self {
            &Flat(ref v) => Flat(v.clone()),
            &Long(ref v) => v[index].clone(),
            &Empty => Empty
        }
    }

    pub fn get_flat(&self, index:usize) -> String {
        match self.get(index) {
            Flat(ref v) => v.clone(),
            Long(_) | Empty => "".to_string()
        }
    }

    pub fn slice(&self, u_from:isize, u_to:isize) -> WashArgs {
        let from = min(max(0, u_from) as usize, self.len()) as usize;
        let to = {
            match u_to {
                v if v < 0 => self.len(),
                _ => min(from, self.len())
            }
        };
        if to <= from {
            return Long(vec![]);
        }
        match self {
            &Flat(_) => Empty,
            &Empty => Empty,
            &Long(ref v) => Long(v[from..to].to_vec())
        }
    }
}
<|endoftext|>


<commit_before>//! Utility functions for use within wlroots-rs

use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::process::exit;
use std::time::Duration;

use wlroots_sys::{__va_list_tag, log_importance_t, wlr_log_init};
pub use wlroots_sys::log_importance_t::*;

static mut RUST_LOGGING_FN: LogCallback = dummy_callback;

/// The signature for the callback function you can hook into the logging
/// functionality of wlroots.
pub type LogCallback = fn(LogVerbosity, String);

/// How verbose you want the logging. Lower levels prints more.
pub type LogVerbosity = log_importance_t;

/// Initialize wlroots logging at a certain level of verbosity with
/// an optional callback that will be called for every log.
///
/// To log using this system, use the `wlr_log!` macro.
// TODO Wrap the callback function type
pub fn init_logging<T>(verbosity: LogVerbosity, callback: T)
    where T: Into<Option<LogCallback>>
{
    unsafe {
        match callback.into() {
            None => wlr_log_init(verbosity, None),
            Some(callback) => {
                RUST_LOGGING_FN = callback;
                wlr_log_init(verbosity, Some(log_callback));
            }
        }
    }
}

/// Dummy callback to fill in RUST_LOGGING_FN when it's not in use.
fn dummy_callback(_: LogVerbosity, _: String) {}

/// Real hook into the logging callback, calls the real user-supplied callback
/// with nice Rust inputs.
unsafe extern "C" fn log_callback(importance: log_importance_t,
                                  fmt: *const c_char,
                                  _va_list: *mut __va_list_tag) {
    RUST_LOGGING_FN(importance,
                    c_to_rust_string(fmt).unwrap_or_else(|| "".into()))
}

/// Trait to convert something to mili seconds.
///
/// Used primarily to convert a `std::time::Duration` into
/// something usable by wlroots
pub trait ToMS {
    fn to_ms(self) -> u32;
}

impl ToMS for Duration {
    fn to_ms(self) -> u32 {
        let seconds_delta = self.as_secs() as u32;
        let nano_delta = self.subsec_nanos();
        (seconds_delta * 1000) + nano_delta / 1000000
    }
}

/// Converts a Rust string into C string without error handling.
/// If any error occurs, it is logged and then the program is immediantly
/// aborted.
pub fn safe_as_cstring<S>(string: S) -> CString
    where S: Into<Vec<u8>>
{
    match CString::new(string) {
        Ok(string) => string,
        Err(err) => {
            wlr_log!(L_ERROR,
                     "Error occured while trying to convert a Rust string to a C string {:?}",
                     err);
            exit(1)
        }
    }
}

/// Converts a C string into a Rust string without error handling.
/// The pointer passed to this function _must_ be valid.
pub unsafe fn c_to_rust_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        Some(CStr::from_ptr(c_str).to_string_lossy().into_owned())
    }
}

/// Handle unwinding from a panic, used in conjunction with
/// `::std::panic::catch_unwind`.
///
/// When a panic occurs, we terminate the compositor and let the rest
/// of the code run.
pub(crate) unsafe fn handle_unwind<T>(res: ::std::thread::Result<T>) {
    match res {
        Ok(_) => {}
        Err(err) => {
            if ::compositor::COMPOSITOR_PTR == 0 as *mut _ {
                ::std::process::abort();
            }
            (&mut *::compositor::COMPOSITOR_PTR).save_panic_error(err);
            ::compositor::terminate()
        }
    }
}
<commit_msg>add current_time util function<commit_after>//! Utility functions for use within wlroots-rs

use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::process::exit;
use std::time::Duration;

use libc::{clock_gettime, CLOCK_MONOTONIC, timespec};

use wlroots_sys::{__va_list_tag, log_importance_t, wlr_log_init};
pub use wlroots_sys::log_importance_t::*;

static mut RUST_LOGGING_FN: LogCallback = dummy_callback;

/// The signature for the callback function you can hook into the logging
/// functionality of wlroots.
pub type LogCallback = fn(LogVerbosity, String);

/// How verbose you want the logging. Lower levels prints more.
pub type LogVerbosity = log_importance_t;

/// Initialize wlroots logging at a certain level of verbosity with
/// an optional callback that will be called for every log.
///
/// To log using this system, use the `wlr_log!` macro.
// TODO Wrap the callback function type
pub fn init_logging<T>(verbosity: LogVerbosity, callback: T)
    where T: Into<Option<LogCallback>>
{
    unsafe {
        match callback.into() {
            None => wlr_log_init(verbosity, None),
            Some(callback) => {
                RUST_LOGGING_FN = callback;
                wlr_log_init(verbosity, Some(log_callback));
            }
        }
    }
}

/// Dummy callback to fill in RUST_LOGGING_FN when it's not in use.
fn dummy_callback(_: LogVerbosity, _: String) {}

/// Real hook into the logging callback, calls the real user-supplied callback
/// with nice Rust inputs.
unsafe extern "C" fn log_callback(importance: log_importance_t,
                                  fmt: *const c_char,
                                  _va_list: *mut __va_list_tag) {
    RUST_LOGGING_FN(importance,
                    c_to_rust_string(fmt).unwrap_or_else(|| "".into()))
}

/// Trait to convert something to mili seconds.
///
/// Used primarily to convert a `std::time::Duration` into
/// something usable by wlroots
pub trait ToMS {
    fn to_ms(self) -> u32;
}

impl ToMS for Duration {
    fn to_ms(self) -> u32 {
        let seconds_delta = self.as_secs() as u32;
        let nano_delta = self.subsec_nanos();
        (seconds_delta * 1000) + nano_delta / 1000000
    }
}

/// Converts a Rust string into C string without error handling.
/// If any error occurs, it is logged and then the program is immediantly
/// aborted.
pub fn safe_as_cstring<S>(string: S) -> CString
    where S: Into<Vec<u8>>
{
    match CString::new(string) {
        Ok(string) => string,
        Err(err) => {
            wlr_log!(L_ERROR,
                     "Error occured while trying to convert a Rust string to a C string {:?}",
                     err);
            exit(1)
        }
    }
}

/// Converts a C string into a Rust string without error handling.
/// The pointer passed to this function _must_ be valid.
pub unsafe fn c_to_rust_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        Some(CStr::from_ptr(c_str).to_string_lossy().into_owned())
    }
}

/// Handle unwinding from a panic, used in conjunction with
/// `::std::panic::catch_unwind`.
///
/// When a panic occurs, we terminate the compositor and let the rest
/// of the code run.
pub(crate) unsafe fn handle_unwind<T>(res: ::std::thread::Result<T>) {
    match res {
        Ok(_) => {}
        Err(err) => {
            if ::compositor::COMPOSITOR_PTR == 0 as *mut _ {
                ::std::process::abort();
            }
            (&mut *::compositor::COMPOSITOR_PTR).save_panic_error(err);
            ::compositor::terminate()
        }
    }
}

/// Get the current time as a duration suitable for `surface.send_frame_done()` and synthetic seat
/// events.
pub fn current_time() -> Duration {
    unsafe {
        let mut ts = timespec{tv_sec: 0, tv_nsec: 0};
        clock_gettime(CLOCK_MONOTONIC, &mut ts);
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }
}
<|endoftext|>


<commit_before>use assert_cmd::prelude::*;
use copy_dir::copy_dir;
use predicates::prelude::*;
use predicates::str::{contains, similar};
use std::error::Error;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use tempfile::{tempdir, TempDir};

// helpers

pub struct TempRepo {
    dir: TempDir,
}

impl TempRepo {
    pub fn new() -> io::Result<TempRepo> {
        let dir = tempdir()?;
        copy_dir("tests/repo", dir.path().join("repo"))?;
        Ok(TempRepo { dir })
    }

    pub fn path(&self) -> PathBuf {
        self.dir.path().join("repo")
    }

    pub fn path_string(&self) -> String {
        self.path().to_string_lossy().to_string()
    }
}

fn run_test<T>(test_fn: T) -> Result<(), Box<Error>>
where
    T: FnOnce(&mut Command, &Path, &TempRepo) -> Result<(), Box<Error>>,
{
    let empty_dir = tempdir()?;
    let repo = TempRepo::new()?;
    let mut cmd = Command::cargo_bin("sala")?;
    test_fn(&mut cmd, &empty_dir.path(), &repo)
}

const DIRECTORY: &str = "foo";
const EXISTING_SECRET: &str = "foo/@bar";
const NON_EXISTING_SECRET: &str = "foo/@new";
const INVALID_SECRET_PATH_DEEP: &str = "foo/@bar/@baz";
const NON_EXISTING_SECRET_DEEP: &str = "foo/bar/baz/@new";

// get

#[test]
fn get_no_repo() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        fs::write(dir.join("foo"), "".as_bytes())?;

        cmd.current_dir(&dir)
            .args(&["get", "foo"])
            .assert()
            .failure()
            .stderr(similar("Run `sala init' first\n"));

        Ok(())
    })
}

#[test]
fn get_wrong_passphrase() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", EXISTING_SECRET])
            .with_stdin()
            .buffer("this is wrong\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter the master passphrase:
Error: Unable to unlock the encryption key
",
            ));

        Ok(())
    })
}

#[test]
fn get_not_found() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", NON_EXISTING_SECRET])
            .assert()
            .failure()
            .stderr(similar(format!(
                "\
Error: File does not exist or invalid: {}
",
                NON_EXISTING_SECRET
            )));

        Ok(())
    })
}

#[test]
fn get_directory() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", DIRECTORY])
            .assert()
            .failure()
            .stderr(similar(format!(
                "\
Error: File does not exist or invalid: {}
",
                DIRECTORY
            )));

        Ok(())
    })
}

#[test]
fn get_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

#[test]
fn get_raw() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["-r", "get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar("baz\n"));

        Ok(())
    })
}

#[test]
fn implicit_get() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .arg(EXISTING_SECRET)
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

#[test]
fn get_in_dir_does_not_exist() -> Result<(), Box<Error>> {
    run_test(|cmd, tmpdir, _| {
        let dir = tmpdir.join("foo");
        cmd.args(&["-C", &dir.to_string_lossy(), "get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .failure()
            .stderr(contains("Error: Cannot change to directory: "));

        Ok(())
    })
}

#[test]
fn get_in_dir_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.args(&["-C", &repo.path_string(), "get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

#[test]
fn get_saladir_env() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.env("SALADIR", repo.path_string())
            .args(&["get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

// set

#[test]
fn set_no_repo() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(&dir)
            .args(&["set", "foobar"])
            .assert()
            .failure()
            .stderr(similar("Run `sala init' first").trim());

        Ok(())
    })
}

#[test]
fn set_wrong_passphrase() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET])
            .with_stdin()
            .buffer("this is wrong\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter the master passphrase:
Error: Unable to unlock the encryption key
",
            ));

        Ok(())
    })
}

#[test]
fn set_target_is_directory() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", DIRECTORY])
            .assert()
            .failure()
            .stderr(similar(
                "\
Error: Target is a directory: foo
",
            ));

        Ok(())
    })
}

#[test]
fn set_secrets_dont_match() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\nfoo\nother\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter the master passphrase: Type a new secret for foo/@new: Confirm:
Inputs did not match.
",
            ));

        assert_eq!(repo.path().join(NON_EXISTING_SECRET).exists(), false);
        Ok(())
    })
}

#[test]
fn set_new_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/@new: Confirm: ",
            ));

        let secret_path = repo.path().join(NON_EXISTING_SECRET);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

#[test]
fn set_new_cannot_create_parent_dirs() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", INVALID_SECRET_PATH_DEEP])
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar("Error: Cannot create directory: foo/@bar\n"));

        Ok(())
    })
}

#[test]
fn set_new_creates_parent_dirs() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET_DEEP])
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/bar/baz/@new: Confirm: ",
            ));

        let secret_path = repo.path().join(NON_EXISTING_SECRET_DEEP);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

#[test]
fn set_replace_existing_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\nquux\nquux\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/@bar: Confirm: ",
            ));

        let secret_path = repo.path().join(EXISTING_SECRET);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

#[test]
fn implicit_set() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .arg(NON_EXISTING_SECRET)
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/@new: Confirm: ",
            ));

        let secret_path = repo.path().join(NON_EXISTING_SECRET);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

// init

#[test]
fn init_already_initialized() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .arg("init")
            .output()?
            .assert()
            .failure()
            .stderr(similar("Error: The master key already exists\n"));

        Ok(())
    })
}

#[test]
fn init_passphrases_dont_match() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(dir)
            .arg("init")
            .with_stdin()
            .buffer("foobar\nquux\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter a master passphrase: Confirm:
Inputs did not match.
",
            ));

        assert_eq!(dir.join(".sala/key").exists(), false);
        Ok(())
    })
}

#[test]
fn init_success() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(dir)
            .arg("init")
            .with_stdin()
            .buffer("foobar\nfoobar\n")
            .output()?
            .assert()
            .success()
            .stdout(similar(
                "\
Please pick a master passphrase. It is used to encrypt a very long
random key, which in turn is used to encrypt all the private data in
this directory.

Make sure you remember the master passphrase and that it's strong
enough for your privacy needs.

Generating a master key (512 bits)... done
",
            ))
            .stderr(similar("Enter a master passphrase: Confirm: "));

        assert_eq!(dir.join(".sala/key").metadata()?.len() > 0, true);
        Ok(())
    })
}

// misc

#[test]
fn no_args() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(dir)
            .assert()
            .failure()
            .stderr(similar("Try `sala --help'\n"));

        Ok(())
    })
}
<commit_msg>Avoid test failures if user has a global config file (Rust)<commit_after>use assert_cmd::prelude::*;
use copy_dir::copy_dir;
use predicates::prelude::*;
use predicates::str::{contains, similar};
use std::error::Error;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use tempfile::{tempdir, TempDir};

// helpers

pub struct TempRepo {
    dir: TempDir,
}

impl TempRepo {
    pub fn new() -> io::Result<TempRepo> {
        let dir = tempdir()?;
        copy_dir("tests/repo", dir.path().join("repo"))?;
        Ok(TempRepo { dir })
    }

    pub fn path(&self) -> PathBuf {
        self.dir.path().join("repo")
    }

    pub fn path_string(&self) -> String {
        self.path().to_string_lossy().to_string()
    }
}

fn run_test<T>(test_fn: T) -> Result<(), Box<Error>>
where
    T: FnOnce(&mut Command, &Path, &TempRepo) -> Result<(), Box<Error>>,
{
    let empty_dir = tempdir()?;
    let repo = TempRepo::new()?;
    let mut cmd = Command::cargo_bin("sala")?;
    cmd.env("HOME", empty_dir.path());
    test_fn(&mut cmd, &empty_dir.path(), &repo)
}

const DIRECTORY: &str = "foo";
const EXISTING_SECRET: &str = "foo/@bar";
const NON_EXISTING_SECRET: &str = "foo/@new";
const INVALID_SECRET_PATH_DEEP: &str = "foo/@bar/@baz";
const NON_EXISTING_SECRET_DEEP: &str = "foo/bar/baz/@new";

// get

#[test]
fn get_no_repo() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        fs::write(dir.join("foo"), "".as_bytes())?;

        cmd.current_dir(&dir)
            .args(&["get", "foo"])
            .assert()
            .failure()
            .stderr(similar("Run `sala init' first\n"));

        Ok(())
    })
}

#[test]
fn get_wrong_passphrase() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", EXISTING_SECRET])
            .with_stdin()
            .buffer("this is wrong\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter the master passphrase:
Error: Unable to unlock the encryption key
",
            ));

        Ok(())
    })
}

#[test]
fn get_not_found() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", NON_EXISTING_SECRET])
            .assert()
            .failure()
            .stderr(similar(format!(
                "\
Error: File does not exist or invalid: {}
",
                NON_EXISTING_SECRET
            )));

        Ok(())
    })
}

#[test]
fn get_directory() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", DIRECTORY])
            .assert()
            .failure()
            .stderr(similar(format!(
                "\
Error: File does not exist or invalid: {}
",
                DIRECTORY
            )));

        Ok(())
    })
}

#[test]
fn get_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

#[test]
fn get_raw() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["-r", "get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar("baz\n"));

        Ok(())
    })
}

#[test]
fn implicit_get() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .arg(EXISTING_SECRET)
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

#[test]
fn get_in_dir_does_not_exist() -> Result<(), Box<Error>> {
    run_test(|cmd, tmpdir, _| {
        let dir = tmpdir.join("foo");
        cmd.args(&["-C", &dir.to_string_lossy(), "get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .failure()
            .stderr(contains("Error: Cannot change to directory: "));

        Ok(())
    })
}

#[test]
fn get_in_dir_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.args(&["-C", &repo.path_string(), "get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

#[test]
fn get_saladir_env() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.env("SALADIR", repo.path_string())
            .args(&["get", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\n")
            .output()?
            .assert()
            .success()
            .stderr(similar("Enter the master passphrase: "))
            .stdout(similar(
                "
foo/@bar: baz

",
            ));

        Ok(())
    })
}

// set

#[test]
fn set_no_repo() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(&dir)
            .args(&["set", "foobar"])
            .assert()
            .failure()
            .stderr(similar("Run `sala init' first").trim());

        Ok(())
    })
}

#[test]
fn set_wrong_passphrase() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET])
            .with_stdin()
            .buffer("this is wrong\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter the master passphrase:
Error: Unable to unlock the encryption key
",
            ));

        Ok(())
    })
}

#[test]
fn set_target_is_directory() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", DIRECTORY])
            .assert()
            .failure()
            .stderr(similar(
                "\
Error: Target is a directory: foo
",
            ));

        Ok(())
    })
}

#[test]
fn set_secrets_dont_match() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\nfoo\nother\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter the master passphrase: Type a new secret for foo/@new: Confirm:
Inputs did not match.
",
            ));

        assert_eq!(repo.path().join(NON_EXISTING_SECRET).exists(), false);
        Ok(())
    })
}

#[test]
fn set_new_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/@new: Confirm: ",
            ));

        let secret_path = repo.path().join(NON_EXISTING_SECRET);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

#[test]
fn set_new_cannot_create_parent_dirs() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", INVALID_SECRET_PATH_DEEP])
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar("Error: Cannot create directory: foo/@bar\n"));

        Ok(())
    })
}

#[test]
fn set_new_creates_parent_dirs() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", NON_EXISTING_SECRET_DEEP])
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/bar/baz/@new: Confirm: ",
            ));

        let secret_path = repo.path().join(NON_EXISTING_SECRET_DEEP);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

#[test]
fn set_replace_existing_success() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .args(&["set", EXISTING_SECRET])
            .with_stdin()
            .buffer("qwerty\nquux\nquux\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/@bar: Confirm: ",
            ));

        let secret_path = repo.path().join(EXISTING_SECRET);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

#[test]
fn implicit_set() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .arg(NON_EXISTING_SECRET)
            .with_stdin()
            .buffer("qwerty\nfoo\nfoo\n")
            .output()?
            .assert()
            .success()
            .stderr(similar(
                "Enter the master passphrase: Type a new secret for foo/@new: Confirm: ",
            ));

        let secret_path = repo.path().join(NON_EXISTING_SECRET);
        assert_eq!(secret_path.is_file(), true);
        assert_eq!(secret_path.metadata()?.len() > 0, true);
        Ok(())
    })
}

// init

#[test]
fn init_already_initialized() -> Result<(), Box<Error>> {
    run_test(|cmd, _, repo| {
        cmd.current_dir(repo.path())
            .arg("init")
            .output()?
            .assert()
            .failure()
            .stderr(similar("Error: The master key already exists\n"));

        Ok(())
    })
}

#[test]
fn init_passphrases_dont_match() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(dir)
            .arg("init")
            .with_stdin()
            .buffer("foobar\nquux\n")
            .output()?
            .assert()
            .failure()
            .stderr(similar(
                "\
Enter a master passphrase: Confirm:
Inputs did not match.
",
            ));

        assert_eq!(dir.join(".sala/key").exists(), false);
        Ok(())
    })
}

#[test]
fn init_success() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(dir)
            .arg("init")
            .with_stdin()
            .buffer("foobar\nfoobar\n")
            .output()?
            .assert()
            .success()
            .stdout(similar(
                "\
Please pick a master passphrase. It is used to encrypt a very long
random key, which in turn is used to encrypt all the private data in
this directory.

Make sure you remember the master passphrase and that it's strong
enough for your privacy needs.

Generating a master key (512 bits)... done
",
            ))
            .stderr(similar("Enter a master passphrase: Confirm: "));

        assert_eq!(dir.join(".sala/key").metadata()?.len() > 0, true);
        Ok(())
    })
}

// misc

#[test]
fn no_args() -> Result<(), Box<Error>> {
    run_test(|cmd, dir, _| {
        cmd.current_dir(dir)
            .assert()
            .failure()
            .stderr(similar("Try `sala --help'\n"));

        Ok(())
    })
}
<|endoftext|>