<commit_before>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are defined in this crate
//! because they cannot be used in [syn] without "full" feature.
//!
//! ## Optional features
//!
//! syn-mid in the default features aims to provide the features between "full"
//! and "derive" of [syn].
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: struct.ItemFn.html
//! [`syn_mid::Block`]: struct.Block.html
//! [syn]: https://github.com/dtolnay/syn

#![doc(html_root_url = "https://docs.rs/syn-mid/0.4.0")]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code))
))]
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(
    clippy::eval_order_dependence,
    clippy::large_enum_variant,
    clippy::module_name_repetitions,
    clippy::use_self
)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod arg;
mod pat;
mod path;

pub use self::{arg::*, pat::*};

use proc_macro2::TokenStream;
use syn::{
    punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility,
};

ast_struct! {
    /// A braced block containing Rust statements.
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: TokenStream,
    }
}

ast_struct! {
    /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
    /// }`.
    pub struct ItemFn {
        pub attrs: Vec<Attribute>,
        pub vis: Visibility,
        pub constness: Option<Token![const]>,
        pub asyncness: Option<Token![async]>,
        pub unsafety: Option<Token![unsafe]>,
        pub abi: Option<Abi>,
        pub fn_token: Token![fn],
        pub ident: Ident,
        pub generics: Generics,
        pub paren_token: token::Paren,
        pub inputs: Punctuated<FnArg, Token![,]>,
        pub output: ReturnType,
        pub block: Block,
    }
}

mod parsing {
    use syn::{
        braced, parenthesized,
        parse::{Parse, ParseStream, Result},
        Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility, WhereClause,
    };

    use super::{Block, FnArg, ItemFn};

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

    impl Parse for ItemFn {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let attrs = input.call(Attribute::parse_outer)?;
            let vis: Visibility = input.parse()?;
            let constness: Option<Token![const]> = input.parse()?;
            let asyncness: Option<Token![async]> = input.parse()?;
            let unsafety: Option<Token![unsafe]> = input.parse()?;
            let abi: Option<Abi> = input.parse()?;
            let fn_token: Token![fn] = input.parse()?;
            let ident: Ident = input.parse()?;
            let generics: Generics = input.parse()?;

            let content;
            let paren_token = parenthesized!(content in input);
            let inputs = content.parse_terminated(FnArg::parse)?;

            let output: ReturnType = input.parse()?;
            let where_clause: Option<WhereClause> = input.parse()?;

            let block = input.parse()?;

            Ok(Self {
                attrs,
                vis,
                constness,
                asyncness,
                unsafety,
                abi,
                fn_token,
                ident,
                generics: Generics { where_clause, ..generics },
                paren_token,
                inputs,
                output,
                block,
            })
        }
    }
}

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

    use super::{Block, ItemFn};

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

    impl ToTokens for ItemFn {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            self.constness.to_tokens(tokens);
            self.asyncness.to_tokens(tokens);
            self.unsafety.to_tokens(tokens);
            self.abi.to_tokens(tokens);
            self.fn_token.to_tokens(tokens);
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            self.paren_token.surround(tokens, |tokens| {
                self.inputs.to_tokens(tokens);
            });
            self.output.to_tokens(tokens);
            self.generics.where_clause.to_tokens(tokens);
            self.block.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.block.stmts.clone());
            });
        }
    }
}
<commit_msg>Remove #![warn(clippy::pedantic)]<commit_after>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are defined in this crate
//! because they cannot be used in [syn] without "full" feature.
//!
//! ## Optional features
//!
//! syn-mid in the default features aims to provide the features between "full"
//! and "derive" of [syn].
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: struct.ItemFn.html
//! [`syn_mid::Block`]: struct.Block.html
//! [syn]: https://github.com/dtolnay/syn

#![doc(html_root_url = "https://docs.rs/syn-mid/0.4.0")]
#![doc(test(
    no_crate_inject,
    attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code))
))]
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::all)]
#![allow(clippy::eval_order_dependence, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod arg;
mod pat;
mod path;

pub use self::{arg::*, pat::*};

use proc_macro2::TokenStream;
use syn::{
    punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility,
};

ast_struct! {
    /// A braced block containing Rust statements.
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: TokenStream,
    }
}

ast_struct! {
    /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
    /// }`.
    pub struct ItemFn {
        pub attrs: Vec<Attribute>,
        pub vis: Visibility,
        pub constness: Option<Token![const]>,
        pub asyncness: Option<Token![async]>,
        pub unsafety: Option<Token![unsafe]>,
        pub abi: Option<Abi>,
        pub fn_token: Token![fn],
        pub ident: Ident,
        pub generics: Generics,
        pub paren_token: token::Paren,
        pub inputs: Punctuated<FnArg, Token![,]>,
        pub output: ReturnType,
        pub block: Block,
    }
}

mod parsing {
    use syn::{
        braced, parenthesized,
        parse::{Parse, ParseStream, Result},
        Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility, WhereClause,
    };

    use super::{Block, FnArg, ItemFn};

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

    impl Parse for ItemFn {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let attrs = input.call(Attribute::parse_outer)?;
            let vis: Visibility = input.parse()?;
            let constness: Option<Token![const]> = input.parse()?;
            let asyncness: Option<Token![async]> = input.parse()?;
            let unsafety: Option<Token![unsafe]> = input.parse()?;
            let abi: Option<Abi> = input.parse()?;
            let fn_token: Token![fn] = input.parse()?;
            let ident: Ident = input.parse()?;
            let generics: Generics = input.parse()?;

            let content;
            let paren_token = parenthesized!(content in input);
            let inputs = content.parse_terminated(FnArg::parse)?;

            let output: ReturnType = input.parse()?;
            let where_clause: Option<WhereClause> = input.parse()?;

            let block = input.parse()?;

            Ok(Self {
                attrs,
                vis,
                constness,
                asyncness,
                unsafety,
                abi,
                fn_token,
                ident,
                generics: Generics { where_clause, ..generics },
                paren_token,
                inputs,
                output,
                block,
            })
        }
    }
}

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

    use super::{Block, ItemFn};

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

    impl ToTokens for ItemFn {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            self.constness.to_tokens(tokens);
            self.asyncness.to_tokens(tokens);
            self.unsafety.to_tokens(tokens);
            self.abi.to_tokens(tokens);
            self.fn_token.to_tokens(tokens);
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            self.paren_token.surround(tokens, |tokens| {
                self.inputs.to_tokens(tokens);
            });
            self.output.to_tokens(tokens);
            self.generics.where_clause.to_tokens(tokens);
            self.block.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.block.stmts.clone());
            });
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_imports)]

#[macro_use]
extern crate nom;

extern crate crc;

use nom::{HexDisplay, Needed, IResult, ErrorKind, le_i32, le_u64, le_u32, le_u8, le_u16, length_value, le_f32,
          FileProducer};
use nom::Err;
use nom::IResult::*;

struct A {
    a: u8,
    b: u8,
}

#[derive(PartialEq,Debug)]
enum RProp {
    Array(Vec<Vec<(String, RProp)>>),
    Bool(bool),
    Byte(u8),
    Float(f32),
    Int(u32),
    Name(String),
    QWord(u64),
    Str(String),
}

named!(length_encoded,
       chain!(
        size: le_u32 ~
        crc: le_u32 ~
        data: take!(size),
        || {data}
    ));

/// Text is encoded with a leading int that denotes the number of bytes that
/// the text spans. The last byte in the text will be null terminated, so we trim
/// it off. It may seem redundant to store this information, but stackoverflow contains
/// a nice reasoning for why it may have been done this way:
///
/// http://stackoverflow.com/questions/6293457/why-are-c-net-strings-length-prefixed-and-null-terminated
named!(text_encoded<&[u8], &str>,
    chain!(
        size: le_u32 ~
        data: take_str!(size - 1) ~
        take!(1),
        || {data}
    )
);

named!(str_prop<&[u8], RProp>,
  chain!(le_u64 ~ x: text_encoded,
    || {RProp::Str(x.to_string())}));

named!(name_prop<&[u8], RProp>,
  chain!(le_u64 ~ x: text_encoded,
    || {RProp::Name(x.to_string())}));

named!(int_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_u32,
        || {RProp::Int(x)}));

named!(bool_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_u8,
        || {RProp::Bool(x == 1)}));

named!(float_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_f32,
        || {RProp::Float(x)}));

named!(qword_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_u64,
        || {RProp::QWord(x)}));

named!(array_prop<&[u8], RProp>,
    chain!(
        le_u64 ~
        size: le_u32 ~
        elems: count!(rdict, size as usize),
        || {RProp::Array(elems)}));

named!(rprop_encoded<&[u8], RProp>,
  switch!(text_encoded,
    "ArrayProperty" => call!(array_prop) |
    "BoolProperty" => call!(bool_prop) |
    "ByteProperty" => call!(str_prop)|
    "FloatProperty" => call!(float_prop) |
    "IntProperty" => call!(int_prop) |
    "NameProperty" => call!(name_prop) |
    "QWordProperty" => call!(qword_prop) |
    "StrProperty" => call!(str_prop)
  )
);

fn rdict(input: &[u8]) -> IResult<&[u8], Vec<(String, RProp)> > {
    let mut v: Vec<(String, RProp)> = Vec::new();
    let mut res: IResult<&[u8], Vec<(String, RProp)>> = IResult::Done(input, Vec::new());
    let mut done = false;
    let mut cslice = input;

    while !done {
      match text_encoded(cslice) {
        IResult::Done(i, txt) => {
          cslice = i;
          match txt {
            "None" => { done = true }
            _ => {
              match rprop_encoded(cslice) {
                IResult::Done(inp, val) => { cslice = inp; v.push((txt.to_string(), val)); },
                IResult::Incomplete(a) => { res = IResult::Incomplete(a); done = true },
                IResult::Error(a) => { res = IResult::Error(a); done = true }
              }
            }
          }
        },

        IResult::Incomplete(a) => {
          done = true;
          res = IResult::Incomplete(a);
        },

        IResult::Error(a) => {
          done = true;
          res = IResult::Error(a);
        }
      }
    }

    match res {
      IResult::Done(a, b) => IResult::Done(cslice, v),
      _ => res
    }
}

