<commit_before>// An item is line of text that read from `find` command or stdin together with
// the internal states, such as selected or not

use ansi::ANSIParser;
use curses::attr_t;
use field::*;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::default::Default;
use std::sync::Arc;

// An item will store everything that one line input will need to be operated and displayed.
//
// What's special about an item?
// The simplest version of an item is a line of string, but things are getting more complex:
// - The conversion of lower/upper case is slow in rust, because it involds unicode.
// - We may need to interpret the ANSI codes in the text.
// - The text can be transformed and limited while searching.

// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
// more than one line.

#[derive(Debug)]
pub struct Item {
    // (num of run, number of index)
    index: (usize, usize),

    // The text that will be ouptut when user press `enter`
    orig_text: String,

    // The text that will shown into the screen. Can be transformed.
    text: String,

    // cache of the lower case version of text. To improve speed
    chars: Vec<char>,

    // the ansi state (color) of the text
    ansi_states: Vec<(usize, attr_t)>,
    matching_ranges: Vec<(usize, usize)>,

    // For the transformed ANSI case, the output will need another transform.
    using_transform_fields: bool,
    ansi_enabled: bool,
}

impl<'a> Item {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
        index: (usize, usize),
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (text, states_text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields))
        } else if using_transform_fields {
            // transformed, not ansi
            (parse_transform_fields(delimiter, &orig_text, trans_fields), Vec::new())
        } else if ansi_enabled {
            // not transformed, ansi
            ansi_parser.parse_ansi(&orig_text)
        } else {
            // normal case
            ("".to_string(), Vec::new())
        };

        let mut ret = Item {
            index: index,
            orig_text: orig_text,
            text: text,
            chars: Vec::new(),
            ansi_states: states_text,
            using_transform_fields: !trans_fields.is_empty(),
            matching_ranges: Vec::new(),
            ansi_enabled: ansi_enabled,
        };

        let chars: Vec<char> = if ret.get_text().as_bytes().is_ascii() {
            ret.get_text().as_bytes().iter().map(|&s| s as char).collect()
        } else {
            ret.get_text().chars().collect()
        };

        let matching_ranges = if !matching_fields.is_empty() {
            parse_matching_fields(delimiter, ret.get_text(), matching_fields)
        } else {
            vec![(0, chars.len())]
        };

        ret.chars = chars;
        ret.matching_ranges = matching_ranges;
        ret
    }

    pub fn get_text(&self) -> &str {
        if !self.using_transform_fields && !self.ansi_enabled {
            &self.orig_text
        } else {
            &self.text
        }
    }

    pub fn get_orig_text(&'a self) -> Cow<'a, str> {
        Cow::Borrowed(&self.orig_text)
    }

    pub fn get_output_text(&'a self) -> Cow<'a, str> {
        if self.using_transform_fields && self.ansi_enabled {
            let mut ansi_parser: ANSIParser = Default::default();
            let (text, _) = ansi_parser.parse_ansi(&self.orig_text);
            Cow::Owned(text)
        } else if !self.using_transform_fields && self.ansi_enabled {
            Cow::Borrowed(&self.text)
        } else {
            Cow::Borrowed(&self.orig_text)
        }
    }

    pub fn get_chars(&self) -> &[char] {
        &self.chars
    }

    pub fn get_ansi_states(&self) -> &Vec<(usize, attr_t)> {
        &self.ansi_states
    }

    pub fn get_index(&self) -> usize {
        self.index.1
    }

    pub fn get_full_index(&self) -> (usize, usize) {
        self.index
    }

    pub fn get_matching_ranges(&self) -> &[(usize, usize)] {
        &self.matching_ranges
    }
}

impl Clone for Item {
    fn clone(&self) -> Item {
        Item {
            index: self.index,
            orig_text: self.orig_text.clone(),
            text: self.text.clone(),
            chars: self.chars.clone(),
            ansi_states: self.ansi_states.clone(),
            using_transform_fields: self.using_transform_fields,
            matching_ranges: self.matching_ranges.clone(),
            ansi_enabled: self.ansi_enabled,
        }
    }
}

// A bunch of items
pub type ItemGroup = Vec<Arc<Item>>;
pub type MatchedItemGroup = Vec<MatchedItem>;

pub type Rank = [i64; 4]; // score, index, start, end

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    Range(usize, usize),
    Chars(Vec<usize>),
}

#[derive(Clone, Debug)]
pub struct MatchedItem {
    pub item: Arc<Item>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that metched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<Item>) -> Self {
        MatchedItem {
            item: item,
            rank: [0, 0, 0, 0],
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }
}

impl Ord for MatchedItem {
    fn cmp(&self, other: &MatchedItem) -> Ordering {
        self.rank.cmp(&other.rank)
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for MatchedItem {
    fn partial_cmp(&self, other: &MatchedItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MatchedItem {
    fn eq(&self, other: &MatchedItem) -> bool {
        self.rank == other.rank
    }
}

impl Eq for MatchedItem {}
<commit_msg>remove duplicate variable name.<commit_after>// An item is line of text that read from `find` command or stdin together with
// the internal states, such as selected or not

use ansi::ANSIParser;
use curses::attr_t;
use field::*;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::default::Default;
use std::sync::Arc;

// An item will store everything that one line input will need to be operated and displayed.
//
// What's special about an item?
// The simplest version of an item is a line of string, but things are getting more complex:
// - The conversion of lower/upper case is slow in rust, because it involds unicode.
// - We may need to interpret the ANSI codes in the text.
// - The text can be transformed and limited while searching.

// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
// more than one line.

#[derive(Debug)]
pub struct Item {
    // (num of run, number of index)
    index: (usize, usize),

    // The text that will be ouptut when user press `enter`
    orig_text: String,

    // The text that will shown into the screen. Can be transformed.
    text: String,

    // cache of the lower case version of text. To improve speed
    chars: Vec<char>,

    // the ansi state (color) of the text
    ansi_states: Vec<(usize, attr_t)>,
    matching_ranges: Vec<(usize, usize)>,

    // For the transformed ANSI case, the output will need another transform.
    using_transform_fields: bool,
    ansi_enabled: bool,
}

impl<'a> Item {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
        index: (usize, usize),
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (text, states_text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields))
        } else if using_transform_fields {
            // transformed, not ansi
            (parse_transform_fields(delimiter, &orig_text, trans_fields), Vec::new())
        } else if ansi_enabled {
            // not transformed, ansi
            ansi_parser.parse_ansi(&orig_text)
        } else {
            // normal case
            ("".to_string(), Vec::new())
        };

        let mut ret = Item {
            index: index,
            orig_text,
            text: text,
            chars: Vec::new(),
            ansi_states: states_text,
            using_transform_fields: !trans_fields.is_empty(),
            matching_ranges: Vec::new(),
            ansi_enabled: ansi_enabled,
        };

        let chars: Vec<char> = if ret.get_text().as_bytes().is_ascii() {
            ret.get_text().as_bytes().iter().map(|&s| s as char).collect()
        } else {
            ret.get_text().chars().collect()
        };

        let matching_ranges = if !matching_fields.is_empty() {
            parse_matching_fields(delimiter, ret.get_text(), matching_fields)
        } else {
            vec![(0, chars.len())]
        };

        ret.chars = chars;
        ret.matching_ranges = matching_ranges;
        ret
    }

    pub fn get_text(&self) -> &str {
        if !self.using_transform_fields && !self.ansi_enabled {
            &self.orig_text
        } else {
            &self.text
        }
    }

