<commit_before>use traits::*;

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum BFTokenType {
    IncrementPtr(usize),      // >
    DecrementPtr(usize),      // <
    IncrementData(usize),     // +
    DecrementData(usize),     // -
    Output,                   // .
    Input,                    // ,

    // These store their corresponding tokens
    //  aka LoopStart stores the position of
    //  the matching LoopEnd and vice versa.
    LoopStart(usize),         // [
    LoopEnd(usize),           // ]

    // Optimised instructions
    SetCurrent(i8),           // Sets the current cell to value
    AddCurrentUp(usize),      // Adds current cell to cell in [current + value]
    AddCurrentDown(usize)     // Adds current cell to cell in [current - value]
}

#[derive(Clone, Debug, Copy)]
pub struct BFToken {
    pub token_type : BFTokenType,

    // Used for matching brackets
    pub pos : usize
}

pub struct BFLexer {
}

impl Lexer<Vec<BFToken>> for BFLexer {

    fn parse(input_string:String) -> LexResult<Vec<BFToken>> {
        // Create empty vector
        let mut tokens : Vec<BFToken> = vec![];

        // Store the index of the token in the vector
        let mut pos : usize = 0;

        // This stores the positions of open brackets
        // This is used to match up bracket pairs
        //  so that they can jump to each other in O(1)
        let mut loop_stack : Vec<usize> = vec![];

        // Store the previous 5 tokens, these are used
        //  for optimisations.
        let mut last_tokens = [BFToken { pos : 0, token_type : BFTokenType::Input }; 5];

        // Loop through each character
        for character in input_string.chars() {
            // Match our character to a TokenType.
            let token_type = match character {
                '>' => {
                    // Batch up all the '>' tokens
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::IncrementPtr(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::IncrementPtr(new_x)
                },
                '<' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::DecrementPtr(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::DecrementPtr(new_x)
                },
                '+' =>  {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::IncrementData(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::IncrementData(new_x)
                },
                '-' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::DecrementData(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::DecrementData(new_x)
                },
                '.' => BFTokenType::Output,
                ',' => BFTokenType::Input,
                '[' => {
                    // Push this pos onto stack
                    loop_stack.push(pos);

                    // Store temp value of 0 for now - will be updated
                    //  once we know matching ]
                    BFTokenType::LoopStart(0)
                },
                ']' => {

                    // Get matching bracket.
                    let index = loop_stack.pop().expect("Bracket mismatch");
                    let mut ret_token : BFTokenType = BFTokenType::LoopEnd(index);

                    // Update it's data position to this ] token
                    tokens[index].token_type = BFTokenType::LoopStart(pos);

                    match last_tokens[0].token_type {
                        // This currently checks for [-] or [+] and replaces
                        //  those with a set current cell to 0 instruction.
                        BFTokenType::IncrementData(_)
                        | BFTokenType::DecrementData(_) => {
                            match last_tokens[1].token_type {
                                BFTokenType::LoopStart(_) => {
                                    ret_token = BFTokenType::SetCurrent(0);
                                    tokens.pop();
                                    tokens.pop();
                                    pos-=2;
                                },
                                _ => { }
                            }
                        },

                        //  Optimisation for [-<+>] or [->+<] pattern.
                        BFTokenType::DecrementPtr(x)
                        | BFTokenType::IncrementPtr(x) => {
                            match last_tokens[1].token_type {
                                BFTokenType::IncrementData(a) => {
                                    match last_tokens[2].token_type {
                                        BFTokenType::IncrementPtr(y)
                                        | BFTokenType::DecrementPtr(y) => {
                                             if x == y {
                                                match last_tokens[3].token_type {
                                                    BFTokenType::DecrementData(b) => {
                                                        if a == b {
                                                            match last_tokens[4].token_type {
                                                                BFTokenType::LoopStart(_) => {
                                                                    if last_tokens[0].token_type == BFTokenType::DecrementPtr(x) {
                                                                        ret_token = BFTokenType::AddCurrentUp(x);
                                                                    } else {
                                                                        ret_token = BFTokenType::AddCurrentDown(x);
                                                                    }
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    pos-=5;
                                                                },
                                                                _ => {}
                                                            }
                                                        }
                                                    },
                                                    _ => { }
                                                }
                                            }
                                        },
                                        _ => { }
                                    }
                                },
                                _ => { }
                            };
                        },

                        // Empty Loop
                        BFTokenType::LoopStart(_) => {
                            tokens.pop();
                            pos-=1;
                            continue;
                        }
                        _ => { }
                    }

                    ret_token
                },

                // BF is a very simple language - if there is an
                //  unrecognised character, it is ignored.
                _ => continue
            };

            let mut i = 1;
            // Recopy last tokens instead of shifting as they
            //  may have chagned.
            while i < 5 && pos > i-1 {
                last_tokens[i] = tokens[pos-i].clone();
                i+=1;
            }

            pos+=1;

            // Add it to the list of tokens
            let token = BFToken { token_type : token_type, pos : pos};

            last_tokens[0] = token.clone();

            tokens.push(token);
        }

        // No way for this to currently fail.
        LexResult::Success(tokens)
    }
}
<commit_msg>Tidying up whitespace.<commit_after>use traits::*;

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum BFTokenType {
    IncrementPtr(usize),      // >
    DecrementPtr(usize),      // <
    IncrementData(usize),     // +
    DecrementData(usize),     // -
    Output,                   // .
    Input,                    // ,

    // These store their corresponding tokens
    //  aka LoopStart stores the position of
    //  the matching LoopEnd and vice versa.
    LoopStart(usize),         // [
    LoopEnd(usize),           // ]

    // Optimised instructions
    SetCurrent(i8),           // Sets the current cell to value
    AddCurrentUp(usize),      // Adds current cell to cell in [current + value]
    AddCurrentDown(usize)     // Adds current cell to cell in [current - value]
}

#[derive(Clone, Debug, Copy)]
pub struct BFToken {
    pub token_type : BFTokenType,

    // Used for matching brackets
    pub pos : usize
}

pub struct BFLexer {
}

impl Lexer<Vec<BFToken>> for BFLexer {

    fn parse(input_string:String) -> LexResult<Vec<BFToken>> {
        // Create empty vector
        let mut tokens : Vec<BFToken> = vec![];

        // Store the index of the token in the vector
        let mut pos : usize = 0;

        // This stores the positions of open brackets
        // This is used to match up bracket pairs
        //  so that they can jump to each other in O(1)
        let mut loop_stack : Vec<usize> = vec![];

        // Store the previous 5 tokens, these are used
        //  for optimisations.
        let mut last_tokens = [BFToken { pos : 0, token_type : BFTokenType::Input }; 5];

        // Loop through each character
        for character in input_string.chars() {
            // Match our character to a TokenType.
            let token_type = match character {
                '>' => {
                    // Batch up all the '>' tokens
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::IncrementPtr(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::IncrementPtr(new_x)
                },
                '<' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::DecrementPtr(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::DecrementPtr(new_x)
                },
                '+' =>  {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::IncrementData(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::IncrementData(new_x)
                },
                '-' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        match last_tokens[0].token_type {
                            BFTokenType::DecrementData(x) => {
                                tokens.pop();
                                pos-=1;
                                new_x += x;
                            },
                            _ => {}
                        }
                    }
                    BFTokenType::DecrementData(new_x)
                },
                '.' => BFTokenType::Output,
                ',' => BFTokenType::Input,
                '[' => {
                    // Push this pos onto stack
                    loop_stack.push(pos);

                    // Store temp value of 0 for now - will be updated
                    //  once we know matching ]
                    BFTokenType::LoopStart(0)
                },
                ']' => {

                    // Get matching bracket.
                    let index = loop_stack.pop().expect("Bracket mismatch");
                    let mut ret_token : BFTokenType = BFTokenType::LoopEnd(index);

                    // Update it's data position to this ] token
                    tokens[index].token_type = BFTokenType::LoopStart(pos);

                    match last_tokens[0].token_type {
                        // This currently checks for [-] or [+] and replaces
                        //  those with a set current cell to 0 instruction.
                        BFTokenType::IncrementData(_)
                        | BFTokenType::DecrementData(_) => {
                            match last_tokens[1].token_type {
                                BFTokenType::LoopStart(_) => {
                                    ret_token = BFTokenType::SetCurrent(0);
                                    tokens.pop();
                                    tokens.pop();
                                    pos-=2;
                                },
                                _ => { }
                            }
                        },

                        //  Optimisation for [-<+>] or [->+<] pattern.
                        BFTokenType::DecrementPtr(x)
                        | BFTokenType::IncrementPtr(x) => {
                            match last_tokens[1].token_type {
                                BFTokenType::IncrementData(a) => {
                                    match last_tokens[2].token_type {
                                        BFTokenType::IncrementPtr(y)
                                        | BFTokenType::DecrementPtr(y) => {
                                             if x == y {
                                                match last_tokens[3].token_type {
                                                    BFTokenType::DecrementData(b) => {
                                                        if a == b {
                                                            match last_tokens[4].token_type {
                                                                BFTokenType::LoopStart(_) => {
                                                                    if last_tokens[0].token_type == BFTokenType::DecrementPtr(x) {
                                                                        ret_token = BFTokenType::AddCurrentUp(x);
                                                                    } else {
                                                                        ret_token = BFTokenType::AddCurrentDown(x);
                                                                    }
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    tokens.pop();
                                                                    pos-=5;
                                                                },
                                                                _ => {}
                                                            }
                                                        }
                                                    },
                                                    _ => { }
                                                }
                                            }
                                        },
                                        _ => { }
                                    }
                                },
                                _ => { }
                            };
                        },

                        // Empty Loop
                        BFTokenType::LoopStart(_) => {
                            tokens.pop();
                            pos-=1;
                            continue;
                        }
                        _ => { }
                    }

                    ret_token
                },

                // BF is a very simple language - if there is an
                //  unrecognised character, it is ignored.
                _ => continue
            };

            let mut i = 1;
            // Recopy last tokens instead of shifting as they
            //  may have chagned.
            while i < 5 && pos > i-1 {
                last_tokens[i] = tokens[pos-i].clone();
                i+=1;
            }

            pos+=1;

            // Add it to the list of tokens
            let token = BFToken { token_type : token_type, pos : pos};

            last_tokens[0] = token.clone();

            tokens.push(token);
        }

        // No way for this to currently fail.
        LexResult::Success(tokens)
    }
}
<|endoftext|>


<commit_before>pub mod v1 {
    pub enum Entity {
        Account,
        Application,
        Attachment,
        Card,
        Context,
        Error,
        Instance,
        Mention,
        Notification,
        Relationship,
        Report,
        Results,
        Status,
        Tag
    }

    pub enum Method {
        Accounts,
        Apps,
        Blocks,
        Favorites,
        FollowRequests,
        Follows,
        Instances,
        Media,
        Mutes,
        Notifications,
        Reports,
        Search,
        Statuses,
        Timelines
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Account {
        #[serde(rename = "id")]
        account_id: i32,
        username: String,
        acct: String,
        display_name: String,
        note: String,
        url: String,
        avatar: String,
        header: String,
        locked: bool,
        created_at: String,
        followers_count: i32,
        following_count: i32,
        statuses_count: i32
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Application {
        pub name: String,
        pub website: Option<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Attachment {
        #[serde(rename = "id")]
        pub attachment_id: i32,
        #[serde(rename = "type")]
        pub attachment_type: String,
        pub url: String,
        pub remote_url: String,
        pub preview_url: String,
        pub text_url: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Card {
        pub url: String,
        pub title: String,
        pub description: String,
        pub image: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Context {
        ancestors: Vec<Status>,
        descendants: Vec<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Error {
        pub error: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Instance {
        pub url: String,
        pub title: String,
        pub description: String,
        pub email: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Mention {
        #[serde(rename = "id")]
        pub mention_id: i32,
        pub url: String,
        pub username: String,
        pub acct: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Notification {
        #[serde( rename = "id")]
        notification_id: i32,
        #[serde( rename = "type")]
        notification_type: String,
        created_at: String,
        account: Account,
        status: Option<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Relationship {
        #[serde(rename = "id")]
        pub relationship_id: i32,
        pub following: bool,
        pub followed_by: bool,
        pub blocking: bool,
        pub muting: bool,
        pub requested: bool
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Report {
        #[serde(rename = "id")]
        pub report_id: i32,
        pub action_taken: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Results {
        accounts: Vec<Account>,
        statuses: Vec<Status>,
        hashtags: Vec<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Status {
        #[serde(rename = "id")]
        status_id: i32,
        uri: String,
        url: String,
        account: Account,
        in_reply_to_id: Option<i32>,
        in_reply_to_account_id: Option<i32>,
        reblog: Option<Box<Status>>,
        content: String,
        created_at: String,
        reblogs_count: i32,
        favourites_count: i32,
        reblogged: bool,
        favourited: bool,
        sensitive: bool,
        spoiler_text: String,
        visibility: String,
        media_attachments: Vec<Attachment>,
        mentions: Vec<Mention>,
        tags: Vec<Tag>,
        application: Application
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Tag {
        pub name: String,
        pub url: String
    }
}
<commit_msg>bump to v0.1.2; deserialized entities implemented<commit_after>pub mod v1 {
    pub enum Entity {
        Account,
        Application,
        Attachment,
        Card,
        Context,
        Error,
        Instance,
        Mention,
        Notification,
        Relationship,
        Report,
        Results,
        Status,
        Tag
    }

    pub enum Method {
        Accounts,
        Apps,
        Blocks,
        Favorites,
        FollowRequests,
        Follows,
        Instances,
        Media,
        Mutes,
        Notifications,
        Reports,
        Search,
        Statuses,
        Timelines
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Account {
        #[serde(rename = "id")]
        pub account_id: i32,
        pub username: String,
        pub acct: String,
        pub display_name: String,
        pub note: String,
        pub url: String,
        pub avatar: String,
        pub header: String,
        pub locked: bool,
        pub created_at: String,
        pub followers_count: i32,
        pub following_count: i32,
        pub statuses_count: i32
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Application {
        pub name: String,
        pub website: Option<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Attachment {
        #[serde(rename = "id")]
        pub attachment_id: i32,
        #[serde(rename = "type")]
        pub attachment_type: String,
        pub url: String,
        pub remote_url: String,
        pub preview_url: String,
        pub text_url: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Card {
        pub url: String,
        pub title: String,
        pub description: String,
        pub image: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Context {
        pub ancestors: Vec<Status>,
        pub descendants: Vec<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Error {
        pub error: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Instance {
        pub url: String,
        pub title: String,
        pub description: String,
        pub email: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Mention {
        #[serde(rename = "id")]
        pub mention_id: i32,
        pub url: String,
        pub username: String,
        pub acct: String
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Notification {
        #[serde( rename = "id")]
        pub notification_id: i32,
        #[serde( rename = "type")]
        pub notification_type: String,
        pub created_at: String,
        pub account: Account,
        pub status: Option<Status>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Relationship {
        #[serde(rename = "id")]
        pub relationship_id: i32,
        pub following: bool,
        pub followed_by: bool,
        pub blocking: bool,
        pub muting: bool,
        pub requested: bool
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Report {
        #[serde(rename = "id")]
        pub report_id: i32,
        pub action_taken: String,
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Results {
        pub accounts: Vec<Account>,
        pub statuses: Vec<Status>,
        pub hashtags: Vec<String>
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Status {
        #[serde(rename = "id")]
        pub status_id: i32,
        pub uri: String,
        pub url: String,
        pub account: Account,
        pub in_reply_to_id: Option<i32>,
        pub in_reply_to_account_id: Option<i32>,
        pub reblog: Option<Box<Status>>,
        pub content: String,
        pub created_at: String,
        pub reblogs_count: i32,
        pub favourites_count: i32,
        pub reblogged: bool,
        pub favourited: bool,
        pub sensitive: bool,
        pub spoiler_text: String,
        pub visibility: String,
        pub media_attachments: Vec<Attachment>,
        pub mentions: Vec<Mention>,
        pub tags: Vec<Tag>,
        pub application: Application
    }

    #[derive(Debug, Deserialize, PartialEq, Serialize)]
    pub struct Tag {
        pub name: String,
        pub url: String
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Error, Formatter};

#[derive(Debug, PartialEq, Eq)]
pub enum BinOp {
    Minus,
    Plus,
    Slash,
    Star,
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 100,
    Mult = 60,
    Add = 50,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Float(f64),
    Var(String),
    Undefined,
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Undefined | Exp::Float(_) | Exp::Var(_) => Precedence::Const,
        }
    }
}

impl Display for Exp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Float(f)   => write!(fmt, "{}", f),
            Exp::Var(ref v) => write!(fmt, "{}", v),
            Exp::Undefined => write!(fmt, "undefined"),
        }
    }
}

#[derive(Debug)]
pub enum Stmt {
    Assign(String, Exp),
    Decl(String, Exp),
    BareExp(Exp)
}

impl Display for Stmt {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Stmt::Assign(ref v, ref exp) => write!(fmt, "{} = {};\n", v, exp),
            Stmt::Decl(ref v, ref exp) => write!(fmt, "var {} = {};\n", v, exp),
            Stmt::BareExp(ref exp) => write!(fmt, "{};\n", exp),
        }
    }
}
<commit_msg>reorder ast enums to be alphabetical<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Debug, PartialEq, Eq)]
pub enum BinOp {
    Minus,
    Plus,
    Slash,
    Star,
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 100,
    Mult = 60,
    Add = 50,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Float(f64),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Undefined | Exp::Float(_) | Exp::Var(_) => Precedence::Const,
        }
    }
}

impl Display for Exp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Float(f)   => write!(fmt, "{}", f),
            Exp::Var(ref v) => write!(fmt, "{}", v),
            Exp::Undefined => write!(fmt, "undefined"),
        }
    }
}

#[derive(Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
}

impl Display for Stmt {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            Stmt::Assign(ref v, ref exp) => write!(fmt, "{} = {};\n", v, exp),
            Stmt::Decl(ref v, ref exp) => write!(fmt, "var {} = {};\n", v, exp),
            Stmt::BareExp(ref exp) => write!(fmt, "{};\n", exp),
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate dent;
extern crate term;
extern crate term_size;

use clap::{App, Arg};
use dent::plot;
use dent::summary::Summary;
use dent::t_test::{TTest, welch_t_test};

use std::error;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

mod fmt;
mod log;

macro_rules! ok {
    ($r: expr) => {
        match $r {
            Ok(t) => t,
            Err(e) => {
                log::error(&format!("{}", e));
                std::process::exit(1);
            }
        }
    }
}

fn print_summary(s: &Summary, outliers: bool) {
    let width = 10;
    let size_width = 6;

    if outliers {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max",
            mean = "Mean",
            std = "Std Dev",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max(), width),
            mean = fmt::f(s.mean(), width),
            std = fmt::f(s.standard_deviation(), width),
        );
    } else {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min Adj",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max Adj",
            mean = "Mean",
            std = "Std Dev",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min_adjacent(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max_adjacent(), width),
            mean = fmt::f(s.mean(), width),
            std = fmt::f(s.standard_deviation(), width),
        );
    }
}

fn print_t_test(t_test: &TTest, s1: &Summary, s2: &Summary) {
    let width = 12;

    println!("{l:>w$} = {v} ± {se}", w = width, l = "m₁ ± SE", v = s1.mean(), se = s1.standard_error());
    println!("{l:>w$} = {v} ± {se}", w = width, l = "m₂ ± SE", v = s2.mean(), se = s2.standard_error());
    println!("{l:>w$} = {v}", w = width, l = "t", v = t_test.t);
    println!("{l:>w$} = {v}", w = width, l = "p", v = t_test.p);
    println!("{l:>w$} = {v}", w = width, l = "DF", v = t_test.df);
}

fn summarize_file(path: &str, lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let f = File::open(path).or_else(|e| {
        log::error(&format!("Could not open file: {:?}", path));
        Err(e)
    })?;
    let reader = BufReader::new(f);

    let data = read_data(reader, lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn read_data<R>(reader: R, lax_parsing: bool) -> Result<Vec<f64>, Box<error::Error>>
    where R: BufRead {
    let mut data: Vec<f64> = vec![];

    for l in reader.lines() {
        let s = l?.trim().to_string();

        if s.is_empty() {
            continue;
        }

        match s.parse() {
            Ok(d) => data.push(d),
            err => if !lax_parsing { err?; }
        }
    }

    Ok(data)
}

fn summarize_stdin(lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let stdin = io::stdin();
    let data = read_data(stdin.lock(), lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn display_t_test(
    summary1: &Summary,
    summary2: &Summary,
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    let t_test = ok!(welch_t_test(&summary1, &summary2));

    if draw_plot {
        let p = ok!(plot::comparison_plot(&[summary1, summary2], width, ascii, true, outliers));
        println!("{}\n", p);
    }

    print_summary(&summary1, outliers);
    println!();
    print_summary(&summary2, outliers);
    println!();
    print_t_test(&t_test, &summary1, &summary2);
}

fn display_summaries(
    summaries: &[Summary],
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    if draw_plot {
        let summary_refs: Vec<&Summary> = summaries
            .iter()
            .collect();

        let plot = ok!(plot::comparison_plot(&summary_refs, width, ascii, true, true));
        println!("{}\n", plot);
    }

    for i in 0..summaries.len() {
        if i > 0 {
            println!();
        }
        print_summary(&summaries[i], outliers);
    }
}

fn main() {
    let matches = App::new("dent")
        .version("0.3.0")
        .author("Joe Ranweiler <joe@lemma.co>")
        .about("A tiny tool for t-tests &c.")
        .arg(Arg::with_name("stdin")
             .short("s")
             .long("stdin")
             .help("Read and summarize data from stdin"))
        .arg(Arg::with_name("files")
             .multiple(true)
             .value_name("FILES")
             .takes_value(true)
             .required_unless("stdin")
             .help("Path to one or more files of sample data"))
        .arg(Arg::with_name("lax")
             .long("lax")
             .help("Ignore non-numeric input lines"))
        .arg(Arg::with_name("plot_outliers")
             .long("outliers")
             .help("Include outliers and use min/max for outer fences of boxplot"))
        .arg(Arg::with_name("plot")
             .short("p")
             .long("plot")
             .help("Print standard boxplots"))
        .arg(Arg::with_name("ascii")
             .long("ascii")
             .help("Use only ASCII characters in boxplots"))
        .arg(Arg::with_name("width")
             .short("w")
             .long("width")
             .value_name("WIDTH")
             .takes_value(true)
             .help("Width of boxplot"))
        .get_matches();

    let ascii = matches.is_present("ascii");
    let lax_parsing = matches.is_present("lax");
    let draw_plot = matches.is_present("plot");
    let use_stdin = matches.is_present("stdin");
    let outliers = matches.is_present("plot_outliers");

    let width = matches
        .value_of("width")
        .and_then(|w| w.parse::<usize>().ok())
        .or(term_size::dimensions().map(|(w, _)| w))
        .unwrap_or(80);

    let summaries = if use_stdin {
        vec![ok!(summarize_stdin(lax_parsing))]
    } else {
        // Required if `stdin` is not present, so we can unwrap.
        matches.values_of("files")
            .unwrap_or_else(|| unreachable!())
            .map(|f| ok!(summarize_file(f, lax_parsing)))
            .collect()
    };

    match summaries.len() {
        0 => unreachable!(),
        // We want match 1 with the case `len()` > 2.
        2 => {
            display_t_test(
                &summaries[0],
                &summaries[1],
                draw_plot,
                width,
                ascii,
                outliers,
            );
        }
        _ => {
            display_summaries(
                &summaries,
                draw_plot,
                width,
                ascii,
                outliers,
            );
        },
    };
}
<commit_msg>Include difference of means with derived standard errors<commit_after>extern crate clap;
extern crate dent;
extern crate term;
extern crate term_size;

use clap::{App, Arg};
use dent::plot;
use dent::summary::Summary;
use dent::t_test::{TTest, welch_t_test};

use std::error;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

mod fmt;
mod log;

macro_rules! ok {
    ($r: expr) => {
        match $r {
            Ok(t) => t,
            Err(e) => {
                log::error(&format!("{}", e));
                std::process::exit(1);
            }
        }
    }
}

fn print_summary(s: &Summary, outliers: bool) {
    let width = 10;
    let size_width = 6;

    if outliers {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max",
            mean = "Mean",
            std = "Std Dev",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max(), width),
            mean = fmt::f(s.mean(), width),
            std = fmt::f(s.standard_deviation(), width),
        );
    } else {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min Adj",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max Adj",
            mean = "Mean",
            std = "Std Dev",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min_adjacent(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max_adjacent(), width),
            mean = fmt::f(s.mean(), width),
            std = fmt::f(s.standard_deviation(), width),
        );
    }
}

fn print_t_test(t_test: &TTest, s1: &Summary, s2: &Summary) {
    let width = 12;

    let m1 = s1.mean();
    let m2 = s2.mean();
    let se1 = s1.standard_error();
    let se2 = s1.standard_error();

    let del = m2 - m1;
    let se_del = (se1.powi(2) + se1.powi(2)).sqrt();

    println!("{l:>w$} = {v} ± {se}", w = width, l = "m₁ ± SE", v = m1, se = se1);
    println!("{l:>w$} = {v} ± {se}", w = width, l = "m₂ ± SE", v = m2, se = se2);
    println!("{l:>w$} = {v} ± {se}", w = width, l = "m₂ - m₁ ± SE", v = del, se = se_del);
    println!("{l:>w$} = {v}", w = width, l = "p", v = t_test.p);
    println!("{l:>w$} = {v}", w = width, l = "t", v = t_test.t);
    println!("{l:>w$} = {v}", w = width, l = "DF", v = t_test.df);
}

fn summarize_file(path: &str, lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let f = File::open(path).or_else(|e| {
        log::error(&format!("Could not open file: {:?}", path));
        Err(e)
    })?;
    let reader = BufReader::new(f);

    let data = read_data(reader, lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn read_data<R>(reader: R, lax_parsing: bool) -> Result<Vec<f64>, Box<error::Error>>
    where R: BufRead {
    let mut data: Vec<f64> = vec![];

    for l in reader.lines() {
        let s = l?.trim().to_string();

        if s.is_empty() {
            continue;
        }

        match s.parse() {
            Ok(d) => data.push(d),
            err => if !lax_parsing { err?; }
        }
    }

    Ok(data)
}

fn summarize_stdin(lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let stdin = io::stdin();
    let data = read_data(stdin.lock(), lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn display_t_test(
    summary1: &Summary,
    summary2: &Summary,
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    let t_test = ok!(welch_t_test(&summary1, &summary2));

    if draw_plot {
        let p = ok!(plot::comparison_plot(&[summary1, summary2], width, ascii, true, outliers));
        println!("{}\n", p);
    }

    print_summary(&summary1, outliers);
    println!();
    print_summary(&summary2, outliers);
    println!();
    print_t_test(&t_test, &summary1, &summary2);
}

fn display_summaries(
    summaries: &[Summary],
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    if draw_plot {
        let summary_refs: Vec<&Summary> = summaries
            .iter()
            .collect();

        let plot = ok!(plot::comparison_plot(&summary_refs, width, ascii, true, true));
        println!("{}\n", plot);
    }

    for i in 0..summaries.len() {
        if i > 0 {
            println!();
        }
        print_summary(&summaries[i], outliers);
    }
}

fn main() {
    let matches = App::new("dent")
        .version("0.3.0")
        .author("Joe Ranweiler <joe@lemma.co>")
        .about("A tiny tool for t-tests &c.")
        .arg(Arg::with_name("stdin")
             .short("s")
             .long("stdin")
             .help("Read and summarize data from stdin"))
        .arg(Arg::with_name("files")
             .multiple(true)
             .value_name("FILES")
             .takes_value(true)
             .required_unless("stdin")
             .help("Path to one or more files of sample data"))
        .arg(Arg::with_name("lax")
             .long("lax")
             .help("Ignore non-numeric input lines"))
        .arg(Arg::with_name("plot_outliers")
             .long("outliers")
             .help("Include outliers and use min/max for outer fences of boxplot"))
        .arg(Arg::with_name("plot")
             .short("p")
             .long("plot")
             .help("Print standard boxplots"))
        .arg(Arg::with_name("ascii")
             .long("ascii")
             .help("Use only ASCII characters in boxplots"))
        .arg(Arg::with_name("width")
             .short("w")
             .long("width")
             .value_name("WIDTH")
             .takes_value(true)
             .help("Width of boxplot"))
        .get_matches();

    let ascii = matches.is_present("ascii");
    let lax_parsing = matches.is_present("lax");
    let draw_plot = matches.is_present("plot");
    let use_stdin = matches.is_present("stdin");
    let outliers = matches.is_present("plot_outliers");

    let width = matches
        .value_of("width")
        .and_then(|w| w.parse::<usize>().ok())
        .or(term_size::dimensions().map(|(w, _)| w))
        .unwrap_or(80);

    let summaries = if use_stdin {
        vec![ok!(summarize_stdin(lax_parsing))]
    } else {
        // Required if `stdin` is not present, so we can unwrap.
        matches.values_of("files")
            .unwrap_or_else(|| unreachable!())
            .map(|f| ok!(summarize_file(f, lax_parsing)))
            .collect()
    };

    match summaries.len() {
        0 => unreachable!(),
        // We want match 1 with the case `len()` > 2.
        2 => {
            display_t_test(
                &summaries[0],
                &summaries[1],
                draw_plot,
                width,
                ascii,
                outliers,
            );
        }
        _ => {
            display_summaries(
                &summaries,
                draw_plot,
                width,
                ascii,
                outliers,
            );
        },
    };
}
<|endoftext|>


<commit_before>extern crate byteorder;
pub mod rom_loader;
pub mod memory;
pub mod cpu;

use std::env;

fn main() {
    let cpu: cpu::CpuState;
    cpu::opcode::load_from_file("resources/opcodes.csv");

    match rom_loader::load_ines("roms/nestest.nes") {
    //match load_ines(args[1]) {
      Ok(_) => (),
      Err(err) => println!("Error: {:?}", err),
    }
}

<commit_msg>removed commented out code<commit_after>extern crate byteorder;
pub mod rom_loader;
pub mod memory;
pub mod cpu;

use std::env;

fn main() {
    let cpu: cpu::CpuState;
    cpu::opcode::load_from_file("resources/opcodes.csv");

    match rom_loader::load_ines("roms/nestest.nes") {
      Ok(_) => (),
      Err(err) => println!("Error: {:?}", err),
    }
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate dent;
extern crate term;
extern crate term_size;

use clap::{App, Arg};
use dent::plot;
use dent::summary::Summary;
use dent::t_test::{TTest, welch_t_test};

use std::error;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

mod fmt;
mod log;

macro_rules! ok {
    ($r: expr) => {
        match $r {
            Ok(t) => t,
            Err(e) => {
                log::error(&format!("{}", e));
                std::process::exit(1);
            }
        }
    }
}

fn print_summary(s: &Summary, outliers: bool) {
    let width = 10;
    let size_width = 6;

    if outliers {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max",
            mean = "Mean",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max(), width),
            mean = fmt::f(s.mean(), width),
        );
    } else {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min Adj",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max Adj",
            mean = "Mean",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min_adjacent(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max_adjacent(), width),
            mean = fmt::f(s.mean(), width),
        );
    }
}

fn print_t_test(t_test: &TTest) {
    let width = 12;

    println!("{l:>w$} = {v}", w = width, l = "t", v = t_test.t);
    println!("{l:>w$} = {v}", w = width, l = "p", v = t_test.p);
    println!("{l:>w$} = {v}", w = width, l = "DF", v = t_test.df);
}

fn summarize_file(path: &str, lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let f = File::open(path).or_else(|e| {
        log::error(&format!("Could not open file: {:?}", path));
        Err(e)
    })?;
    let reader = BufReader::new(f);

    let data = read_data(reader, lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn read_data<R>(reader: R, lax_parsing: bool) -> Result<Vec<f64>, Box<error::Error>>
    where R: BufRead {
    let mut data: Vec<f64> = vec![];

    for l in reader.lines() {
        let s = l?.trim().to_string();

        if s.is_empty() {
            continue;
        }

        match s.parse() {
            Ok(d) => data.push(d),
            err => if !lax_parsing { err?; }
        }
    }

    Ok(data)
}

fn summarize_stdin(lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let stdin = io::stdin();
    let data = read_data(stdin.lock(), lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn display_t_test(
    summary1: &Summary,
    summary2: &Summary,
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    let t_test = ok!(welch_t_test(&summary1, &summary2));

    if draw_plot {
        let p = ok!(plot::comparison_plot(&[summary1, summary2], width, ascii, true, outliers));
        println!("{}\n", p);
    }

    print_summary(&summary1, outliers);
    println!();
    print_summary(&summary2, outliers);
    println!();
    print_t_test(&t_test);
}

fn display_summaries(
    summaries: &[Summary],
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    if draw_plot {
        let summary_refs: Vec<&Summary> = summaries
            .iter()
            .collect();

        let plot = ok!(plot::comparison_plot(&summary_refs, width, ascii, true, true));
        println!("{}\n", plot);
    }

    for i in 0..summaries.len() {
        if i > 0 {
            println!();
        }
        print_summary(&summaries[i], outliers);
    }
}

fn main() {
    let matches = App::new("dent")
        .version("0.3.0")
        .author("Joe Ranweiler <joe@lemma.co>")
        .about("A tiny tool for t-tests &c.")
        .arg(Arg::with_name("stdin")
             .short("s")
             .long("stdin")
             .help("Read and summarize data from stdin"))
        .arg(Arg::with_name("files")
             .multiple(true)
             .value_name("FILES")
             .takes_value(true)
             .required_unless("stdin")
             .help("Path to one or more files of sample data"))
        .arg(Arg::with_name("lax")
             .long("lax")
             .help("Ignore non-numeric input lines"))
        .arg(Arg::with_name("plot_outliers")
             .long("outliers")
             .help("Include outliers and use min/max for outer fences of boxplot"))
        .arg(Arg::with_name("plot")
             .short("p")
             .long("plot")
             .help("Print standard boxplots"))
        .arg(Arg::with_name("ascii")
             .long("ascii")
             .help("Use only ASCII characters in boxplots"))
        .arg(Arg::with_name("width")
             .short("w")
             .long("width")
             .value_name("WIDTH")
             .takes_value(true)
             .help("Width of boxplot"))
        .get_matches();

    let ascii = matches.is_present("ascii");
    let lax_parsing = matches.is_present("lax");
    let draw_plot = matches.is_present("plot");
    let use_stdin = matches.is_present("stdin");
    let outliers = matches.is_present("plot_outliers");

    let width = matches
        .value_of("width")
        .and_then(|w| w.parse::<usize>().ok())
        .or(term_size::dimensions().map(|(w, _)| w))
        .unwrap_or(80);

    let summaries = if use_stdin {
        vec![ok!(summarize_stdin(lax_parsing))]
    } else {
        // Required if `stdin` is not present, so we can unwrap.
        matches.values_of("files")
            .unwrap_or_else(|| unreachable!())
            .map(|f| ok!(summarize_file(f, lax_parsing)))
            .collect()
    };

    match summaries.len() {
        0 => unreachable!(),
        // We want match 1 with the case `len()` > 2.
        2 => {
            display_t_test(
                &summaries[0],
                &summaries[1],
                draw_plot,
                width,
                ascii,
                outliers,
            );
        }
        _ => {
            display_summaries(
                &summaries,
                draw_plot,
                width,
                ascii,
                outliers,
            );
        },
    };
}
<commit_msg>Include standard deviation in summary tables<commit_after>extern crate clap;
extern crate dent;
extern crate term;
extern crate term_size;

use clap::{App, Arg};
use dent::plot;
use dent::summary::Summary;
use dent::t_test::{TTest, welch_t_test};

use std::error;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

mod fmt;
mod log;

macro_rules! ok {
    ($r: expr) => {
        match $r {
            Ok(t) => t,
            Err(e) => {
                log::error(&format!("{}", e));
                std::process::exit(1);
            }
        }
    }
}

fn print_summary(s: &Summary, outliers: bool) {
    let width = 10;
    let size_width = 6;

    if outliers {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max",
            mean = "Mean",
            std = "Std Dev",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max(), width),
            mean = fmt::f(s.mean(), width),
            std = fmt::f(s.standard_deviation(), width),
        );
    } else {
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = "Size",
            min = "Min Adj",
            q1 = "Q1",
            med = "Median",
            q3 = "Q3",
            max = "Max Adj",
            mean = "Mean",
            std = "Std Dev",
        );
        println!(
            "{n:>nw$}  {min:>w$}  {q1:>w$}  {med:>w$}  {q3:>w$}  {max:>w$}  {mean:>w$}  {std:>w$}",
            w = width,
            nw = size_width,
            n = fmt::f(s.size(), width),
            min = fmt::f(s.min_adjacent(), width),
            q1 = fmt::f(s.lower_quartile(), width),
            med = fmt::f(s.median(), width),
            q3 = fmt::f(s.upper_quartile(), width),
            max = fmt::f(s.max_adjacent(), width),
            mean = fmt::f(s.mean(), width),
            std = fmt::f(s.standard_deviation(), width),
        );
    }
}

fn print_t_test(t_test: &TTest) {
    let width = 12;

    println!("{l:>w$} = {v}", w = width, l = "t", v = t_test.t);
    println!("{l:>w$} = {v}", w = width, l = "p", v = t_test.p);
    println!("{l:>w$} = {v}", w = width, l = "DF", v = t_test.df);
}

fn summarize_file(path: &str, lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let f = File::open(path).or_else(|e| {
        log::error(&format!("Could not open file: {:?}", path));
        Err(e)
    })?;
    let reader = BufReader::new(f);

    let data = read_data(reader, lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn read_data<R>(reader: R, lax_parsing: bool) -> Result<Vec<f64>, Box<error::Error>>
    where R: BufRead {
    let mut data: Vec<f64> = vec![];

    for l in reader.lines() {
        let s = l?.trim().to_string();

        if s.is_empty() {
            continue;
        }

        match s.parse() {
            Ok(d) => data.push(d),
            err => if !lax_parsing { err?; }
        }
    }

    Ok(data)
}

fn summarize_stdin(lax_parsing: bool) -> Result<Summary, Box<error::Error>> {
    let stdin = io::stdin();
    let data = read_data(stdin.lock(), lax_parsing)?;

    Ok(Summary::new(&data)?)
}

fn display_t_test(
    summary1: &Summary,
    summary2: &Summary,
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    let t_test = ok!(welch_t_test(&summary1, &summary2));

    if draw_plot {
        let p = ok!(plot::comparison_plot(&[summary1, summary2], width, ascii, true, outliers));
        println!("{}\n", p);
    }

    print_summary(&summary1, outliers);
    println!();
    print_summary(&summary2, outliers);
    println!();
    print_t_test(&t_test);
}

fn display_summaries(
    summaries: &[Summary],
    draw_plot: bool,
    width: usize,
    ascii: bool,
    outliers: bool,
) {
    if draw_plot {
        let summary_refs: Vec<&Summary> = summaries
            .iter()
            .collect();

        let plot = ok!(plot::comparison_plot(&summary_refs, width, ascii, true, true));
        println!("{}\n", plot);
    }

    for i in 0..summaries.len() {
        if i > 0 {
            println!();
        }
        print_summary(&summaries[i], outliers);
    }
}

fn main() {
    let matches = App::new("dent")
        .version("0.3.0")
        .author("Joe Ranweiler <joe@lemma.co>")
        .about("A tiny tool for t-tests &c.")
        .arg(Arg::with_name("stdin")
             .short("s")
             .long("stdin")
             .help("Read and summarize data from stdin"))
        .arg(Arg::with_name("files")
             .multiple(true)
             .value_name("FILES")
             .takes_value(true)
             .required_unless("stdin")
             .help("Path to one or more files of sample data"))
        .arg(Arg::with_name("lax")
             .long("lax")
             .help("Ignore non-numeric input lines"))
        .arg(Arg::with_name("plot_outliers")
             .long("outliers")
             .help("Include outliers and use min/max for outer fences of boxplot"))
        .arg(Arg::with_name("plot")
             .short("p")
             .long("plot")
             .help("Print standard boxplots"))
        .arg(Arg::with_name("ascii")
             .long("ascii")
             .help("Use only ASCII characters in boxplots"))
        .arg(Arg::with_name("width")
             .short("w")
             .long("width")
             .value_name("WIDTH")
             .takes_value(true)
             .help("Width of boxplot"))
        .get_matches();

    let ascii = matches.is_present("ascii");
    let lax_parsing = matches.is_present("lax");
    let draw_plot = matches.is_present("plot");
    let use_stdin = matches.is_present("stdin");
    let outliers = matches.is_present("plot_outliers");

    let width = matches
        .value_of("width")
        .and_then(|w| w.parse::<usize>().ok())
        .or(term_size::dimensions().map(|(w, _)| w))
        .unwrap_or(80);

    let summaries = if use_stdin {
        vec![ok!(summarize_stdin(lax_parsing))]
    } else {
        // Required if `stdin` is not present, so we can unwrap.
        matches.values_of("files")
            .unwrap_or_else(|| unreachable!())
            .map(|f| ok!(summarize_file(f, lax_parsing)))
            .collect()
    };

    match summaries.len() {
        0 => unreachable!(),
        // We want match 1 with the case `len()` > 2.
        2 => {
            display_t_test(
                &summaries[0],
                &summaries[1],
                draw_plot,
                width,
                ascii,
                outliers,
            );
        }
        _ => {
            display_summaries(
                &summaries,
                draw_plot,
                width,
                ascii,
                outliers,
            );
        },
    };
}
<|endoftext|>


<commit_before>pub struct Runner;

impl Runner {
    pub fn run(path: &str) {
        println!("Generating site in {}", path);

        let documents = Runner::parse_documents(path.to_string() + "/_posts");
    }

    fn parse_documents(document_path: &str) {
        println!("{}", document_path);
    }
}
<commit_msg>use absolute paths for all paths, create Documents from path and push them to documents vector<commit_after>use std::os;
use std::io::fs;
use std::io::File;
use std::path::Path;

use document::Document;

pub struct Runner;

impl Runner {
    pub fn run(path_string: &str) {
        let base_path = os::make_absolute(&Path::new(path_string));
        let document_path = os::make_absolute(&Path::new((path_string.to_string() + "/_posts").as_slice()));

        println!("Generating site in {}", base_path.as_str().unwrap());

        let documents = Runner::parse_documents(document_path);
    }

    fn parse_documents(document_path: Path) {
        let paths = fs::readdir(&document_path);
        let mut document_vec = vec!();

        if paths.is_ok() {
            for path in paths.unwrap().iter() {
                document_vec.push(Document::new(path));
            }
        } else {
            println!("Path {} doesn't exist", document_path.as_str().unwrap());
        }
    }
}
<|endoftext|>


<commit_before>
use std::str;

use regex::Regex;

use pos;
use ui::PrintOption;
use util::FlipResultOption;

use {
    Result,
    Error,
    ErrorType
};

#[derive(Debug)]
pub enum Cmd {
    EnterInsertMode(pos::Range),
    Quit,
    Debug(pos::Range),
    Jump(pos::Range),
    JumpNext,
    Write,
    Print(pos::Range, PrintOption),
    PrintLineNumber(pos::Range),
}

static COMMAND_RE: &'static str = r"^(?P<range>[%.,$\d]+)?(?P<cmd>[a-zA-Z?=])?$";

impl Cmd {
    fn from_char_and_range(c: char, range: pos::Range) -> Result<Cmd> {
        match c {
            'i' => Ok(Cmd::EnterInsertMode(range)),
            'q' => Ok(Cmd::Quit),
            'w' => Ok(Cmd::Write),
            'p' => Ok(Cmd::Print(range, PrintOption::Normal)),
            'n' => Ok(Cmd::Print(range, PrintOption::Numbered)),
            'l' => Ok(Cmd::Print(range, PrintOption::LineEndings)),
            '=' => Ok(Cmd::PrintLineNumber(range)),
            '?' => Ok(Cmd::Debug(range)),
            _ => Err(Error::new(ErrorType::ParseError))
        }
    }
}

struct ParsedData {
    cmd_char: Option<char>,
    range: Option<pos::Range>,
    arg: Option<String>
}

impl ParsedData {

    fn empty() -> ParsedData {
        ParsedData {
            cmd_char: None,
            range: None,
            arg: None
        }
    }

    fn new(s: &str) -> Result<ParsedData> {

        if s.len() == 0 {
            return Ok(ParsedData::empty());
        }

        let re = try!(Regex::new(COMMAND_RE));

        if let Some(captures) = re.captures(s) {

            let cmd_range = try!(captures.name("range").map(|r| r.parse::<pos::Range>()).flip());

            let cmd_char = captures.name("cmd").and_then(|c| c.chars().next());

            Ok(ParsedData {
                cmd_char: cmd_char,
                range: cmd_range,
                arg: None
            })

        } else {
            Err(Error::new(ErrorType::ParseError))
        }
    }
}

impl str::FromStr for Cmd {
    type Err = Error;

    fn from_str(s: &str) -> Result<Cmd> {

        if s.len() == 0 {
            return Ok(Cmd::JumpNext);
        }

        let re = Regex::new(COMMAND_RE).unwrap();

        if let Some(captures) = re.captures(s) {

            let cmd_range = try!(captures.name("range")
                                 .map(|r| r.parse::<pos::Range>())
                                 .unwrap_or(Ok(pos::Range::Line(pos::Pos::Current))));

            return match captures.name("cmd") {
                Some(cmd) => Cmd::from_char_and_range(cmd.chars().next().unwrap(), cmd_range),
                None => Ok(Cmd::Jump(cmd_range))
            };
        }

        Err(Error::detailed(ErrorType::ParseError, s.to_string()))
    }
}

<commit_msg>new cmd parser<commit_after>
use std::str;

use regex::Regex;

use std::convert::From;

use pos;
use ui::PrintOption;
use util::FlipResultOption;

use {
    Result,
    Error,
    ErrorType
};

#[derive(Debug)]
pub enum Cmd {
    EnterInsertMode(pos::Range),
    Quit,
    Debug(pos::Range),
    Jump(pos::Range),
    JumpNext,
    Write,
    Print(pos::Range, PrintOption),
    PrintLineNumber(pos::Range),
}

static COMMAND_RE: &'static str = r"^(?P<range>[%.,$\d]+)?(?P<cmd>[a-zA-Z?=])?$";

impl Cmd {
    fn from_parsed_data(data: ParsedData) -> Result<Cmd> {
        if data.is_empty() {
            return Ok(Cmd::JumpNext);
        }

        let range = data.range.unwrap_or_else( pos::Range::current_line );

        if let Some(c) = data.cmd_char {
            match c {
                'i' => Ok(Cmd::EnterInsertMode(range)),
                'q' => Ok(Cmd::Quit),
                'w' => Ok(Cmd::Write),
                'p' => Ok(Cmd::Print(range, PrintOption::Normal)),
                'n' => Ok(Cmd::Print(range, PrintOption::Numbered)),
                'l' => Ok(Cmd::Print(range, PrintOption::LineEndings)),
                '=' => Ok(Cmd::PrintLineNumber(range)),
                '?' => Ok(Cmd::Debug(range)),
                _ => Err(Error::new(ErrorType::ParseError))
            }

        } else {

            if data.arg != None {
                return Err(Error::new(ErrorType::ParseError))
            }

            Ok(Cmd::Jump(range))
        }
    }
}

struct ParsedData {
    cmd_char: Option<char>,
    range: Option<pos::Range>,
    arg: Option<String>
}

impl ParsedData {
    fn is_empty(&self) -> bool {
        match (&self.cmd_char, &self.range, &self.arg) {
            (&None, &None, &None) => true,
            _ => false
        }
    }

    fn empty() -> ParsedData {
        ParsedData {
            cmd_char: None,
            range: None,
            arg: None
        }
    }
}

impl str::FromStr for ParsedData {
    type Err = Error;

    fn from_str(s: &str) -> Result<ParsedData> {

        if s.len() == 0 {
            return Ok(ParsedData::empty());
        }

        let re = try!(Regex::new(COMMAND_RE));

        if let Some(captures) = re.captures(s) {

            let cmd_range = try!(captures.name("range").map(|r| r.parse::<pos::Range>()).flip());

            let cmd_char = captures.name("cmd").and_then(|c| c.chars().next());

            Ok(ParsedData {
                cmd_char: cmd_char,
                range: cmd_range,
                arg: None
            })

        } else {
            Err(Error::new(ErrorType::ParseError))
        }
    }
}

impl str::FromStr for Cmd {
    type Err = Error;

    fn from_str(s: &str) -> Result<Cmd> {

        let parsed_data = try!(s.parse::<ParsedData>());

        Cmd::from_parsed_data(parsed_data)
    }
}

<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use liquid_dsp::LiquidComplex32;

use num::complex::Complex;
use std::mem;
use std::ops::Rem;

// Rust does not support C complex numbers in the same way on 32 and 64 bit platforms:
// https://github.com/rust-lang/rfcs/issues/793
// Therefore this workaround is needed.
//
// Type `LiquidComplex32` is used here because standard `num::complex::Complex` does not have #[repr(C)].
// Function `ccexpf` is implemented in complex.c
//
// Notice that `ccexpf` does not return value, it just changes `z` value in place.
// For some reson it did not work correctly on ARM (BeagleBoneBlack) if `ccexpf` returned
// calculated `LiquidComplex32` struct. Although it worked on Mac OS X and 64/32 bit X86 Ubuntu.
extern {
    pub fn ccexpf(z: *mut LiquidComplex32);
}

use std::f32::consts::PI;

#[cfg(test)]
use std;

#[cfg(test)]
fn assert_eq_delta(a: f32, b: f32, delta: f32) {
    let relative_error = ((a - b) / b).abs();
    if relative_error >= delta {
        panic!("`(left == right)` (left: `{}`, right: `{}`)'", a, b);
    }
}

#[test]
fn test_cexpf() {
    // cargo test -- --nocapture
    // to see prints

    let mut a = Complex::<f32>::new(0.0, 0.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.0, 0.000001);
    assert_eq_delta(a.im, 0.0, 0.000001);

    let mut a = Complex::<f32>::new(1.0, 1.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.468694, 0.000001);
    assert_eq_delta(a.im, 2.2873552, 0.000001);

    let mut a = Complex::<f32>::new(70.0, 70.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1593075600000000000000000000000f32, 0.000001);
    assert_eq_delta(a.im, 1946674600000000000000000000000f32, 0.000001);

    let mut a = Complex::<f32>::new(1_000_000.0, 1_000_000.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq!(a.re, std::f32::INFINITY);
    assert_eq!(a.im, -std::f32::INFINITY);

    //println!("a={:?}", a);
}

pub fn convert_iqi16_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of i16 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 4 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(4) {
        let i: f32 = ((b[1] as i16) << 8 | b[0] as i16) as f32 / 32768.;
        let q: f32 = ((b[3] as i16) << 8 | b[2] as i16) as f32 / 32768.;

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn convert_iqf32_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of f32 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 8 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(8) {
        let i: f32 = unsafe {mem::transmute::<u32, f32>(((b[3] as u32) << 24) | ((b[2] as u32) << 16) | ((b[1] as u32) << 8) | b[0] as u32)};
        let q: f32 = unsafe {mem::transmute::<u32, f32>(((b[7] as u32) << 24) | ((b[6] as u32) << 16) | ((b[5] as u32) << 8) | b[4] as u32)};

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn shift_frequency(inbuf: &[Complex<f32>], samplenum: &mut u64, shift_hz: f64, samplerate: u32) -> Vec<Complex<f32>> {
    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len());

    for sample in inbuf {
        let mut corrector = Complex::<f32>::new(0.0, -2. * PI * (shift_hz / samplerate as f64 * (*samplenum) as f64) as f32);
        unsafe { ccexpf(mem::transmute(&mut corrector))};
        output.push(sample * corrector);

        if (shift_hz / samplerate as f64 * *samplenum as f64).fract() == 0.0 {
            *samplenum = 1;
        }
        else {
            *samplenum += 1;
        }
    }

    output
}
<commit_msg>add test_bench_shift_frequency()<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use liquid_dsp::LiquidComplex32;

use num::complex::Complex;
use std::mem;
use std::ops::Rem;

// Rust does not support C complex numbers in the same way on 32 and 64 bit platforms:
// https://github.com/rust-lang/rfcs/issues/793
// Therefore this workaround is needed.
//
// Type `LiquidComplex32` is used here because standard `num::complex::Complex` does not have #[repr(C)].
// Function `ccexpf` is implemented in complex.c
//
// Notice that `ccexpf` does not return value, it just changes `z` value in place.
// For some reson it did not work correctly on ARM (BeagleBoneBlack) if `ccexpf` returned
// calculated `LiquidComplex32` struct. Although it worked on Mac OS X and 64/32 bit X86 Ubuntu.
extern {
    pub fn ccexpf(z: *mut LiquidComplex32);
}

use std::f32::consts::PI;

#[cfg(test)]
use std;

#[cfg(test)]
fn assert_eq_delta(a: f32, b: f32, delta: f32) {
    let relative_error = ((a - b) / b).abs();
    if relative_error >= delta {
        panic!("`(left == right)` (left: `{}`, right: `{}`)'", a, b);
    }
}

#[test]
fn test_cexpf() {
    // cargo test -- --nocapture
    // to see prints

    let mut a = Complex::<f32>::new(0.0, 0.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.0, 0.000001);
    assert_eq_delta(a.im, 0.0, 0.000001);

    let mut a = Complex::<f32>::new(1.0, 1.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1.468694, 0.000001);
    assert_eq_delta(a.im, 2.2873552, 0.000001);

    let mut a = Complex::<f32>::new(70.0, 70.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq_delta(a.re, 1593075600000000000000000000000f32, 0.000001);
    assert_eq_delta(a.im, 1946674600000000000000000000000f32, 0.000001);

    let mut a = Complex::<f32>::new(1_000_000.0, 1_000_000.0);
    unsafe {ccexpf(mem::transmute(&mut a))};
    assert_eq!(a.re, std::f32::INFINITY);
    assert_eq!(a.im, -std::f32::INFINITY);

    //println!("a={:?}", a);
}

pub fn convert_iqi16_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of i16 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 4 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(4) {
        let i: f32 = ((b[1] as i16) << 8 | b[0] as i16) as f32 / 32768.;
        let q: f32 = ((b[3] as i16) << 8 | b[2] as i16) as f32 / 32768.;

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn convert_iqf32_to_complex(inbuf: &[u8]) -> Vec<Complex<f32>> {
    // inbuf consists of f32 IQ pairs that are represented as bytes here
    assert!(inbuf.len() % 8 == 0);

    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len()/8);

    for b in inbuf.chunks(8) {
        let i: f32 = unsafe {mem::transmute::<u32, f32>(((b[3] as u32) << 24) | ((b[2] as u32) << 16) | ((b[1] as u32) << 8) | b[0] as u32)};
        let q: f32 = unsafe {mem::transmute::<u32, f32>(((b[7] as u32) << 24) | ((b[6] as u32) << 16) | ((b[5] as u32) << 8) | b[4] as u32)};

        output.push(Complex::<f32>::new(i, q));
    }

    output
}

pub fn shift_frequency(inbuf: &[Complex<f32>], samplenum: &mut u64, shift_hz: f64, samplerate: u32) -> Vec<Complex<f32>> {
    let mut output = Vec::<Complex<f32>>::with_capacity(inbuf.len());

    for sample in inbuf {
        let mut corrector = Complex::<f32>::new(0.0, -2. * PI * (shift_hz / samplerate as f64 * (*samplenum) as f64) as f32);
        unsafe { ccexpf(mem::transmute(&mut corrector))};
        output.push(sample * corrector);

        if (shift_hz / samplerate as f64 * *samplenum as f64).fract() == 0.0 {
            *samplenum = 1;
        }
        else {
            *samplenum += 1;
        }
    }

    output
}

#[test]
fn test_bench_shift_frequency() {
    // use as:
    // cargo test test_bench_shift_frequency -- release

    let mut samplenr: u64 = 0;
    let shift_hz: f64 = 815000.0;
    let samplerate: u32 = 2400000;

    let input: [u8; 1_000_000] = [0xAA; 1_000_000];
    let complex_input = convert_iqf32_to_complex(&input);

    let mut iterator = 0;
    loop {
        shift_frequency(&complex_input, &mut samplenr, shift_hz, samplerate);

        iterator += 1;
        if iterator > 300 {
            break;
        }
    }
}
<|endoftext|>


<commit_before>//! Signed modulo 256-bit integer

use std::convert::{From, Into};
use std::ops::{Div, Rem};
use std::cmp::Ordering;

use super::{Sign, M256};
use super::u256::SIGN_BIT_MASK;

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
/// Represents a signed module 256-bit integer.
pub struct MI256(Sign, M256);

impl MI256 {
    /// Zero value of MI256.
    pub fn zero() -> MI256 { MI256(Sign::NoSign, M256::zero()) }
    /// One value of MI256.
    pub fn one() -> MI256 { MI256(Sign::Plus, M256::one()) }
    /// Maximum value of MI256.
    pub fn max_value() -> MI256 { MI256(Sign::Plus, M256::max_value() & SIGN_BIT_MASK.into()) }
    /// Minimum value of MI256.
    pub fn min_value() -> MI256 { MI256(Sign::Minus, (M256::max_value() & SIGN_BIT_MASK.into()) + M256::from(1u64)) }
}

impl Default for MI256 { fn default() -> MI256 { MI256::zero() } }
impl From<M256> for MI256 {
    fn from(val: M256) -> MI256 {
        if val == M256::zero() {
            MI256::zero()
        } else if val & SIGN_BIT_MASK.into() == val {
            MI256(Sign::Plus, val)
        } else {
            MI256(Sign::Minus, !val + M256::from(1u64))
        }
    }
}
impl Into<M256> for MI256 {
    fn into(self) -> M256 {
        let sign = self.0;
        if sign == Sign::NoSign {
            M256::zero()
        } else if sign == Sign::Plus {
            self.1
        } else {
            !self.1 + M256::from(1u64)
        }
    }
}

impl Ord for MI256 {
    fn cmp(&self, other: &MI256) -> Ordering {
        match (self.0, other.0) {
            (Sign::NoSign, Sign::NoSign) => Ordering::Equal,
            (Sign::NoSign, Sign::Plus) => Ordering::Less,
            (Sign::NoSign, Sign::Minus) => Ordering::Greater,
            (Sign::Minus, Sign::NoSign) => Ordering::Less,
            (Sign::Minus, Sign::Plus) => Ordering::Less,
            (Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
            (Sign::Plus, Sign::Minus) => Ordering::Greater,
            (Sign::Plus, Sign::NoSign) => Ordering::Greater,
            (Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
        }
    }
}

impl PartialOrd for MI256 {
    fn partial_cmp(&self, other: &MI256) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Div for MI256 {
    type Output = MI256;

    fn div(self, other: MI256) -> MI256 {
        println!("self: {:?}, other: {:?}", self, other);
        if other == MI256::zero() {
            return MI256::zero();
        }

        if self == MI256::min_value() && other == MI256(Sign::Minus, M256::from(1u64)) {
            return MI256::min_value();
        }

        let d = (self.1 / other.1) & SIGN_BIT_MASK.into();

        if d == M256::zero() {
            return MI256::zero();
        }

        match (self.0, other.0) {
            (Sign::Plus, Sign::Plus) |
            (Sign::Minus, Sign::Minus) => MI256(Sign::Plus, d),
            (Sign::Plus, Sign::Minus) |
            (Sign::Minus, Sign::Plus) => MI256(Sign::Minus, d),
            _ => MI256::zero()
        }
    }
}

impl Rem for MI256 {
    type Output = MI256;

    fn rem(self, other: MI256) -> MI256 {
        let r = (self.1 % other.1) & SIGN_BIT_MASK.into();

        if r == M256::zero() {
            return MI256::zero()
        }

        MI256(self.0, r)
    }
}

#[cfg(test)]
mod tests {
    use super::MI256;
    use m256::M256;
    use std::str::FromStr;

    #[test]
    pub fn sdiv() {
        assert_eq!(MI256::from(M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()) / MI256::from(M256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()), MI256::from(M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()));
    }

    #[test]
    pub fn m256() {
        let m256 = M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap();
        let mi256 = MI256::from(m256);
        let m256b: M256 = mi256.into();
        assert_eq!(m256, m256b);
    }
}
<commit_msg>Typo: remove a debug print line<commit_after>//! Signed modulo 256-bit integer

use std::convert::{From, Into};
use std::ops::{Div, Rem};
use std::cmp::Ordering;

use super::{Sign, M256};
use super::u256::SIGN_BIT_MASK;

#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
/// Represents a signed module 256-bit integer.
pub struct MI256(Sign, M256);

impl MI256 {
    /// Zero value of MI256.
    pub fn zero() -> MI256 { MI256(Sign::NoSign, M256::zero()) }
    /// One value of MI256.
    pub fn one() -> MI256 { MI256(Sign::Plus, M256::one()) }
    /// Maximum value of MI256.
    pub fn max_value() -> MI256 { MI256(Sign::Plus, M256::max_value() & SIGN_BIT_MASK.into()) }
    /// Minimum value of MI256.
    pub fn min_value() -> MI256 { MI256(Sign::Minus, (M256::max_value() & SIGN_BIT_MASK.into()) + M256::from(1u64)) }
}

impl Default for MI256 { fn default() -> MI256 { MI256::zero() } }
impl From<M256> for MI256 {
    fn from(val: M256) -> MI256 {
        if val == M256::zero() {
            MI256::zero()
        } else if val & SIGN_BIT_MASK.into() == val {
            MI256(Sign::Plus, val)
        } else {
            MI256(Sign::Minus, !val + M256::from(1u64))
        }
    }
}
impl Into<M256> for MI256 {
    fn into(self) -> M256 {
        let sign = self.0;
        if sign == Sign::NoSign {
            M256::zero()
        } else if sign == Sign::Plus {
            self.1
        } else {
            !self.1 + M256::from(1u64)
        }
    }
}

impl Ord for MI256 {
    fn cmp(&self, other: &MI256) -> Ordering {
        match (self.0, other.0) {
            (Sign::NoSign, Sign::NoSign) => Ordering::Equal,
            (Sign::NoSign, Sign::Plus) => Ordering::Less,
            (Sign::NoSign, Sign::Minus) => Ordering::Greater,
            (Sign::Minus, Sign::NoSign) => Ordering::Less,
            (Sign::Minus, Sign::Plus) => Ordering::Less,
            (Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
            (Sign::Plus, Sign::Minus) => Ordering::Greater,
            (Sign::Plus, Sign::NoSign) => Ordering::Greater,
            (Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
        }
    }
}

impl PartialOrd for MI256 {
    fn partial_cmp(&self, other: &MI256) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Div for MI256 {
    type Output = MI256;

    fn div(self, other: MI256) -> MI256 {
        if other == MI256::zero() {
            return MI256::zero();
        }

        if self == MI256::min_value() && other == MI256(Sign::Minus, M256::from(1u64)) {
            return MI256::min_value();
        }

        let d = (self.1 / other.1) & SIGN_BIT_MASK.into();

        if d == M256::zero() {
            return MI256::zero();
        }

        match (self.0, other.0) {
            (Sign::Plus, Sign::Plus) |
            (Sign::Minus, Sign::Minus) => MI256(Sign::Plus, d),
            (Sign::Plus, Sign::Minus) |
            (Sign::Minus, Sign::Plus) => MI256(Sign::Minus, d),
            _ => MI256::zero()
        }
    }
}

impl Rem for MI256 {
    type Output = MI256;

    fn rem(self, other: MI256) -> MI256 {
        let r = (self.1 % other.1) & SIGN_BIT_MASK.into();

        if r == M256::zero() {
            return MI256::zero()
        }

        MI256(self.0, r)
    }
}

#[cfg(test)]
mod tests {
    use super::MI256;
    use m256::M256;
    use std::str::FromStr;

    #[test]
    pub fn sdiv() {
        assert_eq!(MI256::from(M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()) / MI256::from(M256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()), MI256::from(M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()));
    }

    #[test]
    pub fn m256() {
        let m256 = M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap();
        let mi256 = MI256::from(m256);
        let m256b: M256 = mi256.into();
        assert_eq!(m256, m256b);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

#[macro_export]
macro_rules! cubeb_log_internal {
    ($level: expr, $msg: expr) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                cubeb_log_internal!(__INTERNAL__ $msg);
            }
        }
    };
    ($level: expr, $fmt: expr, $($arg: expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                cubeb_log_internal!(__INTERNAL__ format!($fmt, $($arg),*));
            }
        }
    };
    (__INTERNAL__ $msg: expr) => {
        if let Some(log_callback) = $crate::ffi::g_cubeb_log_callback {
            let cstr = ::std::ffi::CString::new(format!("{}:{}: {}\n", file!(), line!(), $msg)).unwrap();
            log_callback(cstr.as_ptr());
        }
    }
}

#[macro_export]
macro_rules! cubeb_logv {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Verbose, $msg));
    ($fmt: expr, $($arg: expr),+) => (cubeb_log_internal!($crate::LogLevel::Verbose, $fmt, $($arg),*));
}

#[macro_export]
macro_rules! cubeb_log {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Normal, $msg));
    ($fmt: expr, $($arg: expr),+) => (cubeb_log_internal!($crate::LogLevel::Normal, $fmt, $($arg),*));
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_normal_logging() {
        cubeb_log!("This is log at normal level");
        cubeb_log!("{} Formatted log", 1);
        cubeb_log!("{} Formatted {} log {}", 1, 2, 3);
    }

    #[test]
    fn test_verbose_logging() {
        cubeb_logv!("This is a log at verbose level");
        cubeb_logv!("{} Formatted log", 1);
        cubeb_logv!("{} Formatted {} log {}", 1, 2, 3);
    }
}
<commit_msg>Only print filename in the log<commit_after>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

#[macro_export]
macro_rules! cubeb_log_internal {
    ($level: expr, $msg: expr) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                cubeb_log_internal!(__INTERNAL__ $msg);
            }
        }
    };
    ($level: expr, $fmt: expr, $($arg: expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                cubeb_log_internal!(__INTERNAL__ format!($fmt, $($arg),*));
            }
        }
    };
    (__INTERNAL__ $msg: expr) => {
        if let Some(log_callback) = $crate::ffi::g_cubeb_log_callback {
            let filename = std::path::Path::new(file!()).file_name().unwrap().to_str().unwrap();
            let cstr = ::std::ffi::CString::new(format!("{}:{}: {}\n", filename, line!(), $msg)).unwrap();
            log_callback(cstr.as_ptr());
        }
    }
}

#[macro_export]
macro_rules! cubeb_logv {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Verbose, $msg));
    ($fmt: expr, $($arg: expr),+) => (cubeb_log_internal!($crate::LogLevel::Verbose, $fmt, $($arg),*));
}

#[macro_export]
macro_rules! cubeb_log {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Normal, $msg));
    ($fmt: expr, $($arg: expr),+) => (cubeb_log_internal!($crate::LogLevel::Normal, $fmt, $($arg),*));
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_normal_logging() {
        cubeb_log!("This is log at normal level");
        cubeb_log!("{} Formatted log", 1);
        cubeb_log!("{} Formatted {} log {}", 1, 2, 3);
    }

    #[test]
    fn test_verbose_logging() {
        cubeb_logv!("This is a log at verbose level");
        cubeb_logv!("{} Formatted log", 1);
        cubeb_logv!("{} Formatted {} log {}", 1, 2, 3);
    }
}
<|endoftext|>