named!(f<&[u8],A>,
    chain!(
        header_size:  le_i32 ~
        header_crc:   le_i32 ~
        header:       take!(header_size) ~
        content_size: le_i32 ~
        content_crc:  le_i32 ~
        content:      take!(content_size),
        || {A {a: 0, b: 0}}
    )
);

#[cfg(test)]
mod tests {
    use nom::IResult::{Done, Error, Incomplete};
    use nom::Needed::Size;
    use super::RProp::*;

    #[test]
    fn missing_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..8]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn incomplete_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..9]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn missing_header() {
        let r = super::length_encoded(&[]);
        assert_eq!(r, Incomplete(Size(4)));
    }

    #[test]
    fn missing_crc_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..4]);
        assert_eq!(r, Incomplete(Size(8)));
    }

    #[test]
    fn parse_a_header_with_zero_data() {
        let data = [0, 0, 0, 0, 0, 0, 0, 0];
        let r = super::length_encoded(&data);
        assert_eq!(r, Done(&[][..], &[][..]));
    }

    #[test]
    fn parse_text_encoding() {
        // dd skip=16 count=28 if=rumble.replay of=text.replay bs=1
        let data = include_bytes!("../assets/text.replay");
        let r = super::text_encoded(data);
        assert_eq!(r, Done(&[][..], "TAGame.Replay_Soccar_TA"));
    }

    #[test]
    fn rdict_no_elements() {
        let data = [0x05, 0x00, 0x00, 0x00, b'N', b'o', b'n', b'e', 0x00];
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  Vec::new()));
    }

    #[test]
    fn rdict_one_element() {
        // dd skip=$((0x1269)) count=$((0x12a8 - 0x1269)) if=rumble.replay of=rdict_one.replay bs=1
        let data = include_bytes!("../assets/rdict_one.replay");
        let r = super::rdict(data);
        assert_eq!(r, Done(&[][..],  vec![("PlayerName".to_string(), super::RProp::Str("comagoosie".to_string()))]));
    }

    #[test]
    fn rdict_one_int_element() {
        // dd skip=$((0x250)) count=$((0x284 - 0x250)) if=rumble.replay of=rdict_int.replay bs=1
        let data = include_bytes!("../assets/rdict_int.replay");
        let r = super::rdict(data);
        assert_eq!(r, Done(&[][..],  vec![("PlayerTeam".to_string(), super::RProp::Int(0))]));
    }

    #[test]
    fn rdict_one_bool_element() {
        // dd skip=$((0xa0f)) count=$((0xa3b - 0xa0f)) if=rumble.replay of=rdict_bool.replay bs=1
        let data = include_bytes!("../assets/rdict_bool.replay");
        let r = super::rdict(data);
        assert_eq!(r, Done(&[][..],  vec![("bBot".to_string(), super::RProp::Bool(false))]));
    }

    fn append_none(input: &[u8]) -> Vec<u8> {
        let append = [0x05, 0x00, 0x00, 0x00, b'N', b'o', b'n', b'e', 0x00];
        let mut v = Vec::new();
        v.extend_from_slice(input);
        v.extend_from_slice(&append);
        v
    }

    #[test]
    fn rdict_one_name_element() {
        // dd skip=$((0x1237)) count=$((0x1269 - 0x1237)) if=rumble.replay of=rdict_name.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_name.replay"));
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  vec![("MatchType".to_string(), super::RProp::Name("Online".to_string()))]));

    }

    #[test]
    fn rdict_one_float_element() {
        // dd skip=$((0x10a2)) count=$((0x10ce - 0x10a2)) if=rumble.replay of=rdict_float.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_float.replay"));
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  vec![("RecordFPS".to_string(), super::RProp::Float(30.0))]));
    }

    #[test]
    fn rdict_one_qword_element() {
        // dd skip=$((0x576)) count=$((0x5a5 - 0x576)) if=rumble.replay of=rdict_qword.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_qword.replay"));
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  vec![("OnlineID".to_string(), super::RProp::QWord(76561198101748375))]));
    }

    #[test]
    fn rdict_one_array_element() {
        // dd skip=$((0x576)) count=$((0x5a5 - 0x576)) if=rumble.replay of=rdict_qword.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_array.replay"));
        let r = super::rdict(&data);
        let expected = vec![
            vec![
                ("frame".to_string(), Int(441)),
                ("PlayerName".to_string(), Str("Cakeboss".to_string())),
                ("PlayerTeam".to_string(), Int(1))
            ], vec![
                ("frame".to_string(), Int(1738)),
                ("PlayerName".to_string(), Str("Sasha Kaun".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(3504)),
                ("PlayerName".to_string(), Str("SilentWarrior".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(5058)),
                ("PlayerName".to_string(), Str("jeffreyj1".to_string())),
                ("PlayerTeam".to_string(), Int(1))
            ], vec![
                ("frame".to_string(), Int(5751)),
                ("PlayerName".to_string(), Str("GOOSE LORD".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(6083)),
                ("PlayerName".to_string(), Str("GOOSE LORD".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(7021)),
                ("PlayerName".to_string(), Str("SilentWarrior".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ]
        ];
        assert_eq!(r, Done(&[][..],  vec![("Goals".to_string(), super::RProp::Array(expected))]));
    }
}
<commit_msg>Shorten some functions with importing modules<commit_after>#![allow(dead_code)]
#![allow(unused_imports)]

#[macro_use]
extern crate nom;

extern crate crc;

use nom::{HexDisplay, Needed, IResult, ErrorKind, le_i32, le_u64, le_u32, le_u8, le_u16, length_value, le_f32,
          FileProducer};
use nom::Err;
use nom::IResult::*;

struct A {
    a: u8,
    b: u8,
}

#[derive(PartialEq,Debug)]
enum RProp {
    Array(Vec<Vec<(String, RProp)>>),
    Bool(bool),
    Byte(u8),
    Float(f32),
    Int(u32),
    Name(String),
    QWord(u64),
    Str(String),
}

named!(length_encoded,
       chain!(
        size: le_u32 ~
        crc: le_u32 ~
        data: take!(size),
        || {data}
    ));

/// Text is encoded with a leading int that denotes the number of bytes that
/// the text spans. The last byte in the text will be null terminated, so we trim
/// it off. It may seem redundant to store this information, but stackoverflow contains
/// a nice reasoning for why it may have been done this way:
///
/// http://stackoverflow.com/questions/6293457/why-are-c-net-strings-length-prefixed-and-null-terminated
named!(text_encoded<&[u8], &str>,
    chain!(
        size: le_u32 ~
        data: take_str!(size - 1) ~
        take!(1),
        || {data}
    )
);

named!(str_prop<&[u8], RProp>,
  chain!(le_u64 ~ x: text_encoded,
    || {RProp::Str(x.to_string())}));

named!(name_prop<&[u8], RProp>,
  chain!(le_u64 ~ x: text_encoded,
    || {RProp::Name(x.to_string())}));

named!(int_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_u32,
        || {RProp::Int(x)}));

named!(bool_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_u8,
        || {RProp::Bool(x == 1)}));

named!(float_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_f32,
        || {RProp::Float(x)}));

named!(qword_prop<&[u8], RProp>,
    chain!(le_u64 ~ x: le_u64,
        || {RProp::QWord(x)}));

named!(array_prop<&[u8], RProp>,
    chain!(
        le_u64 ~
        size: le_u32 ~
        elems: count!(rdict, size as usize),
        || {RProp::Array(elems)}));

named!(rprop_encoded<&[u8], RProp>,
  switch!(text_encoded,
    "ArrayProperty" => call!(array_prop) |
    "BoolProperty" => call!(bool_prop) |
    "ByteProperty" => call!(str_prop)|
    "FloatProperty" => call!(float_prop) |
    "IntProperty" => call!(int_prop) |
    "NameProperty" => call!(name_prop) |
    "QWordProperty" => call!(qword_prop) |
    "StrProperty" => call!(str_prop)
  )
);

fn rdict(input: &[u8]) -> IResult<&[u8], Vec<(String, RProp)> > {
    let mut v: Vec<(String, RProp)> = Vec::new();
    let mut res: IResult<&[u8], Vec<(String, RProp)>> = IResult::Done(input, Vec::new());
    let mut done = false;
    let mut cslice = input;

    while !done {
      match text_encoded(cslice) {
        IResult::Done(i, txt) => {
          cslice = i;
          match txt {
            "None" => { done = true }
            _ => {
              match rprop_encoded(cslice) {
                IResult::Done(inp, val) => { cslice = inp; v.push((txt.to_string(), val)); },
                IResult::Incomplete(a) => { res = IResult::Incomplete(a); done = true },
                IResult::Error(a) => { res = IResult::Error(a); done = true }
              }
            }
          }
        },

        IResult::Incomplete(a) => {
          done = true;
          res = IResult::Incomplete(a);
        },

        IResult::Error(a) => {
          done = true;
          res = IResult::Error(a);
        }
      }
    }

    match res {
      IResult::Done(a, b) => IResult::Done(cslice, v),
      _ => res
    }
}

named!(f<&[u8],A>,
    chain!(
        header_size:  le_i32 ~
        header_crc:   le_i32 ~
        header:       take!(header_size) ~
        content_size: le_i32 ~
        content_crc:  le_i32 ~
        content:      take!(content_size),
        || {A {a: 0, b: 0}}
    )
);

#[cfg(test)]
mod tests {
    use nom::IResult::{Done, Error, Incomplete};
    use nom::Needed::Size;
    use super::RProp::*;
    use super::{length_encoded};

    #[test]
    fn missing_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = length_encoded(&data[..8]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn incomplete_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = length_encoded(&data[..9]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn missing_header() {
        let r = length_encoded(&[]);
        assert_eq!(r, Incomplete(Size(4)));
    }

    #[test]
    fn missing_crc_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = length_encoded(&data[..4]);
        assert_eq!(r, Incomplete(Size(8)));
    }

    #[test]
    fn parse_a_header_with_zero_data() {
        let data = [0, 0, 0, 0, 0, 0, 0, 0];
        let r = length_encoded(&data);
        assert_eq!(r, Done(&[][..], &[][..]));
    }

    #[test]
    fn parse_text_encoding() {
        // dd skip=16 count=28 if=rumble.replay of=text.replay bs=1
        let data = include_bytes!("../assets/text.replay");
        let r = super::text_encoded(data);
        assert_eq!(r, Done(&[][..], "TAGame.Replay_Soccar_TA"));
    }

    #[test]
    fn rdict_no_elements() {
        let data = [0x05, 0x00, 0x00, 0x00, b'N', b'o', b'n', b'e', 0x00];
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  Vec::new()));
    }

    #[test]
    fn rdict_one_element() {
        // dd skip=$((0x1269)) count=$((0x12a8 - 0x1269)) if=rumble.replay of=rdict_one.replay bs=1
        let data = include_bytes!("../assets/rdict_one.replay");
        let r = super::rdict(data);
        assert_eq!(r, Done(&[][..],  vec![("PlayerName".to_string(), Str("comagoosie".to_string()))]));
    }

    #[test]
    fn rdict_one_int_element() {
        // dd skip=$((0x250)) count=$((0x284 - 0x250)) if=rumble.replay of=rdict_int.replay bs=1
        let data = include_bytes!("../assets/rdict_int.replay");
        let r = super::rdict(data);
        assert_eq!(r, Done(&[][..],  vec![("PlayerTeam".to_string(), Int(0))]));
    }

    #[test]
    fn rdict_one_bool_element() {
        // dd skip=$((0xa0f)) count=$((0xa3b - 0xa0f)) if=rumble.replay of=rdict_bool.replay bs=1
        let data = include_bytes!("../assets/rdict_bool.replay");
        let r = super::rdict(data);
        assert_eq!(r, Done(&[][..],  vec![("bBot".to_string(), Bool(false))]));
    }

    fn append_none(input: &[u8]) -> Vec<u8> {
        let append = [0x05, 0x00, 0x00, 0x00, b'N', b'o', b'n', b'e', 0x00];
        let mut v = Vec::new();
        v.extend_from_slice(input);
        v.extend_from_slice(&append);
        v
    }

    #[test]
    fn rdict_one_name_element() {
        // dd skip=$((0x1237)) count=$((0x1269 - 0x1237)) if=rumble.replay of=rdict_name.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_name.replay"));
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  vec![("MatchType".to_string(), Name("Online".to_string()))]));

    }

    #[test]
    fn rdict_one_float_element() {
        // dd skip=$((0x10a2)) count=$((0x10ce - 0x10a2)) if=rumble.replay of=rdict_float.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_float.replay"));
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  vec![("RecordFPS".to_string(), Float(30.0))]));
    }

    #[test]
    fn rdict_one_qword_element() {
        // dd skip=$((0x576)) count=$((0x5a5 - 0x576)) if=rumble.replay of=rdict_qword.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_qword.replay"));
        let r = super::rdict(&data);
        assert_eq!(r, Done(&[][..],  vec![("OnlineID".to_string(), QWord(76561198101748375))]));
    }

    #[test]
    fn rdict_one_array_element() {
        // dd skip=$((0x576)) count=$((0x5a5 - 0x576)) if=rumble.replay of=rdict_qword.replay bs=1
        let data = append_none(include_bytes!("../assets/rdict_array.replay"));
        let r = super::rdict(&data);
        let expected = vec![
            vec![
                ("frame".to_string(), Int(441)),
                ("PlayerName".to_string(), Str("Cakeboss".to_string())),
                ("PlayerTeam".to_string(), Int(1))
            ], vec![
                ("frame".to_string(), Int(1738)),
                ("PlayerName".to_string(), Str("Sasha Kaun".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(3504)),
                ("PlayerName".to_string(), Str("SilentWarrior".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(5058)),
                ("PlayerName".to_string(), Str("jeffreyj1".to_string())),
                ("PlayerTeam".to_string(), Int(1))
            ], vec![
                ("frame".to_string(), Int(5751)),
                ("PlayerName".to_string(), Str("GOOSE LORD".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(6083)),
                ("PlayerName".to_string(), Str("GOOSE LORD".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ], vec![
                ("frame".to_string(), Int(7021)),
                ("PlayerName".to_string(), Str("SilentWarrior".to_string())),
                ("PlayerTeam".to_string(), Int(0))
            ]
        ];
        assert_eq!(r, Done(&[][..],  vec![("Goals".to_string(), Array(expected))]));
    }
}
<|endoftext|>


<commit_before>//! This crate provides pull parser for FBX binary.
//!
//! FBX data consists of generic node and node properties, and it requires interpretation to use as
//! 3D contents.
//! It is similar to relation of XML and COLLADA. COLLADA is represented using XML, but XML DOM is
//! difficult to use directly as COLLADA data.
//! Compare FBX to COLLADA, this crate is XML reader, not COLLADA importer.
//!
//! This crate is specialized to read FBX binary format fastly and would *NOT* implement FBX ASCII
//! reader or FBX writer.

extern crate byteorder;
extern crate flate2;
#[macro_use]
extern crate log;

pub use error::{Error, Result};
pub use event::{FbxEvent, FbxHeaderInfo};
pub use property::{DelayedProperties, PropertiesIter};
pub use reader::{Events, EventReader};

pub mod error;
pub mod event;
pub mod property;
pub mod reader;
<commit_msg>Re-export `property::Property` as `::Property`<commit_after>//! This crate provides pull parser for FBX binary.
//!
//! FBX data consists of generic node and node properties, and it requires interpretation to use as
//! 3D contents.
//! It is similar to relation of XML and COLLADA. COLLADA is represented using XML, but XML DOM is
//! difficult to use directly as COLLADA data.
//! Compare FBX to COLLADA, this crate is XML reader, not COLLADA importer.
//!
//! This crate is specialized to read FBX binary format fastly and would *NOT* implement FBX ASCII
//! reader or FBX writer.

extern crate byteorder;
extern crate flate2;
#[macro_use]
extern crate log;

pub use error::{Error, Result};
pub use event::{FbxEvent, FbxHeaderInfo};
pub use property::{DelayedProperties, Property, PropertiesIter};
pub use reader::{Events, EventReader};

pub mod error;
pub mod event;
pub mod property;
pub mod reader;
<|endoftext|>


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

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

#![feature(link_args, collections, core)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

extern crate libc;
#[macro_use]
extern crate log;
extern crate num;
extern crate rustc_serialize as serialize;

use libc::c_uint;

/*
FIXME: Not sure where JS_Lock is
pub use jsapi::bindgen::JS_Lock as JS_LockRuntime;
pub use jsapi::bindgen::JS_Unlock as JS_UnlockRuntime;
*/

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

use jsapi::{JSContext, JSObject, JS_ComputeThis, JSProtoKey};
use jsval::JSVal;

pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub const default_stacksize: usize = 8192;

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

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

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

pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint;

pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4;
pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31;

pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5;
pub const JSCLASS_USERBIT1: u32 = 1 << 7;

pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4);

pub const JSSLOT_PROXY_PRIVATE: u32 = 1;

pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100;

#[link(name = "jsglue")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "stdc++")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern { }

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

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

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}
<commit_msg>Add JSTrue/JSFalse<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

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

#![feature(link_args, collections, core)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

extern crate libc;
#[macro_use]
extern crate log;
extern crate num;
extern crate rustc_serialize as serialize;

use libc::c_uint;

/*
FIXME: Not sure where JS_Lock is
pub use jsapi::bindgen::JS_Lock as JS_LockRuntime;
pub use jsapi::bindgen::JS_Unlock as JS_UnlockRuntime;
*/

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

use jsapi::{JSContext, JSObject, JS_ComputeThis, JSProtoKey};
use jsval::JSVal;

pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub const default_stacksize: usize = 8192;

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

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

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

pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint;

pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4;
pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31;

pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5;
pub const JSCLASS_USERBIT1: u32 = 1 << 7;

pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4);

pub const JSSLOT_PROXY_PRIVATE: u32 = 1;

pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100;

pub const JSTrue: u8 = 1;
pub const JSFalse: u8 = 0;

#[link(name = "jsglue")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "stdc++")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern { }

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

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

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


<commit_before>// Copyright 2016 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! simple_slab provides a fast, minimal, slab allocator.
//! ## Usage
//!
//! ```no_run
//! extern crate simple_slab;
//!
//! use simple_slab::Slab;
//!
//! fn main() {
//!     const MAX_ELEMS: usize = 100000;
//!
//!     let mut slab = Slab::<u32>::with_capacity(MAX_ELEMS);
//!
//!     // Insertion
//!     for num in 0..MAX_ELEMS {
//!         slab.insert(num as u32);
//!     }
//!
//!     // Traversal
//!     for offset in 0..slab.len() {
//!         slab[offset] = 33;
//!     }
//!
//!     // Iteration
//!     for num in slab.iter() {
//!         // Stuff...
//!     }
//!
//!     // Removal
//!     for offset in 0..slab.len() {
//!         let num = slab.remove(offset);
//!     }
//! }
//! ```

extern crate libc;

use std::{mem, ptr};
use std::ops::{Drop, Index};
use std::iter::{Iterator, IntoIterator};

pub struct Slab<T> {
    capacity: usize,
    num_elems: usize,
    mem_ptr: *mut T
}

pub struct SlabIter<'a, T: 'a> {
    slab: &'a Slab<T>,
    current_offset: usize
}

pub struct SlabMutIter<'a, T: 'a> {
    iter: SlabIter<'a, T>
}

impl<T> Slab<T> {
    /// Creates a new Slab
    pub fn new() -> Slab<T> { Slab::with_capacity(1) }

    /// Creates a new, empty Slab with room for `capacity` elems
    ///
    /// # Panics
    ///
    /// Panics if the host system is out of memory
    pub fn with_capacity(capacity: usize) -> Slab<T> {
        let maybe_ptr = unsafe {
            libc::malloc((mem::size_of::<T>() * capacity)) as *mut T
        };

        // malloc will return NULL if called with zero
        if maybe_ptr.is_null() && capacity != 0 {
            panic!("Unable to allocate requested capacity")
        }

        return Slab {
            capacity: capacity,
            num_elems: 0,
            mem_ptr: maybe_ptr
        }
    }

    /// Inserts a new element into the slab, re-allocating if neccessary.
    ///
    /// # Panics
    /// * If the host system is out of memory.
    #[inline]
    pub fn insert(&mut self, elem: T) {
        if self.num_elems == self.capacity {
            self.reallocate();
        }

        let next_elem_offset = self.num_elems as isize;
        unsafe {
            ptr::write(self.mem_ptr.offset(next_elem_offset), elem);
        }
        self.num_elems += 1;
    }

    /// Removes the element at `offset`.
    ///
    /// # Panics
    ///
    /// * If `offset` is out of bounds.
    #[inline]
    pub fn remove(&mut self, offset: usize) -> T {
        if offset >= self.num_elems {
            panic!("Offset {} out of bounds for slab.len: {}", offset, self.num_elems)
        }

        let last_elem_offset = (self.num_elems - 1) as isize;
        let elem = unsafe {
            let elem_ptr = self.mem_ptr.offset(offset as isize);
            let last_elem_ptr = self.mem_ptr.offset(last_elem_offset);
            mem::replace(&mut (*elem_ptr), ptr::read(last_elem_ptr))
        };

        self.num_elems -= 1;

        return elem;
    }

    /// Returns the number of elements in the slab
    #[inline]
    pub fn len(&self) -> usize { self.num_elems }

    /// Returns an iterator over the slab
    #[inline]
    pub fn iter(&self) -> SlabIter<T> {
        SlabIter {
            slab: self,
            current_offset: 0
        }
    }

    /// Returns a mutable iterator over the slab
    #[inline]
    pub fn iter_mut(&mut self) -> SlabMutIter<T> {
        SlabMutIter { iter: self.iter() }
    }

    /// Reserves capacity * 2 extra space in this slab
    ///
    /// # Panics
    ///
    /// Panics if the host system is out of memory
    #[inline]
    fn reallocate(&mut self) {
        let new_capacity = if self.capacity != 0 { self.capacity * 2 } else { 1 };

        unsafe {
            let maybe_ptr = libc::realloc(self.mem_ptr as *mut libc::c_void,
                                          (mem::size_of::<T>() * new_capacity)) as *mut T;

            if maybe_ptr.is_null() {
                panic!("Unable to allocate new capacity")
            }

            self.capacity = new_capacity;
            self.mem_ptr = maybe_ptr;
        }
    }
}

impl<T> Drop for Slab<T> {
    fn drop(&mut self) {
        unsafe {
            for x in 0..self.len() {
                let elem_ptr = self.mem_ptr.offset(x as isize);
                ptr::drop_in_place(elem_ptr);
            }

            libc::free(self.mem_ptr as *mut _ as *mut libc::c_void);
        }
    }
}

impl<T> Index<usize> for Slab<T> {
    type Output = T;
    fn index(&self, index: usize) -> &Self::Output {
        unsafe {
            &(*(self.mem_ptr.offset(index as isize)))
        }
    }
}

impl<'a, T> Iterator for SlabIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        while self.current_offset < self.slab.len() {
            let offset = self.current_offset;
            self.current_offset += 1;
            unsafe {
                return Some(&(*self.slab.mem_ptr.offset(offset as isize)));
            }
        }

        return  None;
    }
}