    pub fn get_orig_text(&'a self) -> Cow<'a, str> {
        Cow::Borrowed(&self.orig_text)
    }

    pub fn get_output_text(&'a self) -> Cow<'a, str> {
        if self.using_transform_fields && self.ansi_enabled {
            let mut ansi_parser: ANSIParser = Default::default();
            let (text, _) = ansi_parser.parse_ansi(&self.orig_text);
            Cow::Owned(text)
        } else if !self.using_transform_fields && self.ansi_enabled {
            Cow::Borrowed(&self.text)
        } else {
            Cow::Borrowed(&self.orig_text)
        }
    }

    pub fn get_chars(&self) -> &[char] {
        &self.chars
    }

    pub fn get_ansi_states(&self) -> &Vec<(usize, attr_t)> {
        &self.ansi_states
    }

    pub fn get_index(&self) -> usize {
        self.index.1
    }

    pub fn get_full_index(&self) -> (usize, usize) {
        self.index
    }

    pub fn get_matching_ranges(&self) -> &[(usize, usize)] {
        &self.matching_ranges
    }
}

impl Clone for Item {
    fn clone(&self) -> Item {
        Item {
            index: self.index,
            orig_text: self.orig_text.clone(),
            text: self.text.clone(),
            chars: self.chars.clone(),
            ansi_states: self.ansi_states.clone(),
            using_transform_fields: self.using_transform_fields,
            matching_ranges: self.matching_ranges.clone(),
            ansi_enabled: self.ansi_enabled,
        }
    }
}

// A bunch of items
pub type ItemGroup = Vec<Arc<Item>>;
pub type MatchedItemGroup = Vec<MatchedItem>;

pub type Rank = [i64; 4]; // score, index, start, end

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    Range(usize, usize),
    Chars(Vec<usize>),
}

#[derive(Clone, Debug)]
pub struct MatchedItem {
    pub item: Arc<Item>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that metched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<Item>) -> Self {
        MatchedItem {
            item: item,
            rank: [0, 0, 0, 0],
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }
}

impl Ord for MatchedItem {
    fn cmp(&self, other: &MatchedItem) -> Ordering {
        self.rank.cmp(&other.rank)
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for MatchedItem {
    fn partial_cmp(&self, other: &MatchedItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MatchedItem {
    fn eq(&self, other: &MatchedItem) -> bool {
        self.rank == other.rank
    }
}

impl Eq for MatchedItem {}
<|endoftext|>


<commit_before>use NibbleVec;
use endian_type::{LittleEndian, BigEndian};

/// Trait for types which can be used to key a Radix Trie.
///
/// Types that implement this trait should be convertible to a vector of half-bytes (nibbles)
/// such that no two instances of the type convert to the same vector.
/// To protect against faulty behaviour, the trie will **panic** if it finds two distinct keys
/// of type `K` which encode to the same `NibbleVec`, so be careful!
///
/// If you would like to implement this trait for your own type, you need to implement
/// *either* `encode_bytes` or `encode`. You only need to implement one of the two.
/// If you don't implement one, your code will **panic** as soon you use the trie.
/// There is no performance penalty for implementing `encode_bytes` instead of `encode`,
/// so it is preferred except in the case where you require half-byte precision.
///
/// Many standard types implement this trait already. Integer types are encoded *big-endian*
/// by default but can be encoded little-endian using the `LittleEndian<T>` wrapper type.
pub trait TrieKey: PartialEq + Eq {
    /// Encode a value as a vector of bytes.
    fn encode_bytes(&self) -> Vec<u8> {
        panic!("implement this method or TrieKey::encode");
    }

    /// Encode a value as a NibbleVec.
    fn encode(&self) -> NibbleVec {
        NibbleVec::from_byte_vec(self.encode_bytes())
    }
}

/// Key comparison result.
#[derive(Debug)]
pub enum KeyMatch {
    /// The keys match up to the given index.
    Partial(usize),
    /// The first key is a prefix of the second.
    FirstPrefix,
    /// The second key is a prefix of the first.
    SecondPrefix,
    /// The keys match exactly.
    Full,
}

/// Compare two Trie keys.
///
/// Compares `first[start_idx .. ]` to `second`, i.e. only looks at a slice of the first key.
pub fn match_keys(start_idx: usize, first: &NibbleVec, second: &NibbleVec) -> KeyMatch {
    let first_len = first.len() - start_idx;
    let min_length = ::std::cmp::min(first_len, second.len());

    for i in 0..min_length {
        if first.get(start_idx + i) != second.get(i) {
            return KeyMatch::Partial(i);
        }
    }

    match (first_len, second.len()) {
        (x, y) if x < y => KeyMatch::FirstPrefix,
        (x, y) if x == y => KeyMatch::Full,
        _ => KeyMatch::SecondPrefix,
    }
}

/// Check two keys for equality and panic if they differ.
pub fn check_keys<K: ?Sized>(key1: &K, key2: &K)
    where K: TrieKey
{
    if *key1 != *key2 {
        panic!("multiple-keys with the same bit representation.");
    }
}

/// --- TrieKey Implementations for standard types --- ///

// This blanket implementation goes into play when specialization is stabilized
// impl<T> TrieKey for T where T: Into<Vec<u8>> + Clone + Eq + PartialEq {
// fn encode_bytes(&self) -> Vec<u8> {
// self.clone().into()
// }
// }

impl TrieKey for Vec<u8> {
    fn encode_bytes(&self) -> Vec<u8> {
        self.clone()
    }
}

impl TrieKey for [u8] {
    fn encode_bytes(&self) -> Vec<u8> {
        self.clone().to_vec()
    }
}

impl TrieKey for String {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl TrieKey for str {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a mut T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl TrieKey for i8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self as u8);
        return v;
    }
}

impl TrieKey for u8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self);
        return v;
    }
}

impl<T> TrieKey for LittleEndian<T>
    where T: Eq + Copy
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for BigEndian<T>
    where T: Eq + Copy
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

macro_rules! int_keys {
    ( $( $t:ty ),* ) => {
        $(
        impl TrieKey for $t {
            fn encode_bytes(&self) -> Vec<u8> {
                let be: BigEndian<$t> = From::from(*self);
                be.encode_bytes()
            }
        }
        )*
    };
}

int_keys!(u16, u32, u64, i16, i32, i64, usize, isize);
<commit_msg>Add Path/PathBuf as Keys<commit_after>use NibbleVec;
use endian_type::{LittleEndian, BigEndian};
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};

/// Trait for types which can be used to key a Radix Trie.
///
/// Types that implement this trait should be convertible to a vector of half-bytes (nibbles)
/// such that no two instances of the type convert to the same vector.
/// To protect against faulty behaviour, the trie will **panic** if it finds two distinct keys
/// of type `K` which encode to the same `NibbleVec`, so be careful!
///
/// If you would like to implement this trait for your own type, you need to implement
/// *either* `encode_bytes` or `encode`. You only need to implement one of the two.
/// If you don't implement one, your code will **panic** as soon you use the trie.
/// There is no performance penalty for implementing `encode_bytes` instead of `encode`,
/// so it is preferred except in the case where you require half-byte precision.
///
/// Many standard types implement this trait already. Integer types are encoded *big-endian*
/// by default but can be encoded little-endian using the `LittleEndian<T>` wrapper type.
pub trait TrieKey: PartialEq + Eq {
    /// Encode a value as a vector of bytes.
    fn encode_bytes(&self) -> Vec<u8> {
        panic!("implement this method or TrieKey::encode");
    }

    /// Encode a value as a NibbleVec.
    fn encode(&self) -> NibbleVec {
        NibbleVec::from_byte_vec(self.encode_bytes())
    }
}

/// Key comparison result.
#[derive(Debug)]
pub enum KeyMatch {
    /// The keys match up to the given index.
    Partial(usize),
    /// The first key is a prefix of the second.
    FirstPrefix,
    /// The second key is a prefix of the first.
    SecondPrefix,
    /// The keys match exactly.
    Full,
}

/// Compare two Trie keys.
///
/// Compares `first[start_idx .. ]` to `second`, i.e. only looks at a slice of the first key.
pub fn match_keys(start_idx: usize, first: &NibbleVec, second: &NibbleVec) -> KeyMatch {
    let first_len = first.len() - start_idx;
    let min_length = ::std::cmp::min(first_len, second.len());

    for i in 0..min_length {
        if first.get(start_idx + i) != second.get(i) {
            return KeyMatch::Partial(i);
        }
    }

    match (first_len, second.len()) {
        (x, y) if x < y => KeyMatch::FirstPrefix,
        (x, y) if x == y => KeyMatch::Full,
        _ => KeyMatch::SecondPrefix,
    }
}

/// Check two keys for equality and panic if they differ.
pub fn check_keys<K: ?Sized>(key1: &K, key2: &K)
    where K: TrieKey
{
    if *key1 != *key2 {
        panic!("multiple-keys with the same bit representation.");
    }
}

/// --- TrieKey Implementations for standard types --- ///

// This blanket implementation goes into play when specialization is stabilized
// impl<T> TrieKey for T where T: Into<Vec<u8>> + Clone + Eq + PartialEq {
// fn encode_bytes(&self) -> Vec<u8> {
// self.clone().into()
// }
// }

impl TrieKey for Vec<u8> {
    fn encode_bytes(&self) -> Vec<u8> {
        self.clone()
    }
}

impl TrieKey for [u8] {
    fn encode_bytes(&self) -> Vec<u8> {
        self.clone().to_vec()
    }
}

impl TrieKey for String {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl TrieKey for str {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl<'a, T: ?Sized + TrieKey> TrieKey for &'a mut T {
    fn encode_bytes(&self) -> Vec<u8> {
        (**self).encode_bytes()
    }
}

impl TrieKey for i8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self as u8);
        return v;
    }
}

impl TrieKey for u8 {
    fn encode_bytes(&self) -> Vec<u8> {
        let mut v: Vec<u8> = Vec::with_capacity(1);
        v.push(*self);
        return v;
    }
}

#[cfg(unix)]
impl TrieKey for PathBuf {
    fn encode_bytes(&self) -> Vec<u8> {
        use std::os::unix::ffi::OsStringExt;
        let str : OsString = self.clone().into();
        str.into_vec()
    }
}

#[cfg(unix)]
impl TrieKey for Path {
    fn encode_bytes(&self) -> Vec<u8> {
        use std::os::unix::ffi::OsStrExt;
        self.as_os_str().as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for LittleEndian<T>
    where T: Eq + Copy
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().encode_bytes()
    }
}

impl<T> TrieKey for BigEndian<T>
    where T: Eq + Copy
{
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

macro_rules! int_keys {
    ( $( $t:ty ),* ) => {
        $(
        impl TrieKey for $t {
            fn encode_bytes(&self) -> Vec<u8> {
                let be: BigEndian<$t> = From::from(*self);
                be.encode_bytes()
            }
        }
        )*
    };
}

int_keys!(u16, u32, u64, i16, i32, i64, usize, isize);
<|endoftext|>


<commit_before>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::mruby::*;

use std::any::Any;

/// A `macro` useful to run mruby specs.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate mrusty;
/// use mrusty::*;
///
/// # fn main() {
/// struct Cont;
///
/// impl MRubyFile for Cont {
///     fn require(mruby: MRubyType) {
///         mruby.def_class::<Cont>("Container");
///     }
/// }
///
/// describe!(Cont, "
///     describe Class do
///       context 'when 1' do
///         subject { 1 }
///
///         it { is_expected.to eql 1 }
///       end
///
///       context 'when 1' do
///         subject { 1 }
///         let(:one) { 1 }
///
///         it 'won\\'t' do
///           expect(1).to eql one
///         end
///       end
///     end
/// ");
/// # }
/// ```
#[macro_export]
macro_rules! describe {
    ( $t:ty, $spec:expr ) => {
        #[test]
        fn spec() {
            let spec = Spec::new::<$t>($spec);

            assert!(spec.run());
        }
    }
}

/// A `struct` useful for mruby spec definition and running.
///
/// Available matchers:
///
/// * `be_a`, `be_an` - type testing
/// * `be_<somehow>` - test boolean-returning `<name>?` methods
/// * `be <`, `be <=`, `be >`, `be >=` - test relation
/// * `be_eq`, `be_eql`, `be_equal` - test equality
/// * `be_falsey` - test falsey things
/// * `be_truthy` - test truthy things
/// * `have_<something>` - test boolean-returning `has_<name>?` methods
/// * `raise_error` - test errors
/// * `respond_to` - test method responding
/// * `be_within(value).of` - test value
///
/// # Examples
///
/// ```
/// # use mrusty::*;
/// struct Cont;
///
/// impl MRubyFile for Cont {
///     fn require(mruby: MRubyType) {
///         mruby.def_class::<Cont>("Container");
///     }
/// }
///
/// let spec = Spec::new::<Cont>("
///     context 'when 1' do
///       subject { 1 }
///
///       it { is_expected.to eql 1 }
///     end
///
///     context 'when 1' do
///       subject { 1 }
///       let(:one) { 1 }
///
///       it 'won\\'t' do
///         expect(1).to eql one
///       end
///     end
/// ");
///
/// assert_eq!(spec.run(), true);
/// ```
pub struct Spec {
    script: String,
    target: String,
    mruby: MRubyType
}

impl Spec {
    /// Creates an mruby spec runner.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::*;
    /// struct Cont;
    ///
    /// impl MRubyFile for Cont {
    ///     fn require(mruby: MRubyType) {
    ///         mruby.def_class::<Cont>("Container");
    ///     }
    /// }
    ///
    /// Spec::new::<Cont>("
    ///     context 'when 1' do
    ///       subject { 1 }
    ///
    ///       it { is_expected.to eql 1 }
    ///     end
    ///
    ///     context 'when 1' do
    ///       subject { 1 }
    ///       let(:one) { 1 }
    ///
    ///       it 'won\\'t' do
    ///         expect(1).to eql one
    ///       end
    ///     end
    /// ");
    /// ```
    pub fn new<T: MRubyFile + Any>(script: &str) -> Spec {
        let mruby = MRuby::new();

        T::require(mruby.clone());

        mruby.filename("matchers/be.rb");
        mruby.run(include_str!("spec/matchers/be.rb")).unwrap();

        mruby.filename("matchers/be_a.rb");
        mruby.run(include_str!("spec/matchers/be_a.rb")).unwrap();

        mruby.filename("matchers/compare.rb");
        mruby.run(include_str!("spec/matchers/compare.rb")).unwrap();

        mruby.filename("matchers/eq.rb");
        mruby.run(include_str!("spec/matchers/eq.rb")).unwrap();

        mruby.filename("matchers/falsey.rb");
        mruby.run(include_str!("spec/matchers/falsey.rb")).unwrap();

        mruby.filename("matchers/have.rb");
        mruby.run(include_str!("spec/matchers/have.rb")).unwrap();

        mruby.filename("matchers/raise.rb");
        mruby.run(include_str!("spec/matchers/raise.rb")).unwrap();

        mruby.filename("matchers/respond.rb");
        mruby.run(include_str!("spec/matchers/respond.rb")).unwrap();

        mruby.filename("matchers/truthy.rb");
        mruby.run(include_str!("spec/matchers/truthy.rb")).unwrap();

        mruby.filename("matchers/within.rb");
        mruby.run(include_str!("spec/matchers/within.rb")).unwrap();

        mruby.filename("context.rb");
        mruby.run(include_str!("spec/context.rb")).unwrap();

        mruby.filename("example.rb");
        mruby.run(include_str!("spec/example.rb")).unwrap();

        mruby.filename("expect.rb");
        mruby.run(include_str!("spec/expect.rb")).unwrap();

        mruby.filename("spec.rb");
        mruby.run(include_str!("spec/spec.rb")).unwrap();

        let name = mruby.class_name::<T>().unwrap();

        Spec {
            script: script.to_string(),
            target: name,
            mruby: mruby
        }
    }

    /// Runs mruby specs.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::*;
    /// struct Cont;
    ///
    /// impl MRubyFile for Cont {
    ///     fn require(mruby: MRubyType) {
    ///         mruby.def_class::<Cont>("Container");
    ///     }
    /// }
    ///
    /// let spec = Spec::new::<Cont>("
    ///     context 'when 1' do
    ///       subject { 1 }
    ///
    ///       it { is_expected.to eql 1 }
    ///     end
    ///
    ///     context 'when 1' do
    ///       subject { 1 }
    ///       let(:one) { 1 }
    ///
    ///       it 'won\\'t' do
    ///         expect(1).to eql one
    ///       end
    ///     end
    /// ");
    ///
    /// assert_eq!(spec.run(), true);
    /// ```
    pub fn run(&self) -> bool {
        let describe = format!("
            Spec.describe {} do
              {}
            end
        ", self.target, self.script);

        self.mruby.run(&describe).unwrap().to_bool().unwrap()
    }
}

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

    struct Empty;

    impl MRubyFile for Empty {
        fn require(mruby: MRubyType) {
            mruby.def_class::<Empty>("Empty");
        }
    }

    describe!(Empty, "
      context Fixnum do
        context 'when 1' do
          subject { 1 }

          it { is_expected.to eq 1 }
          it { is_expected.not_to eq 2 }

          it { is_expected.to be_an Integer }
          it { is_expected.not_to be_a String }

          it { is_expected.to be_within(0).of(1) }
          it { is_expected.not_to be_within(0.0001).of(2) }

          it { is_expected.to be < 2 }
          it { is_expected.to be <= 2 }
          it { is_expected.not_to be > 2 }
          it { is_expected.not_to be >= 2 }

          it 'is different from 2' do
            expect(1 == 2).to be_falsey
            expect(1 == 2).not_to be_truthy
            expect(1 != 2).to be_truthy
            expect(1 != 2).not_to be_falsey
          end

          it 'does not concatenate with String' do
            expect { '' + 1 }.to raise_error TypeError, \"expected String\"
            expect { 1 + '' }.not_to raise_error Exception
          end

          it { is_expected.to respond_to :to_s }
          it { is_expected.not_to respond_to :to_sym }
        end
      end

      context Hash do
        context 'empty' do
          it { is_expected.to be_empty }
        end

        context 'when {a: 1}' do
          subject { {a: 1} }

          it { is_expected.to have_key :a }
          it { is_expected.not_to be_empty }
        end
      end
    ");
}
<commit_msg>Fixed example.<commit_after>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::mruby::*;

use std::any::Any;

/// A `macro` useful to run mruby specs.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate mrusty;
/// use mrusty::*;
///
/// # fn main() {
/// struct Cont;
///
/// impl MRubyFile for Cont {
///     fn require(mruby: MRubyType) {
///         mruby.def_class::<Cont>("Container");
///     }
/// }
///
/// describe!(Cont, "
///   context 'when 1' do
///     subject { 1 }
///
///     it { is_expected.to eql 1 }
///   end
///
///   context 'when 1' do
///     subject { 1 }
///     let(:one) { 1 }
///
///     it 'won\\'t' do
///       expect(1).to eql one
///     end
///   end
/// ");
/// # }
/// ```
#[macro_export]
macro_rules! describe {
    ( $t:ty, $spec:expr ) => {
        #[test]
        fn spec() {
            let spec = Spec::new::<$t>($spec);

            assert!(spec.run());
        }
    }
}

/// A `struct` useful for mruby spec definition and running.
///
/// Available matchers:
///
/// * `be_a`, `be_an` - type testing
/// * `be_<somehow>` - test boolean-returning `<name>?` methods
/// * `be <`, `be <=`, `be >`, `be >=` - test relation
/// * `be_eq`, `be_eql`, `be_equal` - test equality
/// * `be_falsey` - test falsey things
/// * `be_truthy` - test truthy things
/// * `have_<something>` - test boolean-returning `has_<name>?` methods
/// * `raise_error` - test errors
/// * `respond_to` - test method responding
/// * `be_within(value).of` - test value
///
/// # Examples
///
/// ```
/// # use mrusty::*;
/// struct Cont;
///
/// impl MRubyFile for Cont {
///     fn require(mruby: MRubyType) {
///         mruby.def_class::<Cont>("Container");
///     }
/// }
///
/// let spec = Spec::new::<Cont>("
///     context 'when 1' do
///       subject { 1 }
///
///       it { is_expected.to eql 1 }
///     end
///
///     context 'when 1' do
///       subject { 1 }
///       let(:one) { 1 }
///
///       it 'won\\'t' do
///         expect(1).to eql one
///       end
///     end
/// ");
///
/// assert_eq!(spec.run(), true);
/// ```
pub struct Spec {
    script: String,
    target: String,
    mruby: MRubyType
}

impl Spec {
    /// Creates an mruby spec runner.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::*;
    /// struct Cont;
    ///
    /// impl MRubyFile for Cont {
    ///     fn require(mruby: MRubyType) {
    ///         mruby.def_class::<Cont>("Container");
    ///     }
    /// }
    ///
    /// Spec::new::<Cont>("
    ///     context 'when 1' do
    ///       subject { 1 }
    ///
    ///       it { is_expected.to eql 1 }
    ///     end
    ///
    ///     context 'when 1' do
    ///       subject { 1 }
    ///       let(:one) { 1 }
    ///
    ///       it 'won\\'t' do
    ///         expect(1).to eql one
    ///       end
    ///     end
    /// ");
    /// ```
    pub fn new<T: MRubyFile + Any>(script: &str) -> Spec {
        let mruby = MRuby::new();

        T::require(mruby.clone());

        mruby.filename("matchers/be.rb");
        mruby.run(include_str!("spec/matchers/be.rb")).unwrap();

        mruby.filename("matchers/be_a.rb");
        mruby.run(include_str!("spec/matchers/be_a.rb")).unwrap();

        mruby.filename("matchers/compare.rb");
        mruby.run(include_str!("spec/matchers/compare.rb")).unwrap();

        mruby.filename("matchers/eq.rb");
        mruby.run(include_str!("spec/matchers/eq.rb")).unwrap();

        mruby.filename("matchers/falsey.rb");
        mruby.run(include_str!("spec/matchers/falsey.rb")).unwrap();

        mruby.filename("matchers/have.rb");
        mruby.run(include_str!("spec/matchers/have.rb")).unwrap();

        mruby.filename("matchers/raise.rb");
        mruby.run(include_str!("spec/matchers/raise.rb")).unwrap();

        mruby.filename("matchers/respond.rb");
        mruby.run(include_str!("spec/matchers/respond.rb")).unwrap();

        mruby.filename("matchers/truthy.rb");
        mruby.run(include_str!("spec/matchers/truthy.rb")).unwrap();

        mruby.filename("matchers/within.rb");
        mruby.run(include_str!("spec/matchers/within.rb")).unwrap();

        mruby.filename("context.rb");
        mruby.run(include_str!("spec/context.rb")).unwrap();

        mruby.filename("example.rb");
        mruby.run(include_str!("spec/example.rb")).unwrap();

        mruby.filename("expect.rb");
        mruby.run(include_str!("spec/expect.rb")).unwrap();

        mruby.filename("spec.rb");
        mruby.run(include_str!("spec/spec.rb")).unwrap();

        let name = mruby.class_name::<T>().unwrap();

        Spec {
            script: script.to_string(),
            target: name,
            mruby: mruby
        }
    }

    /// Runs mruby specs.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::*;
    /// struct Cont;
    ///
    /// impl MRubyFile for Cont {
    ///     fn require(mruby: MRubyType) {
    ///         mruby.def_class::<Cont>("Container");
    ///     }
    /// }
    ///
    /// let spec = Spec::new::<Cont>("
    ///     context 'when 1' do
    ///       subject { 1 }
    ///
    ///       it { is_expected.to eql 1 }
    ///     end
    ///
    ///     context 'when 1' do
    ///       subject { 1 }
    ///       let(:one) { 1 }
    ///
    ///       it 'won\\'t' do
    ///         expect(1).to eql one
    ///       end
    ///     end
    /// ");
    ///
    /// assert_eq!(spec.run(), true);
    /// ```
    pub fn run(&self) -> bool {
        let describe = format!("
            Spec.describe {} do
              {}
            end
        ", self.target, self.script);

        self.mruby.run(&describe).unwrap().to_bool().unwrap()
    }
}

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

    struct Empty;

    impl MRubyFile for Empty {
        fn require(mruby: MRubyType) {
            mruby.def_class::<Empty>("Empty");
        }
    }

    describe!(Empty, "
      context Fixnum do
        context 'when 1' do
          subject { 1 }

          it { is_expected.to eq 1 }
          it { is_expected.not_to eq 2 }

          it { is_expected.to be_an Integer }
          it { is_expected.not_to be_a String }

          it { is_expected.to be_within(0).of(1) }
          it { is_expected.not_to be_within(0.0001).of(2) }

          it { is_expected.to be < 2 }
          it { is_expected.to be <= 2 }
          it { is_expected.not_to be > 2 }
          it { is_expected.not_to be >= 2 }

          it 'is different from 2' do
            expect(1 == 2).to be_falsey
            expect(1 == 2).not_to be_truthy
            expect(1 != 2).to be_truthy
            expect(1 != 2).not_to be_falsey
          end

          it 'does not concatenate with String' do
            expect { '' + 1 }.to raise_error TypeError, \"expected String\"
            expect { 1 + '' }.not_to raise_error Exception
          end

          it { is_expected.to respond_to :to_s }
          it { is_expected.not_to respond_to :to_sym }
        end
      end

      context Hash do
        context 'empty' do
          it { is_expected.to be_empty }
        end

        context 'when {a: 1}' do
          subject { {a: 1} }

          it { is_expected.to have_key :a }
          it { is_expected.not_to be_empty }
        end
      end
    ");
}
<|endoftext|>


<commit_before>use super::*;

ast_struct! {
    /// A braced block containing Rust statements.
    ///
    /// *This type is available if Syn is built with the `"full"` feature.*
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: Vec<Stmt>,
    }
}

ast_enum! {
    /// A statement, usually ending in a semicolon.
    ///
    /// *This type is available if Syn is built with the `"full"` feature.*
    pub enum Stmt {
        /// A local (let) binding.
        Local(Local),

        /// An item definition.
        Item(Item),

        /// Expr without trailing semicolon.
        Expr(Expr),

        /// Expression with trailing semicolon.
        Semi(Expr, Token![;]),
    }
}

ast_struct! {
    /// A local `let` binding: `let x: u64 = s.parse()?`.
    ///
    /// *This type is available if Syn is built with the `"full"` feature.*
    pub struct Local {
        pub attrs: Vec<Attribute>,
        pub let_token: Token![let],
        pub pat: Pat,
        pub init: Option<(Token![=], Box<Expr>)>,
        pub semi_token: Token![;],
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use crate::parse::{Parse, ParseStream, Result};
    use crate::punctuated::Punctuated;

    impl Block {
        /// Parse the body of a block as zero or more statements, possibly
        /// including one trailing expression.
        ///
        /// *This function is available if Syn is built with the `"parsing"`
        /// feature.*
        ///
        /// # Example
        ///
        /// ```
        /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token};
        /// use syn::parse::{Parse, ParseStream};
        ///
        /// // Parse a function with no generics or parameter list.
        /// //
        /// //     fn playground {
        /// //         let mut x = 1;
        /// //         x += 1;
        /// //         println!("{}", x);
        /// //     }
        /// struct MiniFunction {
        ///     attrs: Vec<Attribute>,
        ///     fn_token: Token![fn],
        ///     name: Ident,
        ///     brace_token: token::Brace,
        ///     stmts: Vec<Stmt>,
        /// }
        ///
        /// impl Parse for MiniFunction {
        ///     fn parse(input: ParseStream) -> Result<Self> {
        ///         let outer_attrs = input.call(Attribute::parse_outer)?;
        ///         let fn_token: Token![fn] = input.parse()?;
        ///         let name: Ident = input.parse()?;
        ///
        ///         let content;
        ///         let brace_token = braced!(content in input);
        ///         let inner_attrs = content.call(Attribute::parse_inner)?;
        ///         let stmts = content.call(Block::parse_within)?;
        ///
        ///         Ok(MiniFunction {
        ///             attrs: {
        ///                 let mut attrs = outer_attrs;
        ///                 attrs.extend(inner_attrs);
        ///                 attrs
        ///             },
        ///             fn_token,
        ///             name,
        ///             brace_token,
        ///             stmts,
        ///         })
        ///     }
        /// }
        /// ```
        pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
            let mut stmts = Vec::new();
            loop {
                while input.peek(Token![;]) {
                    input.parse::<Token![;]>()?;
                }
                if input.is_empty() {
                    break;
                }
                let s = parse_stmt(input, true)?;
                let requires_semicolon = if let Stmt::Expr(s) = &s {
                    expr::requires_terminator(s)
                } else {
                    false
                };
                stmts.push(s);
                if input.is_empty() {
                    break;
                } else if requires_semicolon {
                    return Err(input.error("unexpected token"));
                }
            }
            Ok(stmts)
        }
    }

    impl Parse for Block {
        fn parse(input: ParseStream) -> Result<Self> {
            let content;
            Ok(Block {
                brace_token: braced!(content in input),
                stmts: content.call(Block::parse_within)?,
            })
        }
    }

    impl Parse for Stmt {
        fn parse(input: ParseStream) -> Result<Self> {
            parse_stmt(input, false)
        }
    }

    fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
        // TODO: optimize using advance_to
        let ahead = input.fork();
        ahead.call(Attribute::parse_outer)?;

        if {
            let ahead = ahead.fork();
            // Only parse braces here; paren and bracket will get parsed as
            // expression statements
            ahead.call(Path::parse_mod_style).is_ok()
                && ahead.parse::<Token![!]>().is_ok()
                && (ahead.peek(token::Brace) || ahead.peek(Ident))
        } {
            stmt_mac(input)
        } else if ahead.peek(Token![let]) {
            stmt_local(input).map(Stmt::Local)
        } else if ahead.peek(Token![pub])
            || ahead.peek(Token![crate]) && !ahead.peek2(Token![::])
            || ahead.peek(Token![extern]) && !ahead.peek2(Token![::])
            || ahead.peek(Token![use])
            || ahead.peek(Token![static]) && (ahead.peek2(Token![mut]) || ahead.peek2(Ident))
            || ahead.peek(Token![const])
            || ahead.peek(Token![unsafe]) && !ahead.peek2(token::Brace)
            || ahead.peek(Token![async])
                && (ahead.peek2(Token![unsafe])
                    || ahead.peek2(Token![extern])
                    || ahead.peek2(Token![fn]))
            || ahead.peek(Token![fn])
            || ahead.peek(Token![mod])
            || ahead.peek(Token![type])
            || ahead.peek(item::parsing::existential) && ahead.peek2(Token![type])
            || ahead.peek(Token![struct])
            || ahead.peek(Token![enum])
            || ahead.peek(Token![union]) && ahead.peek2(Ident)
            || ahead.peek(Token![auto]) && ahead.peek2(Token![trait])
            || ahead.peek(Token![trait])
            || ahead.peek(Token![default])
                && (ahead.peek2(Token![unsafe]) || ahead.peek2(Token![impl]))
            || ahead.peek(Token![impl])
            || ahead.peek(Token![macro])
        {
            input.parse().map(Stmt::Item)
        } else {
            stmt_expr(input, allow_nosemi)
        }
    }

    fn stmt_mac(input: ParseStream) -> Result<Stmt> {
        let attrs = input.call(Attribute::parse_outer)?;
        let path = input.call(Path::parse_mod_style)?;
        let bang_token: Token![!] = input.parse()?;
        let ident: Option<Ident> = input.parse()?;
        let (delimiter, tokens) = mac::parse_delimiter(input)?;
        let semi_token: Option<Token![;]> = input.parse()?;

        Ok(Stmt::Item(Item::Macro(ItemMacro {
            attrs,
            ident,
            mac: Macro {
                path,
                bang_token,
                delimiter,
                tokens,
            },
            semi_token,
        })))
    }

    fn stmt_local(input: ParseStream) -> Result<Local> {
        Ok(Local {
            attrs: input.call(Attribute::parse_outer)?,
            let_token: input.parse()?,
            pat: {
                let leading_vert: Option<Token![|]> = input.parse()?;
                let mut pat: Pat = input.parse()?;
                if leading_vert.is_some()
                    || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
                {
                    let mut cases = Punctuated::new();
                    cases.push_value(pat);
                    while input.peek(Token![|])
                        && !input.peek(Token![||])
                        && !input.peek(Token![|=])
                    {
                        let punct = input.parse()?;
                        cases.push_punct(punct);
                        let pat: Pat = input.parse()?;
                        cases.push_value(pat);
                    }
                    pat = Pat::Or(PatOr {
                        attrs: Vec::new(),
                        leading_vert,
                        cases,
                    });
                }
                if input.peek(Token![:]) {
                    let colon_token: Token![:] = input.parse()?;
                    let ty: Type = input.parse()?;
                    pat = Pat::Type(PatType {
                        attrs: Vec::new(),
                        pat: Box::new(pat),
                        colon_token,
                        ty: Box::new(ty),
                    });
                }
                pat
            },
            init: {
                if input.peek(Token![=]) {
                    let eq_token: Token![=] = input.parse()?;
                    let init: Expr = input.parse()?;
                    Some((eq_token, Box::new(init)))
                } else {
                    None
                }
            },
            semi_token: input.parse()?,
        })
    }

    fn stmt_expr(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
        let mut attrs = input.call(Attribute::parse_outer)?;
        let mut e = expr::parsing::expr_early(input)?;

        attrs.extend(e.replace_attrs(Vec::new()));
        e.replace_attrs(attrs);

        if input.peek(Token![;]) {
            return Ok(Stmt::Semi(e, input.parse()?));
        }

        if allow_nosemi || !expr::requires_terminator(&e) {
            Ok(Stmt::Expr(e))
        } else {
            Err(input.error("expected semicolon"))
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;

    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    impl ToTokens for Block {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                tokens.append_all(&self.stmts);
            });
        }
    }

    impl ToTokens for Stmt {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            match self {
                Stmt::Local(local) => local.to_tokens(tokens),
                Stmt::Item(item) => item.to_tokens(tokens),
                Stmt::Expr(expr) => expr.to_tokens(tokens),
                Stmt::Semi(expr, semi) => {
                    expr.to_tokens(tokens);
                    semi.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for Local {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
            self.let_token.to_tokens(tokens);
            self.pat.to_tokens(tokens);
            if let Some((eq_token, init)) = &self.init {
                eq_token.to_tokens(tokens);
                init.to_tokens(tokens);
            }
            self.semi_token.to_tokens(tokens);
        }
    }
}
<commit_msg>Avoid speculative parsing in 'parse_stmt'<commit_after>use super::*;

ast_struct! {
    /// A braced block containing Rust statements.
    ///
    /// *This type is available if Syn is built with the `"full"` feature.*
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: Vec<Stmt>,
    }
}