impl<'a, T> Iterator for SlabMutIter<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<&'a mut T> {
        unsafe { mem::transmute(self.iter.next()) }
    }
}

impl<'a, T> IntoIterator for &'a Slab<T> {
    type Item = &'a T;
    type IntoIter = SlabIter<'a, T>;
    fn into_iter(self) -> SlabIter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Slab<T> {
    type Item = &'a mut T;
    type IntoIter = SlabMutIter<'a, T>;
    fn into_iter(self) -> SlabMutIter<'a, T> {
        self.iter_mut()
    }
}
<commit_msg>reallocate refactor.<commit_after>// Copyright 2016 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! simple_slab provides a fast, minimal, slab allocator.
//! ## Usage
//!
//! ```no_run
//! extern crate simple_slab;
//!
//! use simple_slab::Slab;
//!
//! fn main() {
//!     const MAX_ELEMS: usize = 100000;
//!
//!     let mut slab = Slab::<u32>::with_capacity(MAX_ELEMS);
//!
//!     // Insertion
//!     for num in 0..MAX_ELEMS {
//!         slab.insert(num as u32);
//!     }
//!
//!     // Traversal
//!     for offset in 0..slab.len() {
//!         slab[offset] = 33;
//!     }
//!
//!     // Iteration
//!     for num in slab.iter() {
//!         // Stuff...
//!     }
//!
//!     // Removal
//!     for offset in 0..slab.len() {
//!         let num = slab.remove(offset);
//!     }
//! }
//! ```