ast_enum! {
    /// A statement, usually ending in a semicolon.
    ///
    /// *This type is available if Syn is built with the `"full"` feature.*
    pub enum Stmt {
        /// A local (let) binding.
        Local(Local),

        /// An item definition.
        Item(Item),

        /// Expr without trailing semicolon.
        Expr(Expr),

        /// Expression with trailing semicolon.
        Semi(Expr, Token![;]),
    }
}

ast_struct! {
    /// A local `let` binding: `let x: u64 = s.parse()?`.
    ///
    /// *This type is available if Syn is built with the `"full"` feature.*
    pub struct Local {
        pub attrs: Vec<Attribute>,
        pub let_token: Token![let],
        pub pat: Pat,
        pub init: Option<(Token![=], Box<Expr>)>,
        pub semi_token: Token![;],
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use crate::parse::discouraged::Speculative;
    use crate::parse::{Parse, ParseStream, Result};
    use crate::punctuated::Punctuated;

    impl Block {
        /// Parse the body of a block as zero or more statements, possibly
        /// including one trailing expression.
        ///
        /// *This function is available if Syn is built with the `"parsing"`
        /// feature.*
        ///
        /// # Example
        ///
        /// ```
        /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token};
        /// use syn::parse::{Parse, ParseStream};
        ///
        /// // Parse a function with no generics or parameter list.
        /// //
        /// //     fn playground {
        /// //         let mut x = 1;
        /// //         x += 1;
        /// //         println!("{}", x);
        /// //     }
        /// struct MiniFunction {
        ///     attrs: Vec<Attribute>,
        ///     fn_token: Token![fn],
        ///     name: Ident,
        ///     brace_token: token::Brace,
        ///     stmts: Vec<Stmt>,
        /// }
        ///
        /// impl Parse for MiniFunction {
        ///     fn parse(input: ParseStream) -> Result<Self> {
        ///         let outer_attrs = input.call(Attribute::parse_outer)?;
        ///         let fn_token: Token![fn] = input.parse()?;
        ///         let name: Ident = input.parse()?;
        ///
        ///         let content;
        ///         let brace_token = braced!(content in input);
        ///         let inner_attrs = content.call(Attribute::parse_inner)?;
        ///         let stmts = content.call(Block::parse_within)?;
        ///
        ///         Ok(MiniFunction {
        ///             attrs: {
        ///                 let mut attrs = outer_attrs;
        ///                 attrs.extend(inner_attrs);
        ///                 attrs
        ///             },
        ///             fn_token,
        ///             name,
        ///             brace_token,
        ///             stmts,
        ///         })
        ///     }
        /// }
        /// ```
        pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
            let mut stmts = Vec::new();
            loop {
                while input.peek(Token![;]) {
                    input.parse::<Token![;]>()?;
                }
                if input.is_empty() {
                    break;
                }
                let s = parse_stmt(input, true)?;
                let requires_semicolon = if let Stmt::Expr(s) = &s {
                    expr::requires_terminator(s)
                } else {
                    false
                };
                stmts.push(s);
                if input.is_empty() {
                    break;
                } else if requires_semicolon {
                    return Err(input.error("unexpected token"));
                }
            }
            Ok(stmts)
        }
    }

    impl Parse for Block {
        fn parse(input: ParseStream) -> Result<Self> {
            let content;
            Ok(Block {
                brace_token: braced!(content in input),
                stmts: content.call(Block::parse_within)?,
            })
        }
    }

    impl Parse for Stmt {
        fn parse(input: ParseStream) -> Result<Self> {
            parse_stmt(input, false)
        }
    }

    fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
        let mut attrs = input.call(Attribute::parse_outer)?;

        // brace-style macros; paren and bracket macros get parsed as
        // expression statements.
        let ahead = input.fork();
        if let Ok(path) = ahead.call(Path::parse_mod_style) {
            if ahead.peek(Token![!]) && (ahead.peek2(token::Brace) || ahead.peek2(Ident)) {
                input.advance_to(&ahead);
                return stmt_mac(input, attrs, path);
            }
        }

        if input.peek(Token![let]) {
            stmt_local(input, attrs).map(Stmt::Local)
        } else if input.peek(Token![pub])
            || input.peek(Token![crate]) && !input.peek2(Token![::])
            || input.peek(Token![extern]) && !input.peek2(Token![::])
            || input.peek(Token![use])
            || input.peek(Token![static]) && (input.peek2(Token![mut]) || input.peek2(Ident))
            || input.peek(Token![const])
            || input.peek(Token![unsafe]) && !input.peek2(token::Brace)
            || input.peek(Token![async])
                && (input.peek2(Token![unsafe])
                    || input.peek2(Token![extern])
                    || input.peek2(Token![fn]))
            || input.peek(Token![fn])
            || input.peek(Token![mod])
            || input.peek(Token![type])
            || input.peek(item::parsing::existential) && input.peek2(Token![type])
            || input.peek(Token![struct])
            || input.peek(Token![enum])
            || input.peek(Token![union]) && input.peek2(Ident)
            || input.peek(Token![auto]) && input.peek2(Token![trait])
            || input.peek(Token![trait])
            || input.peek(Token![default])
                && (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
            || input.peek(Token![impl])
            || input.peek(Token![macro])
        {
            let mut item: Item = input.parse()?;
            attrs.extend(item.replace_attrs(Vec::new()));
            item.replace_attrs(attrs);
            Ok(Stmt::Item(item))
        } else {
            stmt_expr(input, allow_nosemi, attrs)
        }
    }

    fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> {
        let bang_token: Token![!] = input.parse()?;
        let ident: Option<Ident> = input.parse()?;
        let (delimiter, tokens) = mac::parse_delimiter(input)?;
        let semi_token: Option<Token![;]> = input.parse()?;

        Ok(Stmt::Item(Item::Macro(ItemMacro {
            attrs,
            ident,
            mac: Macro {
                path,
                bang_token,
                delimiter,
                tokens,
            },
            semi_token,
        })))
    }

    fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
        Ok(Local {
            attrs,
            let_token: input.parse()?,
            pat: {
                let leading_vert: Option<Token![|]> = input.parse()?;
                let mut pat: Pat = input.parse()?;
                if leading_vert.is_some()
                    || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
                {
                    let mut cases = Punctuated::new();
                    cases.push_value(pat);
                    while input.peek(Token![|])
                        && !input.peek(Token![||])
                        && !input.peek(Token![|=])
                    {
                        let punct = input.parse()?;
                        cases.push_punct(punct);
                        let pat: Pat = input.parse()?;
                        cases.push_value(pat);
                    }
                    pat = Pat::Or(PatOr {
                        attrs: Vec::new(),
                        leading_vert,
                        cases,
                    });
                }
                if input.peek(Token![:]) {
                    let colon_token: Token![:] = input.parse()?;
                    let ty: Type = input.parse()?;
                    pat = Pat::Type(PatType {
                        attrs: Vec::new(),
                        pat: Box::new(pat),
                        colon_token,
                        ty: Box::new(ty),
                    });
                }
                pat
            },
            init: {
                if input.peek(Token![=]) {
                    let eq_token: Token![=] = input.parse()?;
                    let init: Expr = input.parse()?;
                    Some((eq_token, Box::new(init)))
                } else {
                    None
                }
            },
            semi_token: input.parse()?,
        })
    }

    fn stmt_expr(
        input: ParseStream,
        allow_nosemi: bool,
        mut attrs: Vec<Attribute>,
    ) -> Result<Stmt> {
        let mut e = expr::parsing::expr_early(input)?;

        attrs.extend(e.replace_attrs(Vec::new()));
        e.replace_attrs(attrs);

        if input.peek(Token![;]) {
            return Ok(Stmt::Semi(e, input.parse()?));
        }

        if allow_nosemi || !expr::requires_terminator(&e) {
            Ok(Stmt::Expr(e))
        } else {
            Err(input.error("expected semicolon"))
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;

    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    impl ToTokens for Block {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                tokens.append_all(&self.stmts);
            });
        }
    }

    impl ToTokens for Stmt {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            match self {
                Stmt::Local(local) => local.to_tokens(tokens),
                Stmt::Item(item) => item.to_tokens(tokens),
                Stmt::Expr(expr) => expr.to_tokens(tokens),
                Stmt::Semi(expr, semi) => {
                    expr.to_tokens(tokens);
                    semi.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for Local {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
            self.let_token.to_tokens(tokens);
            self.pat.to_tokens(tokens);
            if let Some((eq_token, init)) = &self.init {
                eq_token.to_tokens(tokens);
                init.to_tokens(tokens);
            }
            self.semi_token.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::result::Result as RResult;

use serde_json::value::Value;
use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Error as SerdeError;
use serde::ser::MapVisitor;
use uuid::Uuid;

use error::TaskError;
use error::TaskErrorKind;
use priority::TaskPriority;
use result::Result;
use status::TaskStatus;
use project::Project;
use tag::Tag;
use date::Date;

#[derive(Debug, Clone)]
pub struct Task {
    status      : TaskStatus,
    uuid        : Uuid,
    entry       : Date,
    description : String,

    annotation  : Option<Vec<String>>,
    depends     : Option<String>,
    due         : Option<Date>,
    end         : Option<Date>,
    imask       : Option<i64>,
    mask        : Option<String>,
    modified    : Option<Date>,
    parent      : Option<Uuid>,
    priority    : Option<TaskPriority>,
    project     : Option<Project>,
    recur       : Option<String>,
    scheduled   : Option<Date>,
    start       : Option<Date>,
    tags        : Option<Vec<Tag>>,
    until       : Option<Date>,
    wait        : Option<Date>,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(
        status      : TaskStatus,
        uuid        : Uuid,
        entry       : Date,
        description : String,

        annotation  : Option<Vec<String>>,
        depends     : Option<String>,
        due         : Option<Date>,
        end         : Option<Date>,
        imask       : Option<i64>,
        mask        : Option<String>,
        modified    : Option<Date>,
        parent      : Option<Uuid>,
        priority    : Option<TaskPriority>,
        project     : Option<Project>,
        recur       : Option<String>,
        scheduled   : Option<Date>,
        start       : Option<Date>,
        tags        : Option<Vec<Tag>>,
        until       : Option<Date>,
        wait        : Option<Date>,
    ) -> Task
    {
        Task {
            status      : status,
            uuid        : uuid,
            entry       : entry,
            description : description,

            annotation  : annotation,
            depends     : depends,
            due         : due,
            end         : end,
            imask       : imask,
            mask        : mask,
            modified    : modified,
            parent      : parent,
            priority    : priority,
            project     : project,
            recur       : recur,
            scheduled   : scheduled,
            start       : start,
            tags        : tags,
            until       : until,
            wait        : wait,
        }
    }

    pub fn status(&self) -> &TaskStatus {
        &self.status
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn entry(&self) -> &Date {
        &self.entry
    }

    pub fn description(&self) -> &String {
        &self.description
    }

    pub fn annotation(&self) -> Option<&Vec<String>> {
        self.annotation.as_ref()
    }

    pub fn depends(&self) -> Option<&String> {
        self.depends.as_ref()
    }

    pub fn due(&self) -> Option<&Date> {
        self.due.as_ref()
    }

    pub fn end(&self) -> Option<&Date> {
        self.end.as_ref()
    }

    pub fn imask(&self) -> Option<&i64> {
        self.imask.as_ref()
    }

    pub fn mask(&self) -> Option<&String> {
        self.mask.as_ref()
    }

    pub fn modified(&self) -> Option<&Date> {
        self.modified.as_ref()
    }

    pub fn parent(&self) -> Option<&Uuid> {
        self.parent.as_ref()
    }

    pub fn priority(&self) -> Option<&TaskPriority> {
        self.priority.as_ref()
    }

    pub fn project(&self) -> Option<&Project> {
        self.project.as_ref()
    }

    pub fn recur(&self) -> Option<&String> {
        self.recur.as_ref()
    }

    pub fn scheduled(&self) -> Option<&Date> {
        self.scheduled.as_ref()
    }

    pub fn start(&self) -> Option<&Date> {
        self.start.as_ref()
    }

    pub fn tags(&self) -> Option<&Vec<Tag>> {
        self.tags.as_ref()
    }

    pub fn until(&self) -> Option<&Date> {
        self.until.as_ref()
    }

    pub fn wait(&self) -> Option<&Date> {
        self.wait.as_ref()
    }

}

impl Serialize for Task {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_struct("Task", TaskVisitor {
            value: self,
            state: 0,
        })
    }

}

struct TaskVisitor<'a> {
    value: &'a Task,
    state: u8,
}

impl<'a> MapVisitor for TaskVisitor<'a> {

    fn visit<S>(&mut self, serializer: &mut S) -> RResult<Option<()>, S::Error>
        where S: Serializer
    {
        match self.state {
            0 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("status", &self.value.status))))
            },
            1 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("uuid", &self.value.uuid))))
            },
            2 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("entry", &self.value.entry))))
            },
            3 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("description", &self.value.description))))
            },
            4 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("annotation", &self.value.annotation))))
            },
            5 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("depends", &self.value.depends))))
            },
            6 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("due", &self.value.due))))
            },
            7 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("end", &self.value.end))))
            },
            8 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("imask", &self.value.imask))))
            },
            9 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("mask", &self.value.mask))))
            },
            10 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("modified", &self.value.modified))))
            },
            11 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("parent", &self.value.parent))))
            },
            12 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("priority", &self.value.priority))))
            },
            13 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("project", &self.value.project))))
            },
            14 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("recur", &self.value.recur))))
            },
            15 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("scheduled", &self.value.scheduled))))
            },
            16 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("start", &self.value.start))))
            },
            17 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("tags", &self.value.tags))))
            },
            18 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("until", &self.value.until))))
            },
            19 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("wait", &self.value.wait))))
            },
            _ => {
                Ok(None)
            }
        }
    }

}
<commit_msg>[PENDING] Impl Deserialize for Task<commit_after>use std::collections::BTreeMap;
use std::result::Result as RResult;

use serde_json::value::Value;
use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Visitor;
use serde::de::Error as SerdeError;
use serde::ser::MapVisitor;
use serde::de::MapVisitor as DeserializeMapVisitor;
use uuid::Uuid;

use error::TaskError;
use error::TaskErrorKind;
use priority::TaskPriority;
use result::Result;
use status::TaskStatus;
use project::Project;
use tag::Tag;
use date::Date;

#[derive(Debug, Clone)]
pub struct Task {
    status      : TaskStatus,
    uuid        : Uuid,
    entry       : Date,
    description : String,

    annotation  : Option<Vec<String>>,
    depends     : Option<String>,
    due         : Option<Date>,
    end         : Option<Date>,
    imask       : Option<i64>,
    mask        : Option<String>,
    modified    : Option<Date>,
    parent      : Option<Uuid>,
    priority    : Option<TaskPriority>,
    project     : Option<Project>,
    recur       : Option<String>,
    scheduled   : Option<Date>,
    start       : Option<Date>,
    tags        : Option<Vec<Tag>>,
    until       : Option<Date>,
    wait        : Option<Date>,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(
        status      : TaskStatus,
        uuid        : Uuid,
        entry       : Date,
        description : String,

        annotation  : Option<Vec<String>>,
        depends     : Option<String>,
        due         : Option<Date>,
        end         : Option<Date>,
        imask       : Option<i64>,
        mask        : Option<String>,
        modified    : Option<Date>,
        parent      : Option<Uuid>,
        priority    : Option<TaskPriority>,
        project     : Option<Project>,
        recur       : Option<String>,
        scheduled   : Option<Date>,
        start       : Option<Date>,
        tags        : Option<Vec<Tag>>,
        until       : Option<Date>,
        wait        : Option<Date>,
    ) -> Task
    {
        Task {
            status      : status,
            uuid        : uuid,
            entry       : entry,
            description : description,

            annotation  : annotation,
            depends     : depends,
            due         : due,
            end         : end,
            imask       : imask,
            mask        : mask,
            modified    : modified,
            parent      : parent,
            priority    : priority,
            project     : project,
            recur       : recur,
            scheduled   : scheduled,
            start       : start,
            tags        : tags,
            until       : until,
            wait        : wait,
        }
    }