extern crate libc;

use std::{mem, ptr};
use std::ops::{Drop, Index};
use std::iter::{Iterator, IntoIterator};

pub struct Slab<T> {
    capacity: usize,
    num_elems: usize,
    mem_ptr: *mut T
}

pub struct SlabIter<'a, T: 'a> {
    slab: &'a Slab<T>,
    current_offset: usize
}

pub struct SlabMutIter<'a, T: 'a> {
    iter: SlabIter<'a, T>
}

impl<T> Slab<T> {
    /// Creates a new Slab
    pub fn new() -> Slab<T> { Slab::with_capacity(1) }

    /// Creates a new, empty Slab with room for `capacity` elems
    ///
    /// # Panics
    ///
    /// Panics if the host system is out of memory
    pub fn with_capacity(capacity: usize) -> Slab<T> {
        let maybe_ptr = unsafe {
            libc::malloc((mem::size_of::<T>() * capacity)) as *mut T
        };

        // malloc will return NULL if called with zero
        if maybe_ptr.is_null() && capacity != 0 {
            panic!("Unable to allocate requested capacity")
        }

        return Slab {
            capacity: capacity,
            num_elems: 0,
            mem_ptr: maybe_ptr
        }
    }

    /// Inserts a new element into the slab, re-allocating if neccessary.
    ///
    /// # Panics
    /// * If the host system is out of memory.
    #[inline]
    pub fn insert(&mut self, elem: T) {
        if self.num_elems == self.capacity {
            self.reallocate();
        }

        let next_elem_offset = self.num_elems as isize;
        unsafe {
            ptr::write(self.mem_ptr.offset(next_elem_offset), elem);
        }
        self.num_elems += 1;
    }

    /// Removes the element at `offset`.
    ///
    /// # Panics
    ///
    /// * If `offset` is out of bounds.
    #[inline]
    pub fn remove(&mut self, offset: usize) -> T {
        if offset >= self.num_elems {
            panic!("Offset {} out of bounds for slab.len: {}", offset, self.num_elems)
        }

        let last_elem_offset = (self.num_elems - 1) as isize;
        let elem = unsafe {
            let elem_ptr = self.mem_ptr.offset(offset as isize);
            let last_elem_ptr = self.mem_ptr.offset(last_elem_offset);
            mem::replace(&mut (*elem_ptr), ptr::read(last_elem_ptr))
        };

        self.num_elems -= 1;

        return elem;
    }

    /// Returns the number of elements in the slab
    #[inline]
    pub fn len(&self) -> usize { self.num_elems }

    /// Returns an iterator over the slab
    #[inline]
    pub fn iter(&self) -> SlabIter<T> {
        SlabIter {
            slab: self,
            current_offset: 0
        }
    }

    /// Returns a mutable iterator over the slab
    #[inline]
    pub fn iter_mut(&mut self) -> SlabMutIter<T> {
        SlabMutIter { iter: self.iter() }
    }

    /// Reserves capacity * 2 extra space in this slab
    ///
    /// # Panics
    ///
    /// Panics if the host system is out of memory
    #[inline]
    fn reallocate(&mut self) {
        let new_capacity = if self.capacity != 0 { self.capacity * 2 } else { 1 };
        let maybe_ptr = unsafe {
            libc::realloc(self.mem_ptr as *mut libc::c_void,
                          (mem::size_of::<T>() * new_capacity)) as *mut T
        };

        if maybe_ptr.is_null() {
            panic!("Unable to allocate new capacity")
        }

        self.capacity = new_capacity;
        self.mem_ptr = maybe_ptr;
    }
}

impl<T> Drop for Slab<T> {
    fn drop(&mut self) {
        unsafe {
            for x in 0..self.len() {
                let elem_ptr = self.mem_ptr.offset(x as isize);
                ptr::drop_in_place(elem_ptr);
            }

            libc::free(self.mem_ptr as *mut _ as *mut libc::c_void);
        }
    }
}