    pub fn status(&self) -> &TaskStatus {
        &self.status
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn entry(&self) -> &Date {
        &self.entry
    }

    pub fn description(&self) -> &String {
        &self.description
    }

    pub fn annotation(&self) -> Option<&Vec<String>> {
        self.annotation.as_ref()
    }

    pub fn depends(&self) -> Option<&String> {
        self.depends.as_ref()
    }

    pub fn due(&self) -> Option<&Date> {
        self.due.as_ref()
    }

    pub fn end(&self) -> Option<&Date> {
        self.end.as_ref()
    }

    pub fn imask(&self) -> Option<&i64> {
        self.imask.as_ref()
    }

    pub fn mask(&self) -> Option<&String> {
        self.mask.as_ref()
    }

    pub fn modified(&self) -> Option<&Date> {
        self.modified.as_ref()
    }

    pub fn parent(&self) -> Option<&Uuid> {
        self.parent.as_ref()
    }

    pub fn priority(&self) -> Option<&TaskPriority> {
        self.priority.as_ref()
    }

    pub fn project(&self) -> Option<&Project> {
        self.project.as_ref()
    }

    pub fn recur(&self) -> Option<&String> {
        self.recur.as_ref()
    }

    pub fn scheduled(&self) -> Option<&Date> {
        self.scheduled.as_ref()
    }

    pub fn start(&self) -> Option<&Date> {
        self.start.as_ref()
    }

    pub fn tags(&self) -> Option<&Vec<Tag>> {
        self.tags.as_ref()
    }

    pub fn until(&self) -> Option<&Date> {
        self.until.as_ref()
    }

    pub fn wait(&self) -> Option<&Date> {
        self.wait.as_ref()
    }

}

impl Serialize for Task {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_struct("Task", TaskVisitor {
            value: self,
            state: 0,
        })
    }

}