impl<T> Index<usize> for Slab<T> {
    type Output = T;
    fn index(&self, index: usize) -> &Self::Output {
        unsafe {
            &(*(self.mem_ptr.offset(index as isize)))
        }
    }
}

impl<'a, T> Iterator for SlabIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        while self.current_offset < self.slab.len() {
            let offset = self.current_offset;
            self.current_offset += 1;
            unsafe {
                return Some(&(*self.slab.mem_ptr.offset(offset as isize)));
            }
        }

        return  None;
    }
}

impl<'a, T> Iterator for SlabMutIter<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<&'a mut T> {
        unsafe { mem::transmute(self.iter.next()) }
    }
}

impl<'a, T> IntoIterator for &'a Slab<T> {
    type Item = &'a T;
    type IntoIter = SlabIter<'a, T>;
    fn into_iter(self) -> SlabIter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Slab<T> {
    type Item = &'a mut T;
    type IntoIter = SlabMutIter<'a, T>;
    fn into_iter(self) -> SlabMutIter<'a, T> {
        self.iter_mut()
    }
}
<|endoftext|>


<commit_before>//! Crate retry provides a function, `retry`, which runs an operation continuously until its
//! return value satisfies a specific condition. The maximum number of times to try and the amount
//! of time to wait between tries is configurable.

use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;

/// An error indicating that a retry call failed.
#[derive(Debug)]
pub struct RetryError {
    message: &'static str
}

impl Display for RetryError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.message)
    }
}

impl Error for RetryError {
    fn description(&self) -> &str {
        self.message
    }
}

/// Invokes a function until a condition is satisfied.
///
/// `value_fn` is a closure that will be executed to produce a value. `condition_fn` is a closure
/// that takes the value produced by `value_fn` and returns a boolean indicating whether or not
/// some desired condition is true. `retry` will invoke `value_fn` up to `tries` times, returning
/// the value as soon as `condition_fn` is satisfied, or returning an error when the last try was
/// unsuccessful. It will wait `wait` milliseconds after each unsuccessful try.
///
/// # Failures
///
/// Will fail when:
///
/// 1. `value_fn` has been been invoked `tries` times and has still not satisfied `condition_fn`.
/// 2. `tries` is zero. It must be at least 1.
///
/// # Examples
///
/// Imagine an HTTP API with an endpoint that returns 204 No Content while a job is processing, and
/// eventually 200 OK when the job has completed. Retrying until the job is finished would be
/// written:
///
/// ```
/// # use retry::retry;
/// # struct Client;
/// # impl Client {
/// #     fn query_job_status(&self) -> Response {
/// #         Response {
/// #             code: 200,
/// #             body: "success",
/// #         }
/// #     }
/// # }
/// # struct Response {
/// #     code: u16,
/// #     body: &'static str,
/// # }
/// # let api_client = Client;
/// match retry(10, 500, || api_client.query_job_status(), |response| response.code == 200) {
///     Ok(response) => println!("Job completed with result: {}", response.body),
///     Err(error) => println!("Job completion could not be verified: {}", error),
/// }
/// ```
///
/// This retries the API call up to 10 times, waiting 500 milliseconds after each unsuccesful
/// attempt.
pub fn retry<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    if tries == 0 {
        return Err(RetryError { message: "tries must be non-zero" });
    }

    for _ in 0..tries {
        let value = value_fn();

        if condition_fn(&value) {
            return Ok(value);
        }

        sleep_ms(wait);
    }

    Err(RetryError { message: "reached last try without condition match" })
}

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

    #[test]
    fn succeeds_on_first_try() {
        let value = retry(1, 0, || 1, |value| *value == 1).ok().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn requires_non_zero_tries() {
        let error = retry(0, 0, || 1, |value| *value == 1).err().unwrap();

        assert_eq!(error.message, "tries must be non-zero");
    }

    #[test]
    fn succeeds_on_subsequent_try() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let error = retry(1, 0, || collection.next().unwrap(), |value| *value == 2).err().unwrap();

        assert_eq!(error.message, "reached last try without condition match");
    }
}
<commit_msg>Add infinite_retry.<commit_after>//! Crate retry provides a set of functions for retrying an operation continuously until its
//! return value satisfies a specific condition.

use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;

/// An error indicating that a retry call failed.
#[derive(Debug)]
pub struct RetryError {
    message: &'static str
}

impl Display for RetryError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.message)
    }
}

impl Error for RetryError {
    fn description(&self) -> &str {
        self.message
    }
}

/// Invokes a function a certain number of times or until a condition is satisfied.
///
/// `value_fn` is a closure that will be executed to produce a value. `condition_fn` is a closure
/// that takes the value produced by `value_fn` and returns a boolean indicating whether or not
/// some desired condition is true. `retry` will invoke `value_fn` up to `tries` times, returning
/// the value as soon as `condition_fn` is satisfied, or returning an error when the last try was
/// unsuccessful. It will wait `wait` milliseconds after each unsuccessful try.
///
/// # Failures
///
/// Will fail when:
///
/// 1. `value_fn` has been been invoked `tries` times and has still not satisfied `condition_fn`.
/// 2. `tries` is zero. It must be at least 1.
///
/// # Examples
///
/// Imagine an HTTP API with an endpoint that returns 204 No Content while a job is processing, and
/// eventually 200 OK when the job has completed. Retrying until the job is finished would be
/// written:
///
/// ```
/// # use retry::retry;
/// # struct Client;
/// # impl Client {
/// #     fn query_job_status(&self) -> Response {
/// #         Response {
/// #             code: 200,
/// #             body: "success",
/// #         }
/// #     }
/// # }
/// # struct Response {
/// #     code: u16,
/// #     body: &'static str,
/// # }
/// # let api_client = Client;
/// match retry(10, 500, || api_client.query_job_status(), |response| response.code == 200) {
///     Ok(response) => println!("Job completed with result: {}", response.body),
///     Err(error) => println!("Job completion could not be verified: {}", error),
/// }
/// ```
///
/// This retries the API call up to 10 times, waiting 500 milliseconds after each unsuccesful
/// attempt.
pub fn retry<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    if tries == 0 {
        return Err(RetryError { message: "tries must be non-zero" });
    }

    for _ in 0..tries {
        let value = value_fn();

        if condition_fn(&value) {
            return Ok(value);
        }

        sleep_ms(wait);
    }

    Err(RetryError { message: "reached last try without condition match" })
}

/// Invokes a function infinitely until a condition is satisfied.
///
/// Works the same as `retry`, but will try an infinite number of times. Since it will never return
/// unsuccessfully, its return value is not wrapped in a `Result`.
pub fn infinite_retry<F, G, R>(
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> R where F: FnMut() -> R, G: FnMut(&R) -> bool {
    loop {
        let value = value_fn();

        if condition_fn(&value) {
            return value;
        }

        sleep_ms(wait);
    }
}

#[cfg(test)]
mod tests {
    use super::{infinite_retry, retry};

    #[test]
    fn succeeds_on_first_try() {
        let value = retry(1, 0, || 1, |value| *value == 1).ok().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn requires_non_zero_tries() {
        let error = retry(0, 0, || 1, |value| *value == 1).err().unwrap();

        assert_eq!(error.message, "tries must be non-zero");
    }

    #[test]
    fn succeeds_on_subsequent_try() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let error = retry(1, 0, || collection.next().unwrap(), |value| *value == 2).err().unwrap();

        assert_eq!(error.message, "reached last try without condition match");
    }

    #[test]
    fn succeeds_without_try_count() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = infinite_retry(0, || collection.next().unwrap(), |value| *value == 5);

        assert_eq!(value, 5);
    }
}
<|endoftext|>


<commit_before>//! par is a terminal interface for rendering progress bars
//!
//! #example
//! ```rust
//! use par::Bar;
//! fn main() {
//!     let bar = Bar::new(100);
//!     for i in 1..101 {
//!         bar.add(i);
//!         std::thread::sleep_ms(10);
//!     }
//!     bar.finish_print("done")
//! }
//! ```
extern crate capsize;
extern crate termsize;

use capsize::Capacity;
use std::io::{self, Read, Write};
use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::default::Default;

static FORMAT: &'static str = "[=>_]";

/// Unit of display for progress counter
pub enum Units {
    /// No units
    None,
    /// format progress in humanized byte sizes
    Bytes
}

impl Default for Units {
    fn default() -> Units {
        Units::None
    }
}

/// Preference for reporting progress
pub enum Reporter {
    /// Report progress to stdout
    StdOut,
    /// Report progress to stderr
    StdErr,
    /// Report progress to a callback
    Callback(fn(String) -> ())
}

impl Default for Reporter {
    fn default() -> Reporter {
        Reporter::StdErr
    }
}

/// write progress. Implementations for Read and Write are provided
pub struct Writer<T> {
    inner: T,
    bar: Bar
}

/// read progress. Implementations for Read and Write are provided
pub struct Reader<T> {
    inner: T,
    bar: Bar
}

impl <R: Read> Reader<R> {
    pub fn new(read: R, bar: Bar) -> Reader<R> {
        Reader {
            inner: read,
            bar: bar
        }
    }
}

impl <R: Read> Read for Reader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = try!(self.inner.read(buf));
        self.bar.add(n);
        Ok(n)
    }
}

impl <W: Write> Writer<W> {
    pub fn new(write: W, bar: Bar) -> Writer<W> {
        Writer {
            inner: write,
            bar: bar
        }
    }
}

impl <W: Write> Write for Writer<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.bar.add(n);
        Ok(n)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

/// A bar of progress information
#[derive(Default)]
pub struct Bar {
    total: usize,
    /// show progress percent, defaults to true
    pub show_percent: bool,
    /// show progress counter. Defaults to true
    pub show_counter: bool,
    /// show main progress bar UI. Defaults to true
    pub show_bar: bool,
    /// an arbitrary string label to prefix display with
    pub prefix: String,
    /// preference for reporting progress
    pub reporter: Reporter,
    current: AtomicUsize,
    pub units: Units,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String
}

impl Bar {
    /// creates a new bar with a target total size of `total`
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            total: total,
            show_percent: true,
            show_counter: true,
            show_bar: true,
            ..Default::default()
        };
        bar.format(FORMAT);
        bar
    }

    /// sets a custom format for display
    /// Example: bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        let prev = self.current.fetch_add(delta, Ordering::Relaxed);
        self.update();
        prev
    }

    /// sets the bar count to specified value
    pub fn set(&self, value: usize) {
        self.current.store(value, Ordering::Relaxed);
        self.update()
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        if current <= self.total {
            self.write(current)
        }
    }

    pub fn finish_print(&self, msg: &str) {
        println!("");
        println!("{}", msg)
    }

    fn width(&self) -> usize {
        termsize::get().map(|s|s.cols as usize).unwrap_or(80)
    }

    fn write(&self, current: usize) {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        fn unit(value: usize, units: &Units) -> String {
            match *units {
                Units::None => value.to_string(),
                Units::Bytes => (value as i64).capacity()
            }
        }

        let width = self.width();

        let mut prefix = self.prefix.clone();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = prefix + &format!(
                "{} / {} ", unit(current, &self.units), unit(self.total, &self.units)
            );
        }

        // percent complete
        if self.show_percent {
            let percent = current as f64 / (self.total as f64 / 100_f64);
            suffix = suffix + &format!(
                " {:.*} %", 2, percent
            );
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }

        match self.reporter {
            Reporter::StdErr => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::StdOut => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::Callback(cb) => {
                cb(display);
            }
        }
    }
}

#[test]
fn it_works() {
}
<commit_msg>refactor<commit_after>//! par is a terminal interface for rendering progress bars
//!
//! #example
//! ```rust
//! use par::Bar;
//! fn main() {
//!     let bar = Bar::new(100);
//!     for i in 1..101 {
//!         bar.add(i);
//!         std::thread::sleep_ms(10);
//!     }
//!     bar.finish_print("done")
//! }
//! ```
extern crate capsize;
extern crate termsize;

use capsize::Capacity;
use std::io::{self, Read, Write};
use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::default::Default;

static FORMAT: &'static str = "[=>_]";

/// Unit of display for progress counter
pub enum Units {
    /// No units
    None,
    /// format progress in humanized byte sizes
    Bytes
}

impl Default for Units {
    fn default() -> Units {
        Units::None
    }
}

/// Preference for reporting progress
pub enum Reporter {
    /// Report progress to stdout
    StdOut,
    /// Report progress to stderr
    StdErr,
    /// Report progress to a callback
    Callback(fn(String) -> ()),
    /// Skip reporting
    None
}

impl Default for Reporter {
    fn default() -> Reporter {
        Reporter::StdErr
    }
}

/// write progress. Implementations for Read and Write are provided
pub struct Writer<T> {
    inner: T,
    bar: Bar
}

/// read progress. Implementations for Read and Write are provided
pub struct Reader<T> {
    inner: T,
    bar: Bar
}

impl <R: Read> Reader<R> {
    pub fn new(read: R, bar: Bar) -> Reader<R> {
        Reader {
            inner: read,
            bar: bar
        }
    }
}

impl <R: Read> Read for Reader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let n = try!(self.inner.read(buf));
        self.bar.add(n);
        Ok(n)
    }
}

impl <W: Write> Writer<W> {
    pub fn new(write: W, bar: Bar) -> Writer<W> {
        Writer {
            inner: write,
            bar: bar
        }
    }
}

impl <W: Write> Write for Writer<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.bar.add(n);
        Ok(n)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

/// A bar of progress information
#[derive(Default)]
pub struct Bar {
    total: usize,
    /// show progress percent, defaults to true
    pub show_percent: bool,
    /// show progress counter. Defaults to true
    pub show_counter: bool,
    /// show main progress bar UI. Defaults to true
    pub show_bar: bool,
    /// an arbitrary string label to prefix display with
    pub prefix: String,
    /// preference for reporting progress
    pub reporter: Reporter,
    current: AtomicUsize,
    pub units: Units,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String
}