struct TaskVisitor<'a> {
    value: &'a Task,
    state: u8,
}

impl<'a> MapVisitor for TaskVisitor<'a> {

    fn visit<S>(&mut self, serializer: &mut S) -> RResult<Option<()>, S::Error>
        where S: Serializer
    {
        match self.state {
            0 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("status", &self.value.status))))
            },
            1 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("uuid", &self.value.uuid))))
            },
            2 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("entry", &self.value.entry))))
            },
            3 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("description", &self.value.description))))
            },
            4 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("annotation", &self.value.annotation))))
            },
            5 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("depends", &self.value.depends))))
            },
            6 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("due", &self.value.due))))
            },
            7 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("end", &self.value.end))))
            },
            8 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("imask", &self.value.imask))))
            },
            9 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("mask", &self.value.mask))))
            },
            10 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("modified", &self.value.modified))))
            },
            11 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("parent", &self.value.parent))))
            },
            12 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("priority", &self.value.priority))))
            },
            13 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("project", &self.value.project))))
            },
            14 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("recur", &self.value.recur))))
            },
            15 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("scheduled", &self.value.scheduled))))
            },
            16 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("start", &self.value.start))))
            },
            17 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("tags", &self.value.tags))))
            },
            18 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("until", &self.value.until))))
            },
            19 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("wait", &self.value.wait))))
            },
            _ => {
                Ok(None)
            }
        }
    }

}

impl Deserialize for Task {

    fn deserialize<D>(deserializer: &mut D) -> RResult<Task, D::Error>
        where D: Deserializer
    {
        static FIELDS: &'static [&'static str] = &[
            "status",
            "uuid",
            "entry",
            "description",

            "annotation",
            "depends",
            "due",
            "end",
            "imask",
            "mask",
            "modified",
            "parent",
            "priority",
            "project",
            "recur",
            "scheduled",
            "start",
            "tags",
            "until",
            "wait"
        ];
        deserializer.deserialize_struct("Task", FIELDS, TaskDeserializeVisitor)
    }

}