impl Bar {
    /// creates a new bar with a target total size of `total`
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            total: total,
            show_percent: true,
            show_counter: true,
            show_bar: true,
            ..Default::default()
        };
        bar.format(FORMAT);
        bar
    }

    /// sets a custom format for display
    /// Example: bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        let prev = self.current.fetch_add(delta, Ordering::Relaxed);
        self.update();
        prev
    }

    /// sets the bar count to specified value
    pub fn set(&self, value: usize) {
        self.current.store(value, Ordering::Relaxed);
        self.update()
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        if current <= self.total {
            self.render();
        }
    }

    pub fn finish_print(&self, msg: &str) {
        println!("");
        println!("{}", msg)
    }

    fn width(&self) -> usize {
        termsize::get().map(|s|s.cols as usize).unwrap_or(80)
    }

    #[inline]
    pub fn percent_completed(&self) -> f64 {
        self.current.load(Ordering::Relaxed) as f64 / (self.total as f64 / 100_f64)
    }

    #[inline]
    fn percent_completed_str(&self) -> String {
        format!(
            " {:.*} %", 2, self.percent_completed()
        )
    }

    #[inline]
    fn to_str(&self) -> String {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        fn unit(value: usize, units: &Units) -> String {
            match *units {
                Units::None => value.to_string(),
                Units::Bytes => (value as i64).capacity()
            }
        }
        let current = self.current.load(Ordering::Relaxed);
        let width = self.width();

        let mut prefix = self.prefix.clone();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = prefix + &format!(
                "{} / {} ", unit(current, &self.units), unit(self.total, &self.units)
            );
        }

        // percent complete
        if self.show_percent {
            suffix = suffix + &self.percent_completed_str();
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }
        display
    }

    fn render(&self) {
        let display = self.to_str();
        match self.reporter {
            Reporter::StdErr => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::StdOut => {
                let _ = write!(&mut std::io::stderr(), "\r{}", display);
            },
            Reporter::Callback(cb) => {
                cb(display);
            },
            Reporter::None => ()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let mut bar = Bar::new(100);
        bar.reporter = Reporter::None;
        bar.add(1);
        assert_eq!(bar.percent_completed(), 1_f64);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use std::{convert::TryFrom, path::Path};

use anyhow::{bail, format_err, Result};
use aptos::common::types::EncodingType;
use aptos_config::keys::ConfigKey;
use aptos_crypto::ed25519::Ed25519PrivateKey;
use aptos_sdk::types::chain_id::ChainId;
use clap::{ArgEnum, Parser};

use serde::{Deserialize, Serialize};
use url::Url;

const DEFAULT_API_PORT: u16 = 8080;

#[derive(Clone, Debug, Default, Deserialize, Parser, Serialize)]
pub struct MintArgs {
    /// Ed25519PrivateKey for minting coins
    #[clap(long, parse(try_from_str = ConfigKey::from_encoded_string))]
    pub mint_key: Option<ConfigKey<Ed25519PrivateKey>>,

    #[clap(long, default_value = "mint.key", conflicts_with = "mint-key")]
    pub mint_file: String,
}

impl MintArgs {
    pub fn get_mint_key(&self) -> Result<Ed25519PrivateKey> {
        let key = match &self.mint_key {
            Some(ref key) => key.private_key(),
            None => EncodingType::BCS
                .load_key::<Ed25519PrivateKey>("mint key pair", Path::new(&self.mint_file))?,
        };
        Ok(key)
    }
}

#[derive(Clone, Debug, Default, Deserialize, Parser, Serialize)]
pub struct ClusterArgs {
    /// Nodes the cluster should connect to, e.g. http://node.mysite.com:8080
    /// If the port is not provided, it is assumed to be 8080.
    #[clap(short, long, required = true, min_values = 1, parse(try_from_str = parse_target))]
    pub targets: Vec<Url>,

    /// If set, try to use public peers instead of localhost.
    #[clap(long)]
    pub vasp: bool,

    #[clap(long, default_value = "TESTING")]
    pub chain_id: ChainId,

    #[clap(flatten)]
    pub mint_args: MintArgs,
}

#[derive(Debug, Clone, Copy, ArgEnum, Deserialize, Parser, Serialize)]
pub enum TransactionType {
    P2P,
    AccountGeneration,
    NftMint,
}

impl Default for TransactionType {
    fn default() -> Self {
        TransactionType::P2P
    }
}

#[derive(Clone, Debug, Default, Deserialize, Parser, Serialize)]
pub struct EmitArgs {
    #[clap(long, default_value = "15")]
    pub accounts_per_client: usize,

    #[clap(long)]
    pub workers_per_ac: Option<usize>,

    #[clap(long, default_value = "0")]
    pub wait_millis: u64,

    #[clap(long)]
    pub burst: bool,

    /// This can only be set in conjunction with --burst. By default, when burst
    /// is enabled, we check stats once at the end of the emitter run. If you
    /// would like to opt out of that, you can use this flag.
    #[structopt(long, requires = "burst")]
    pub do_not_check_stats_at_end: bool,

    #[clap(long, default_value = "30")]
    pub txn_expiration_time_secs: u64,

    /// Time to run --emit-tx for in seconds.
    #[clap(long, default_value = "60")]
    pub duration: u64,

    #[clap(long, help = "Percentage of invalid txs", default_value = "0")]
    pub invalid_tx: usize,

    #[clap(arg_enum)]
    pub transaction_type: TransactionType,
}

fn parse_target(target: &str) -> Result<Url> {
    let mut url = Url::try_from(target).map_err(|e| {
        format_err!(
            "Failed to parse listen address, try adding a scheme, e.g. http://: {}",
            e
        )
    })?;
    if url.scheme().is_empty() {
        bail!("Scheme must not be empty, try prefixing URL with http://");
    }
    if url.port_or_known_default().is_none() {
        url.set_port(Some(DEFAULT_API_PORT)).map_err(|_| {
            anyhow::anyhow!(
                "Failed to set port to default value, make sure you have set a scheme like http://"
            )
        })?;
    }
    Ok(url)
}
<commit_msg>[txn-emitter] Add default value to TransactionType for clap parsing<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use std::{convert::TryFrom, path::Path};

use anyhow::{bail, format_err, Result};
use aptos::common::types::EncodingType;
use aptos_config::keys::ConfigKey;
use aptos_crypto::ed25519::Ed25519PrivateKey;
use aptos_sdk::types::chain_id::ChainId;
use clap::{ArgEnum, Parser};

use serde::{Deserialize, Serialize};
use url::Url;

const DEFAULT_API_PORT: u16 = 8080;

#[derive(Clone, Debug, Default, Deserialize, Parser, Serialize)]
pub struct MintArgs {
    /// Ed25519PrivateKey for minting coins
    #[clap(long, parse(try_from_str = ConfigKey::from_encoded_string))]
    pub mint_key: Option<ConfigKey<Ed25519PrivateKey>>,

    #[clap(long, default_value = "mint.key", conflicts_with = "mint-key")]
    pub mint_file: String,
}

impl MintArgs {
    pub fn get_mint_key(&self) -> Result<Ed25519PrivateKey> {
        let key = match &self.mint_key {
            Some(ref key) => key.private_key(),
            None => EncodingType::BCS
                .load_key::<Ed25519PrivateKey>("mint key pair", Path::new(&self.mint_file))?,
        };
        Ok(key)
    }
}

#[derive(Clone, Debug, Default, Deserialize, Parser, Serialize)]
pub struct ClusterArgs {
    /// Nodes the cluster should connect to, e.g. http://node.mysite.com:8080
    /// If the port is not provided, it is assumed to be 8080.
    #[clap(short, long, required = true, min_values = 1, parse(try_from_str = parse_target))]
    pub targets: Vec<Url>,

    /// If set, try to use public peers instead of localhost.
    #[clap(long)]
    pub vasp: bool,

    #[clap(long, default_value = "TESTING")]
    pub chain_id: ChainId,

    #[clap(flatten)]
    pub mint_args: MintArgs,
}

#[derive(Debug, Clone, Copy, ArgEnum, Deserialize, Parser, Serialize)]
pub enum TransactionType {
    P2P,
    AccountGeneration,
    NftMint,
}

impl Default for TransactionType {
    fn default() -> Self {
        TransactionType::P2P
    }
}

#[derive(Clone, Debug, Default, Deserialize, Parser, Serialize)]
pub struct EmitArgs {
    #[clap(long, default_value = "15")]
    pub accounts_per_client: usize,

    #[clap(long)]
    pub workers_per_ac: Option<usize>,

    #[clap(long, default_value = "0")]
    pub wait_millis: u64,

    #[clap(long)]
    pub burst: bool,

    /// This can only be set in conjunction with --burst. By default, when burst
    /// is enabled, we check stats once at the end of the emitter run. If you
    /// would like to opt out of that, you can use this flag.
    #[structopt(long, requires = "burst")]
    pub do_not_check_stats_at_end: bool,

    #[clap(long, default_value = "30")]
    pub txn_expiration_time_secs: u64,

    /// Time to run --emit-tx for in seconds.
    #[clap(long, default_value = "60")]
    pub duration: u64,

    #[clap(long, help = "Percentage of invalid txs", default_value = "0")]
    pub invalid_tx: usize,

    #[clap(long, arg_enum, default_value = "p2p", ignore_case = true)]
    pub transaction_type: TransactionType,
}

fn parse_target(target: &str) -> Result<Url> {
    let mut url = Url::try_from(target).map_err(|e| {
        format_err!(
            "Failed to parse listen address, try adding a scheme, e.g. http://: {}",
            e
        )
    })?;
    if url.scheme().is_empty() {
        bail!("Scheme must not be empty, try prefixing URL with http://");
    }
    if url.port_or_known_default().is_none() {
        url.set_port(Some(DEFAULT_API_PORT)).map_err(|_| {
            anyhow::anyhow!(
                "Failed to set port to default value, make sure you have set a scheme like http://"
            )
        })?;
    }
    Ok(url)
}
<|endoftext|>


<commit_before>#![recursion_limit = "150"]

#[macro_use]
extern crate nom;

pub use self::common::{FieldExpression, Operator, TableKey};
pub use self::column::{Column, FunctionExpression};
pub use self::condition::{ConditionBase, ConditionExpression, ConditionTree};
pub use self::create::CreateTableStatement;
pub use self::insert::InsertStatement;
pub use self::parser::*;
pub use self::select::{SelectStatement, GroupByClause, LimitClause, OrderClause, OrderType};
pub use self::table::Table;

pub mod parser;

#[macro_use]
mod caseless_tag;
mod keywords;
mod column;
mod common;
mod condition;
mod create;
mod insert;
mod select;
mod table;
<commit_msg>Publicly expose `JoinClause`<commit_after>#![recursion_limit = "150"]

#[macro_use]
extern crate nom;

pub use self::common::{FieldExpression, Operator, TableKey};
pub use self::column::{Column, FunctionExpression};
pub use self::condition::{ConditionBase, ConditionExpression, ConditionTree};
pub use self::create::CreateTableStatement;
pub use self::insert::InsertStatement;
pub use self::parser::*;
pub use self::select::{SelectStatement, GroupByClause, JoinClause, LimitClause, OrderClause,
                       OrderType};
pub use self::table::Table;

pub mod parser;

#[macro_use]
mod caseless_tag;
mod keywords;
mod column;
mod common;
mod condition;
mod create;
mod insert;
mod select;
mod table;
<|endoftext|>


<commit_before>#![crate_id = "image"]
#![crate_type = "rlib"]

#![allow(missing_doc)]
#![feature(macro_rules)]

extern crate flate;
extern crate collections;

pub use ColorType = colortype::ColorType;
pub use Grey = colortype::Grey;
pub use RGB = colortype::RGB;
pub use Palette = colortype::Palette;
pub use GreyA = colortype::GreyA;
pub use RGBA = colortype::RGBA;

pub use ImageDecoder = image::ImageDecoder;
pub use ImageError   = image::ImageError;
pub use ImageResult  = image::ImageResult;
pub use ImageFormat  = image::ImageFormat;
pub use image::{PNG, JPEG, GIF, WEBP, PPM};

pub use Image = image::Image;

pub use JPEGDecoder = jpeg::JPEGDecoder;
pub use JPEGEncoder = jpeg::JPEGEncoder;
pub use PNGDecoder  = png::PNGDecoder;
pub use PNGEncoder  = png::PNGEncoder;
pub use GIFDecoder  = gif::GIFDecoder;
pub use PPMEncoder  = ppm::PPMEncoder;
pub use WebpDecoder = webp::WebpDecoder;

pub mod vp8;
pub mod colortype;
pub mod jpeg;
pub mod png;
pub mod gif;
pub mod webp;
pub mod ppm;

mod hash;
mod image;
mod transform;
mod deflate;
mod zlib;
mod lzw;
<commit_msg>Quick fix: add mod pixel to lib.rs<commit_after>#![crate_id = "image"]
#![crate_type = "rlib"]

#![allow(missing_doc)]
#![feature(macro_rules)]

extern crate flate;
extern crate collections;

pub use ColorType = colortype::ColorType;
pub use Grey = colortype::Grey;
pub use RGB = colortype::RGB;
pub use Palette = colortype::Palette;
pub use GreyA = colortype::GreyA;
pub use RGBA = colortype::RGBA;

pub use ImageDecoder = image::ImageDecoder;
pub use ImageError   = image::ImageError;
pub use ImageResult  = image::ImageResult;
pub use ImageFormat  = image::ImageFormat;
pub use image::{PNG, JPEG, GIF, WEBP, PPM};

pub use Image = image::Image;

pub use JPEGDecoder = jpeg::JPEGDecoder;
pub use JPEGEncoder = jpeg::JPEGEncoder;
pub use PNGDecoder  = png::PNGDecoder;
pub use PNGEncoder  = png::PNGEncoder;
pub use GIFDecoder  = gif::GIFDecoder;
pub use PPMEncoder  = ppm::PPMEncoder;
pub use WebpDecoder = webp::WebpDecoder;

pub mod vp8;
pub mod colortype;
pub mod jpeg;
pub mod png;
pub mod gif;
pub mod webp;
pub mod ppm;

mod hash;
mod image;
mod transform;
mod deflate;
mod zlib;
mod lzw;
mod pixels;<|endoftext|>


<commit_before>#![feature(phase)]

extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::io::{BufferedReader, File, IoError, OtherIoError};
use std::os::{getenv, setenv, self_exe_path};

#[deriving(Show, Clone)]
pub struct ParseError {
	line: String
}

#[deriving(Show, Clone)]
pub enum DotenvError {
	Parse(ParseError),
	Io(IoError)
}

// for readability's sake
type ParsedLine = Result<Option<(String, String)>, ParseError>;
type ParsedLines = Result<Vec<(String, String)>, ParseError>;

fn parse_line(line: String) -> ParsedLine {
	let line_regex = regex!(concat!(r"^(\s*(",
		r"#.*|", // A comment, or...
		r"\s*|", // ...an empty string, or...
		r"(export\s+)?", // ...(optionally preceded by "export")...
		r"(?P<key>[A-Za-z_][A-Za-z0-9_]*)", // ...a key,...
		r"\s*=\s*", // ...then an equal sign,...
		r"(?P<value>.+?)", // ...and then its corresponding value.
	r")\s*)[\r\n]*$"));

	line_regex.captures(line.as_slice()).map_or(
		Err(ParseError{line: line.clone()}),
		|captures| {
			let key = captures.name("key");
			let value = captures.name("value");

			if key == "" || value == "" {
				// If there's no key and value, but capturing did not fail,
				// then this means we're dealing with a comment or an empty
				// string.
				Ok(None)
			} else {
				Ok(Some((key.to_string(), value.to_string())))
			}
		}
	)
}

fn parse_line_iter<T: Iterator<String>>(lines: T) -> ParsedLines {
	let parsed_lines: Vec<ParsedLine> =
			lines.map(parse_line).collect();
	let failure = parsed_lines.iter().find(|line| line.is_err());

	if failure.is_some() {
		return Err(failure.unwrap().clone().err().unwrap());
	}

	Ok(parsed_lines.iter().filter_map(|line| {
		line.clone().unwrap()
	}).collect())
}

fn lines_to_env(lines: Vec<(String, String)>) {
	for (key, value) in lines.into_iter() {
		if getenv(key.as_slice()).is_none() {
			setenv(key.as_slice(), value);
		}
	}
}

fn from_file(file: File) -> Result<(), DotenvError> {
	let mut reader = BufferedReader::new(file);
	let lines = reader.lines();

	parse_line_iter(lines.filter_map(|result| {
		result.ok()
	})).map(lines_to_env).map_err(|err| {
		DotenvError::Parse(err)
	})
}

pub fn from_path(path: &Path) -> Result<(), DotenvError> {
	match File::open(path) {
		Ok(file) => from_file(file),
		Err(err) => Err(DotenvError::Io(err))
	}
}

pub fn from_filename(filename: &str) -> Result<(), DotenvError> {
	self_exe_path().as_mut().map(|path| {
		path.push(filename);
		from_path(path)
	}).unwrap_or(Err(DotenvError::Io(IoError{
		kind: OtherIoError,
		desc: "Could not fetch the path of this executable",
		detail: None
	})))
}

pub fn dotenv() -> Result<(), DotenvError> {
	from_filename(".env")
}

#[test]
fn test_parse_line_env() {
	let input_iter = vec![
		"THIS_IS_KEY=hi this is value",
		"   many_spaces  =   wow a  maze   ",
		"export   SHELL_LOVER=1"
	].into_iter().map(|input| input.to_string());
	let actual_iter = input_iter.map(|input| parse_line(input));

	let expected_iter = vec![
		("THIS_IS_KEY", "hi this is value"),
		("many_spaces", "wow a  maze"),
		("SHELL_LOVER", "1")
	].into_iter().map(|(key, value)| (key.to_string(), value.to_string()));

	for (expected, actual) in expected_iter.zip(actual_iter) {
		assert!(actual.is_ok());
		assert!(actual.clone().ok().unwrap().is_some())
		assert_eq!(expected, actual.ok().unwrap().unwrap())
	}
}

#[test]
fn test_parse_line_comment() {
	let input_iter = vec![
		"# foo=bar",
		"    #    "
	].into_iter().map(|input| input.to_string());
	let mut actual_iter = input_iter.map(|input| parse_line(input));

	for actual in actual_iter {
		assert!(actual.is_ok());
		assert!(actual.ok().unwrap().is_none());
	}
}

#[test]
fn test_parse_line_invalid() {
	let input_iter = vec![
		"  invalid    ",
		"very bacon = yes indeed",
		"key=",
		"=value"
	].into_iter().map(|input| input.to_string());
	let mut actual_iter = input_iter.map(|input| parse_line(input));

	for actual in actual_iter {
		assert!(actual.is_err());
	}
}

#[test]
fn test_from_line_iter_valid() {
	let input = vec![
		"test_env_one=1",
		"# a comment",
		"", "\n",
		"test_env_two=2"
	].into_iter().map(|line| line.to_string());
	let actual = parse_line_iter(input);

	assert!(actual.is_ok())
}

#[test]
fn test_from_line_iter_invalid() {
	let input = vec![
		"test_env_one=1",
		"# a comment",
		"not valid"
	].into_iter().map(|line| line.to_string());
	let actual = parse_line_iter(input);

	assert!(actual.is_err())
}
<commit_msg>Remove awkward line break<commit_after>#![feature(phase)]

extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::io::{BufferedReader, File, IoError, OtherIoError};
use std::os::{getenv, setenv, self_exe_path};

#[deriving(Show, Clone)]
pub struct ParseError {
	line: String
}

#[deriving(Show, Clone)]
pub enum DotenvError {
	Parse(ParseError),
	Io(IoError)
}

// for readability's sake
type ParsedLine = Result<Option<(String, String)>, ParseError>;
type ParsedLines = Result<Vec<(String, String)>, ParseError>;

fn parse_line(line: String) -> ParsedLine {
	let line_regex = regex!(concat!(r"^(\s*(",
		r"#.*|", // A comment, or...
		r"\s*|", // ...an empty string, or...
		r"(export\s+)?", // ...(optionally preceded by "export")...
		r"(?P<key>[A-Za-z_][A-Za-z0-9_]*)", // ...a key,...
		r"\s*=\s*", // ...then an equal sign,...
		r"(?P<value>.+?)", // ...and then its corresponding value.
	r")\s*)[\r\n]*$"));

	line_regex.captures(line.as_slice()).map_or(
		Err(ParseError{line: line.clone()}),
		|captures| {
			let key = captures.name("key");
			let value = captures.name("value");

			if key == "" || value == "" {
				// If there's no key and value, but capturing did not fail,
				// then this means we're dealing with a comment or an empty
				// string.
				Ok(None)
			} else {
				Ok(Some((key.to_string(), value.to_string())))
			}
		}
	)
}

fn parse_line_iter<T: Iterator<String>>(lines: T) -> ParsedLines {
	let parsed_lines: Vec<ParsedLine> = lines.map(parse_line).collect();
	let failure = parsed_lines.iter().find(|line| line.is_err());

	if failure.is_some() {
		return Err(failure.unwrap().clone().err().unwrap());
	}

	Ok(parsed_lines.iter().filter_map(|line| {
		line.clone().unwrap()
	}).collect())
}

fn lines_to_env(lines: Vec<(String, String)>) {
	for (key, value) in lines.into_iter() {
		if getenv(key.as_slice()).is_none() {
			setenv(key.as_slice(), value);
		}
	}
}

fn from_file(file: File) -> Result<(), DotenvError> {
	let mut reader = BufferedReader::new(file);
	let lines = reader.lines();

	parse_line_iter(lines.filter_map(|result| {
		result.ok()
	})).map(lines_to_env).map_err(|err| {
		DotenvError::Parse(err)
	})
}

pub fn from_path(path: &Path) -> Result<(), DotenvError> {
	match File::open(path) {
		Ok(file) => from_file(file),
		Err(err) => Err(DotenvError::Io(err))
	}
}

pub fn from_filename(filename: &str) -> Result<(), DotenvError> {
	self_exe_path().as_mut().map(|path| {
		path.push(filename);
		from_path(path)
	}).unwrap_or(Err(DotenvError::Io(IoError{
		kind: OtherIoError,
		desc: "Could not fetch the path of this executable",
		detail: None
	})))
}

pub fn dotenv() -> Result<(), DotenvError> {
	from_filename(".env")
}

#[test]
fn test_parse_line_env() {
	let input_iter = vec![
		"THIS_IS_KEY=hi this is value",
		"   many_spaces  =   wow a  maze   ",
		"export   SHELL_LOVER=1"
	].into_iter().map(|input| input.to_string());
	let actual_iter = input_iter.map(|input| parse_line(input));

	let expected_iter = vec![
		("THIS_IS_KEY", "hi this is value"),
		("many_spaces", "wow a  maze"),
		("SHELL_LOVER", "1")
	].into_iter().map(|(key, value)| (key.to_string(), value.to_string()));

	for (expected, actual) in expected_iter.zip(actual_iter) {
		assert!(actual.is_ok());
		assert!(actual.clone().ok().unwrap().is_some())
		assert_eq!(expected, actual.ok().unwrap().unwrap())
	}
}

#[test]
fn test_parse_line_comment() {
	let input_iter = vec![
		"# foo=bar",
		"    #    "
	].into_iter().map(|input| input.to_string());
	let mut actual_iter = input_iter.map(|input| parse_line(input));

	for actual in actual_iter {
		assert!(actual.is_ok());
		assert!(actual.ok().unwrap().is_none());
	}
}

#[test]
fn test_parse_line_invalid() {
	let input_iter = vec![
		"  invalid    ",
		"very bacon = yes indeed",
		"key=",
		"=value"
	].into_iter().map(|input| input.to_string());
	let mut actual_iter = input_iter.map(|input| parse_line(input));

	for actual in actual_iter {
		assert!(actual.is_err());
	}
}

#[test]
fn test_from_line_iter_valid() {
	let input = vec![
		"test_env_one=1",
		"# a comment",
		"", "\n",
		"test_env_two=2"
	].into_iter().map(|line| line.to_string());
	let actual = parse_line_iter(input);

	assert!(actual.is_ok())
}

#[test]
fn test_from_line_iter_invalid() {
	let input = vec![
		"test_env_one=1",
		"# a comment",
		"not valid"
	].into_iter().map(|line| line.to_string());
	let actual = parse_line_iter(input);

	assert!(actual.is_err())
}
<|endoftext|>