struct TaskDeserializeVisitor;

impl Visitor for TaskDeserializeVisitor {
    type Value = Task;

    fn visit_map<V>(&mut self, mut visitor: V) -> RResult<Task, V::Error>
        where V: DeserializeMapVisitor
    {
        let mut status      = None;
        let mut uuid        = None;
        let mut entry       = None;
        let mut description = None;

        let mut annotation  = None;
        let mut depends     = None;
        let mut due         = None;
        let mut end         = None;
        let mut imask       = None;
        let mut mask        = None;
        let mut modified    = None;
        let mut parent      = None;
        let mut priority    = None;
        let mut project     = None;
        let mut recur       = None;
        let mut scheduled   = None;
        let mut start       = None;
        let mut tags        = None;
        let mut until       = None;
        let mut wait        = None;

        loop {
            let key : Option<String> = try!(visitor.visit_key());
            if key.is_none() {
                break;
            }
            let key = key.unwrap();

            match &key[..] {
                "status" => {
                    status = Some(try!(visitor.visit_value()));
                },
                "uuid" => {
                    uuid = Some(try!(visitor.visit_value()));
                },
                "entry" => {
                    entry = Some(try!(visitor.visit_value()));
                },
                "description" => {
                    description = Some(try!(visitor.visit_value()));
                },

                "annotation" => {
                    annotation = Some(try!(visitor.visit_value()));
                },
                "depends" => {
                    depends = Some(try!(visitor.visit_value()));
                },
                "due" => {
                    due = Some(try!(visitor.visit_value()));
                },
                "end" => {
                    end = Some(try!(visitor.visit_value()));
                },
                "imask" => {
                    imask = Some(try!(visitor.visit_value()));
                },
                "mask" => {
                    mask = Some(try!(visitor.visit_value()));
                },
                "modified" => {
                    modified = Some(try!(visitor.visit_value()));
                },
                "parent" => {
                    parent = Some(try!(visitor.visit_value()));
                },
                "priority" => {
                    priority = Some(try!(visitor.visit_value()));
                },
                "project" => {
                    project = Some(try!(visitor.visit_value()));
                },
                "recur" => {
                    recur = Some(try!(visitor.visit_value()));
                },
                "scheduled" => {
                    scheduled = Some(try!(visitor.visit_value()));
                },
                "start" => {
                    start = Some(try!(visitor.visit_value()));
                },
                "tags" => {
                    tags = Some(try!(visitor.visit_value()));
                },
                "until" => {
                    until = Some(try!(visitor.visit_value()));
                },
                "wait" => {
                    wait = Some(try!(visitor.visit_value()));
                },

                field => debug!("field '{}' ignored", field),
            }
        }

        let status = match status {
            Some(status) => status,
            None => try!(visitor.missing_field("status")),
        };

        let uuid = match uuid {
            Some(uuid) => uuid,
            None => try!(visitor.missing_field("uuid")),
        };

        let entry = match entry {
            Some(entry) => entry,
            None => try!(visitor.missing_field("entry")),
        };

        let description = match description {
            Some(description) => description,
            None => try!(visitor.missing_field("description")),
        };

        try!(visitor.end());

        let task = Task::new(
            status,
            uuid,
            entry,
            description,

            annotation,
            depends,
            due,
            end,
            imask,
            mask,
            modified,
            parent,
            priority,
            project,
            recur,
            scheduled,
            start,
            tags,
            until,
            wait
        );

        Ok(task)
    }
}

<|endoftext|>


<commit_before>extern crate serialport;

use std::collections::HashMap;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::rc::Rc;
use std::thread;
use std::time::Duration;

use serialport as sp;

use serial_support::messages::SerialResponse;

/// Struct for containing Port information
#[derive(Clone)]
pub struct OpenPort<'a> {
  /// The opened serial port
  port: &'a sp::SerialPort,
  /// Handle that controls writes to port
  write_handle: String,
  /// Send channel used to send responses to
  /// all clients who opened the port
  clients: &'a Vec<Rc<Sender<SerialResponse>>>,
}

/// Manages tracking and reading/writing from serial
/// ports
struct SerialPortManager<'a> {
  /// Maintains list of ports
  open_ports: HashMap<String, OpenPort<'a>>,
}

impl<'a> SerialPortManager<'a> {
  fn open_port(&self, port: String) {
    let spSettings = sp::SerialPortSettings {
      baud_rate: sp::BaudRate::Baud115200,
      data_bits: sp::DataBits::Eight,
      flow_control: sp::FlowControl::None,
      parity: sp::Parity::None,
      stop_bits: sp::StopBits::One,
      timeout: Duration::from_millis(1),
    };

  }
  fn add_sender(&self, port: String, sender: Sender<SerialResponse>) {}
  fn remove_sender(&self, sender: Sender<SerialResponse>) {}
  fn remove_write_lock(&self, handle: String, port: Option<String>) {}
  fn add_write_lock(&self, handle: String, port: String) {}
}
<commit_msg>Working on run loop for manager<commit_after>extern crate serialport;

use std::collections::HashMap;
use std::num::Wrapping;
use std::rc::Weak;
use std::sync::mpsc::{Sender, Receiver, TryRecvError};
use std::sync::mpsc;
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;

use serialport as sp;

use serial_support::common::*;
use serial_support::messages::*;

/// Convenience type for a listener
/// that accepts weak refs of Senders of Serial Reponses
/// This is how the manager will communicate
/// results back to the websockets
type SubscReceiver = Receiver<Weak<Sender<SerialResponse>>>;

/// Struct for containing Port information
pub struct OpenPort<'a> {
  /// The opened serial port
  port: &'a mut sp::SerialPort,
  /// Handle that controls writes to port
  write_handle: String,
  /// Send channel used to send responses to
  /// all clients who opened the port
  clients: &'a mut Vec<Sender<SerialResponse>>,
}

/// Manages tracking and reading/writing from serial
/// ports
struct SerialPortManager<'a> {
  /// Maintains list of ports
  open_ports: HashMap<String, OpenPort<'a>>,
  /// Receiver for serial requests
  receiver: Receiver<SerialRequest>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl<'a> SerialPortManager<'a> {
  fn open_port(&self, port: String) {
    // Check if port is already open

    // If not, open it
    let spSettings = sp::SerialPortSettings {
      baud_rate: sp::BaudRate::Baud115200,
      data_bits: sp::DataBits::Eight,
      flow_control: sp::FlowControl::None,
      parity: sp::Parity::None,
      stop_bits: sp::StopBits::One,
      timeout: Duration::from_millis(1),
    };

  }

  fn add_sender(&self, port: String, sender: Sender<SerialResponse>) {}

  fn release_write_lock(&self, handle: String, port: Option<String>) {}

  fn add_write_lock(&self, handle: String, port: String) {}

  fn write_port(&self, handle: String, port: String, data: String, base64: Option<bool>) {}

  fn close_port(&self, port: String) {}

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&self, msg: SerialRequest) {
    match msg {
      SerialRequest::Open { port } => self.open_port(port),
      SerialRequest::WriteLock { handle, port } => self.add_write_lock(handle, port),
      SerialRequest::ReleaseWriteLock { handle, port } => self.release_write_lock(handle, port),
      SerialRequest::Write {
        handle,
        port,
        data,
        base64,
      } => self.write_port(handle, port, data, base64),
      SerialRequest::Close { port } => self.close_port(port),
    }
  }

  /// Fire up the port manager
  ///
  /// TODO Right now this is spinning a thread between reading
  /// subscription requests, reading serial port data
  /// etc. This will cause high cpu usage
  ///
  /// TODO Once this is working, refactor to avoid
  /// thread spinning?
  ///
  fn run(&mut self) {

    let mut shutdown = false;
    let sleep_dur = Duration::from_millis(50);
    let mut serial_buf: Vec<u8> = vec![0; 4096];

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv(){
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
            }
          }
        }
        Ok(req) => self.handle_serial_request(req)
      }

      // Check for new data on each port
      for (portName, openPort) in self.open_ports.iter_mut() {
        // If we have data, send it back
        let bytes_read = openPort.port.read(serial_buf.as_mut_slice());
        // Remove all dead weak references
        // TODO SEND THE DATA
        // openPort.clients.retain(|r| r.upgrade().is_some());
        // for client in openPort.clients.iter_mut(){
        //   match client.upgrade() {
        //     Some(v) => {}
        //     _ => {}
        //   }
        // }
      }

      // Check for Subscribe requests
      match self.subsc_receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              shutdown = true;
              info!("Shutting down SerialPortManager");
            }
          }
        }
        Ok(subs) => {

        }
      }
    }
  }
}

// TODO How to spawn and fire it up
// TODO Document that closing subscription sender will result in
// portmanager shutdown.
// fn spawnManager() -> {}
<|endoftext|>