<commit_before>use std::ops::FnMut;

use ansi_term::{Colour, Style};
use ansi_term::Colour::*;

pub struct LSColors<'var>(pub &'var str);

impl<'var> LSColors<'var> {
    pub fn each_pair<C>(&mut self, mut callback: C) where C: FnMut(Pair<'var>) -> () {
        for next in self.0.split(":") {
            let bits = next.split("=")
                           .take(3)
                           .collect::<Vec<_>>();

            if bits.len() == 2 && !bits[0].is_empty() && !bits[1].is_empty() {
                callback(Pair { key: bits[0], value: bits[1] });
            }
        }
    }
}

pub struct Pair<'var> {
    pub key: &'var str,
    pub value: &'var str,
}

use std::iter::Peekable;
fn parse_into_high_colour<'a, I>(iter: &mut Peekable<I>) -> Option<Colour>
where I: Iterator<Item=&'a str> {
    match iter.peek() {
        Some(&"5") => {
            let _5 = iter.next();
            if let Some(byte) = iter.next() {
                if let Ok(num) = byte.parse() {
                    return Some(Fixed(num));
                }
            }
        }
        _ => {},
    }

    None
}

impl<'var> Pair<'var> {
    pub fn to_style(&self) -> Style {
        let mut style = Style::default();
        let mut iter = self.value.split(";").peekable();

        while let Some(num) = iter.next() {
            match num {

                // Bold and italic
                "1"  => style = style.bold(),
                "4"  => style = style.underline(),

                // Foreground colours
                "30" => style = style.fg(Black),
                "31" => style = style.fg(Red),
                "32" => style = style.fg(Green),
                "33" => style = style.fg(Yellow),
                "34" => style = style.fg(Blue),
                "35" => style = style.fg(Purple),
                "36" => style = style.fg(Cyan),
                "37" => style = style.fg(White),
                "38" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.fg(c) },

                // Background colours
                "40" => style = style.on(Black),
                "41" => style = style.on(Red),
                "42" => style = style.on(Green),
                "43" => style = style.on(Yellow),
                "44" => style = style.on(Blue),
                "45" => style = style.on(Purple),
                "46" => style = style.on(Cyan),
                "47" => style = style.on(White),
                "48" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.on(c) },

                 _    => {/* ignore the error and do nothing */},
            }
        }

        style
    }
}

#[cfg(test)]
mod ansi_test {
    use super::*;
    use ansi_term::Style;

    macro_rules! test {
        ($name:ident: $input:expr => $result:expr) => {
            #[test]
            fn $name() {
                assert_eq!(Pair { key: "", value: $input }.to_style(), $result);
            }
        };
    }

    // Styles
    test!(bold:  "1"         => Style::default().bold());
    test!(under: "4"         => Style::default().underline());
    test!(both:  "1;4"       => Style::default().bold().underline());
    test!(fg:    "31"        => Red.normal());
    test!(bg:    "43"        => Style::default().on(Yellow));
    test!(bfg:   "31;43"     => Red.on(Yellow));
    test!(all:   "43;31;1;4" => Red.on(Yellow).bold().underline());
    test!(again: "1;1;1;1;1" => Style::default().bold());

    // Failure cases
    test!(empty: ""          => Style::default());
    test!(semis: ";;;;;;"    => Style::default());
    test!(nines: "99999999"  => Style::default());
    test!(word:  "GREEN"     => Style::default());

    // Higher colours
    test!(hifg:  "38;5;149"  => Fixed(149).normal());
    test!(hibg:  "48;5;1"    => Style::default().on(Fixed(1)));
    test!(hibo:  "48;5;1;1"  => Style::default().on(Fixed(1)).bold());
    test!(hiund: "4;48;5;1"  => Style::default().on(Fixed(1)).underline());

    test!(fgbg:  "38;5;121;48;5;212"  => Fixed(121).on(Fixed(212)));
    test!(bgfg:  "48;5;121;38;5;212"  => Fixed(212).on(Fixed(121)));
    test!(toohi: "48;5;999"           => Style::default());
}

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

    macro_rules! test {
        ($name:ident: $input:expr => $result:expr) => {
            #[test]
            fn $name() {
                let mut lscs = Vec::new();
                LSColors($input).each_pair(|p| lscs.push( (p.key.clone(), p.to_style()) ));
                assert_eq!(lscs, $result.to_vec());
            }
        };
    }

    // Bad parses
    test!(empty:    ""       => []);
    test!(jibber:   "blah"   => []);

    test!(equals:     "="    => []);
    test!(starts:     "=di"  => []);
    test!(ends:     "id="    => []);

    // Foreground colours
    test!(green:   "cb=32"   => [ ("cb", Green.normal()) ]);
    test!(red:     "di=31"   => [ ("di", Red.normal()) ]);
    test!(blue:    "la=34"   => [ ("la", Blue.normal()) ]);

    // Background colours
    test!(yellow:  "do=43"   => [ ("do", Style::default().on(Yellow)) ]);
    test!(purple:  "re=45"   => [ ("re", Style::default().on(Purple)) ]);
    test!(cyan:    "mi=46"   => [ ("mi", Style::default().on(Cyan)) ]);

    // Bold and underline
    test!(bold:    "fa=1"    => [ ("fa", Style::default().bold()) ]);
    test!(under:   "so=4"    => [ ("so", Style::default().underline()) ]);
    test!(both:    "la=1;4"  => [ ("la", Style::default().bold().underline()) ]);

    // More and many
    test!(more:  "me=43;21;55;34:yu=1;4;1"  => [ ("me", Blue.on(Yellow)), ("yu", Style::default().bold().underline()) ]);
    test!(many:  "red=31:green=32:blue=34"  => [ ("red", Red.normal()), ("green", Green.normal()), ("blue", Blue.normal()) ]);
}
<commit_msg>Fix LS_COLORS 01 and 04 detection<commit_after>use std::ops::FnMut;

use ansi_term::{Colour, Style};
use ansi_term::Colour::*;

pub struct LSColors<'var>(pub &'var str);

impl<'var> LSColors<'var> {
    pub fn each_pair<C>(&mut self, mut callback: C) where C: FnMut(Pair<'var>) -> () {
        for next in self.0.split(":") {
            let bits = next.split("=")
                           .take(3)
                           .collect::<Vec<_>>();

            if bits.len() == 2 && !bits[0].is_empty() && !bits[1].is_empty() {
                callback(Pair { key: bits[0], value: bits[1] });
            }
        }
    }
}

pub struct Pair<'var> {
    pub key: &'var str,
    pub value: &'var str,
}

use std::iter::Peekable;
fn parse_into_high_colour<'a, I>(iter: &mut Peekable<I>) -> Option<Colour>
where I: Iterator<Item=&'a str> {
    match iter.peek() {
        Some(&"5") => {
            let _5 = iter.next();
            if let Some(byte) = iter.next() {
                if let Ok(num) = byte.parse() {
                    return Some(Fixed(num));
                }
            }
        }
        _ => {},
    }

    None
}

impl<'var> Pair<'var> {
    pub fn to_style(&self) -> Style {
        let mut style = Style::default();
        let mut iter = self.value.split(";").peekable();

        while let Some(num) = iter.next() {
            match num {

                // Bold and italic
                "1" | "01" => style = style.bold(),
                "4" | "04" => style = style.underline(),

                // Foreground colours
                "30" => style = style.fg(Black),
                "31" => style = style.fg(Red),
                "32" => style = style.fg(Green),
                "33" => style = style.fg(Yellow),
                "34" => style = style.fg(Blue),
                "35" => style = style.fg(Purple),
                "36" => style = style.fg(Cyan),
                "37" => style = style.fg(White),
                "38" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.fg(c) },

                // Background colours
                "40" => style = style.on(Black),
                "41" => style = style.on(Red),
                "42" => style = style.on(Green),
                "43" => style = style.on(Yellow),
                "44" => style = style.on(Blue),
                "45" => style = style.on(Purple),
                "46" => style = style.on(Cyan),
                "47" => style = style.on(White),
                "48" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.on(c) },

                 _    => {/* ignore the error and do nothing */},
            }
        }

        style
    }
}

#[cfg(test)]
mod ansi_test {
    use super::*;
    use ansi_term::Style;

    macro_rules! test {
        ($name:ident: $input:expr => $result:expr) => {
            #[test]
            fn $name() {
                assert_eq!(Pair { key: "", value: $input }.to_style(), $result);
            }
        };
    }

    // Styles
    test!(bold:  "1"         => Style::default().bold());
    test!(under: "4"         => Style::default().underline());
    test!(both:  "1;4"       => Style::default().bold().underline());
    test!(fg:    "31"        => Red.normal());
    test!(bg:    "43"        => Style::default().on(Yellow));
    test!(bfg:   "31;43"     => Red.on(Yellow));
    test!(all:   "43;31;1;4" => Red.on(Yellow).bold().underline());
    test!(again: "1;1;1;1;1" => Style::default().bold());

    // Failure cases
    test!(empty: ""          => Style::default());
    test!(semis: ";;;;;;"    => Style::default());
    test!(nines: "99999999"  => Style::default());
    test!(word:  "GREEN"     => Style::default());

    // Higher colours
    test!(hifg:  "38;5;149"  => Fixed(149).normal());
    test!(hibg:  "48;5;1"    => Style::default().on(Fixed(1)));
    test!(hibo:  "48;5;1;1"  => Style::default().on(Fixed(1)).bold());
    test!(hiund: "4;48;5;1"  => Style::default().on(Fixed(1)).underline());

    test!(fgbg:  "38;5;121;48;5;212"  => Fixed(121).on(Fixed(212)));
    test!(bgfg:  "48;5;121;38;5;212"  => Fixed(212).on(Fixed(121)));
    test!(toohi: "48;5;999"           => Style::default());
}

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

    macro_rules! test {
        ($name:ident: $input:expr => $result:expr) => {
            #[test]
            fn $name() {
                let mut lscs = Vec::new();
                LSColors($input).each_pair(|p| lscs.push( (p.key.clone(), p.to_style()) ));
                assert_eq!(lscs, $result.to_vec());
            }
        };
    }

    // Bad parses
    test!(empty:    ""       => []);
    test!(jibber:   "blah"   => []);

    test!(equals:     "="    => []);
    test!(starts:     "=di"  => []);
    test!(ends:     "id="    => []);

    // Foreground colours
    test!(green:   "cb=32"   => [ ("cb", Green.normal()) ]);
    test!(red:     "di=31"   => [ ("di", Red.normal()) ]);
    test!(blue:    "la=34"   => [ ("la", Blue.normal()) ]);

    // Background colours
    test!(yellow:  "do=43"   => [ ("do", Style::default().on(Yellow)) ]);
    test!(purple:  "re=45"   => [ ("re", Style::default().on(Purple)) ]);
    test!(cyan:    "mi=46"   => [ ("mi", Style::default().on(Cyan)) ]);

    // Bold and underline
    test!(bold:    "fa=1"    => [ ("fa", Style::default().bold()) ]);
    test!(under:   "so=4"    => [ ("so", Style::default().underline()) ]);
    test!(both:    "la=1;4"  => [ ("la", Style::default().bold().underline()) ]);

    // More and many
    test!(more:  "me=43;21;55;34:yu=1;4;1"  => [ ("me", Blue.on(Yellow)), ("yu", Style::default().bold().underline()) ]);
    test!(many:  "red=31:green=32:blue=34"  => [ ("red", Red.normal()), ("green", Green.normal()), ("blue", Blue.normal()) ]);
}
<|endoftext|>


<commit_before>// Swarm Peer-to-Peer Networking
//
// Agent's should have knowledge of their neighbors/connections, this module is
// to ensure knowledge transfer through the entire swarm. This module will also
// be used to ensure the self-healing nature of the swarm's network and make sure
// that a partition does not take place. Adding an agent or removing an agent from
// the swarm is also the responsibility of this module.
//
// RPC:
//
// - HRTBT
// - HRTBT_ACK
// - JOIN
// - INFO
// - BROADCAST
use std::vec::Vec;
use byteid::ByteId;
// use agent::SwarmAgent;
// use artifact::SwarmArtifact;
// use Location;

pub enum SwarmMsg<Ag, Art, L> {
    HRTBT(Ag),
    HRTBTACK(HeartbeatAck<Ag>),
    JOIN(Ag),
    INFO(IronSwarmEvent<Ag, Art, L>),
    BROADCAST(IronSwarmEvent<Ag, Art, L>)
}

pub enum SwarmEvent<Ag, Art, L> {
    Artifact(Art),
    ArtifactGone(Art),
    AvoidLocation(L),
    Converge(L),
    MaliciousAgent(Ag)
}

pub struct HeartbeatAck<A> {
    agents: Vec<A>
}

pub struct IronSwarmEvent<Ag, Art, L> {
    from_agent: Ag,
    event: SwarmEvent<Ag, Art, L>
}
<commit_msg>Implement the enums with boxed values and explicit lifetimes.<commit_after>// Swarm Peer-to-Peer Networking
//
// Agent's should have knowledge of their neighbors/connections, this module is
// to ensure knowledge transfer through the entire swarm. This module will also
// be used to ensure the self-healing nature of the swarm's network and make sure
// that a partition does not take place. Adding an agent or removing an agent from
// the swarm is also the responsibility of this module.
//
// RPC:
//
// - HRTBT
// - HRTBT_ACK
// - JOIN
// - INFO
// - BROADCAST
use std::vec::Vec;
use byteid::ByteId;
use agent::SwarmAgent;
use artifact::SwarmArtifact;
use Location;

pub enum SwarmMsg<'a, L: Location> {
    HRTBT(Box<SwarmAgent<L>+'a>),
    HRTBTACK(HeartbeatAck<'a, L>),
    JOIN(Box<SwarmAgent<L>+'a>),
    INFO(IronSwarmEvent<'a, L>),
    BROADCAST(IronSwarmEvent<'a, L>)
}

pub enum SwarmEvent<'a, L: Location> {
    Artifact(Box<SwarmArtifact<L>+'a>),
    ArtifactGone(Box<SwarmArtifact<L>+'a>),
    AvoidLocation(Box<Location+'a>),
    Converge(Box<Location+'a>),
    MaliciousAgent(Box<SwarmAgent<L>+'a>)
}

pub struct HeartbeatAck<'a, L: Location> {
    agents: Vec<Box<SwarmAgent<L>+'a>>
}

pub struct IronSwarmEvent<'a, L: Location> {
    from_agent: Box<SwarmAgent<L>+'a>,
    event: SwarmEvent<'a, L>
}
<|endoftext|>


<commit_before>//! Tables making up a font file.

#![allow(non_camel_case_types, non_snake_case)]

macro_rules! spec {
    ($(#[$attribute:meta])* pub $structure:ident {
        $($field:ident ($($kind:tt)+) $(|$($argument:ident),+| $body:block)*,)+
    }) => (
        declare! {
            $(#[$attribute])* pub $structure {
                $($field ($($kind)+),)+
            }
        }
        implement! {
            pub $structure {
                $($field ($($kind)+) $(|$($argument),+| $body)*,)+
            }
        }
    );
}

macro_rules! declare {
    ($(#[$attribute:meta])* pub $structure:ident {
        $($field:ident ($kind:ty),)+
    }) => (itemize! {
        $(#[$attribute])*
        #[derive(Clone, Debug, Default, Eq, PartialEq)]
        pub struct $structure {
            $(pub $field: $kind,)+
        }
    });
}

macro_rules! implement {
    (pub $structure:ident {
        $($field:ident ($($kind:tt)+) $(|$($argument:ident),+| $body:block)*,)+
    }) => (
        impl ::band::Value for $structure {
            fn read<T: ::band::Band>(band: &mut T) -> ::Result<Self> {
                let mut table = $structure::default();
                $(
                    table.$field = read_field!($structure, band, table, [$($kind)+]
                                               $(|$($argument),+| $body)*);
                )+
                Ok(table)
            }
        }
    );
}

macro_rules! itemize(
    ($code:item) => ($code);
);

macro_rules! read_field(
    ($structure:ident, $band:ident, $table:ident, [$kind:ty]
                                                  |$gang:ident, $chair:ident| $body:block) => ({
        #[inline(always)]
        #[allow(unused_variables)]
        fn read<T: ::band::Band>($gang: &mut T, $chair: &$structure) -> ::Result<$kind> $body
        try!(read($band, &$table))
    });
    ($structure:ident, $band:expr, $table:expr, [$kind:ty]) => ({
        try!(::band::Value::read($band))
    });
);

macro_rules! read_vector(
    ($band:ident, $count:expr, Byte) => ({
        let count = $count as usize;
        let mut values = Vec::with_capacity(count);
        unsafe { values.set_len(count) };
        if try!(::std::io::Read::read($band, &mut values)) != count {
            return raise!("failed to read as much as needed");
        }
        Ok(values)
    });
    ($band:ident, $count:expr, Char) => ({
        let count = $count as usize;
        let mut values = Vec::with_capacity(count);
        unsafe { values.set_len(count) };
        if try!(::std::io::Read::read($band, &mut values)) != count {
            return raise!("failed to read as much as needed");
        }
        Ok(unsafe { ::std::mem::transmute(values) })
    });
    ($band:ident, $count:expr) => ({
        let count = $count as usize;
        let mut values = Vec::with_capacity(count);
        for _ in 0..count {
            values.push(try!(::band::Value::read($band)));
        }
        Ok(values)
    });
);

mod char_mapping;
mod font_header;
mod horizontal_header;
mod horizontal_metrics;
mod maximum_profile;
mod naming_table;
mod offset_table;
mod postscript;
mod windows_metrics;

pub use self::char_mapping::{CharMapping, CharMappingHeader, CharMappingRecord};
pub use self::char_mapping::{CharMappingEncoding, CharMappingEncoding4, CharMappingEncoding6};
pub use self::font_header::FontHeader;
pub use self::horizontal_header::HorizontalHeader;
pub use self::horizontal_metrics::{HorizontalMetrics, LongHorizontalMetric};
pub use self::maximum_profile::{MaximumProfile, MaximumProfile05, MaximumProfile10};
pub use self::naming_table::{NamingTable, NamingTable0, NamingTable1};
pub use self::naming_table::{NameRecord, LanguageTagRecord};
pub use self::offset_table::{OffsetTable, OffsetTableHeader, OffsetTableRecord};
pub use self::postscript::{PostScript, PostScript10, PostScript30};
pub use self::windows_metrics::{WindowsMetrics, WindowsMetrics3, WindowsMetrics5};
<commit_msg>A cosmetic change<commit_after>//! Tables making up a font file.

#![allow(non_camel_case_types, non_snake_case)]

macro_rules! spec {
    ($(#[$attribute:meta])* pub $structure:ident {
        $($field:ident ($($kind:tt)+) $(|$($argument:ident),+| $body:block)*,)+
    }) => (
        declare! {
            $(#[$attribute])* pub $structure {
                $($field ($($kind)+),)+
            }
        }
        implement! {
            pub $structure {
                $($field ($($kind)+) $(|$($argument),+| $body)*,)+
            }
        }
    );
}

macro_rules! declare {
    ($(#[$attribute:meta])* pub $structure:ident {
        $($field:ident ($kind:ty),)+
    }) => (itemize! {
        $(#[$attribute])*
        #[derive(Clone, Debug, Default, Eq, PartialEq)]
        pub struct $structure {
            $(pub $field: $kind,)+
        }
    });
}

macro_rules! implement {
    (pub $structure:ident {
        $($field:ident ($($kind:tt)+) $(|$($argument:ident),+| $body:block)*,)+
    }) => (
        impl ::band::Value for $structure {
            fn read<T: ::band::Band>(band: &mut T) -> ::Result<Self> {
                let mut table = $structure::default();
                $(
                    table.$field = read_field!($structure, band, table, [$($kind)+]
                                               $(|$($argument),+| $body)*);
                )+
                Ok(table)
            }
        }
    );
}

macro_rules! itemize(
    ($code:item) => ($code);
);

macro_rules! read_field(
    ($structure:ident, $band:ident, $table:ident, [$kind:ty]
                                                  |$gang:ident, $chair:ident| $body:block) => ({
        #[inline(always)]
        #[allow(unused_variables)]
        fn read<T: ::band::Band>($gang: &mut T, $chair: &$structure) -> ::Result<$kind> $body
        try!(read($band, &$table))
    });
    ($structure:ident, $band:expr, $table:expr, [$kind:ty]) => ({
        try!(::band::Value::read($band))
    });
);

macro_rules! read_vector(
    ($band:ident, $count:expr, Byte) => (unsafe {
        let count = $count as usize;
        let mut values = Vec::with_capacity(count);
        values.set_len(count);
        if try!(::std::io::Read::read($band, &mut values)) != count {
            return raise!("failed to read as much as needed");
        }
        Ok(values)
    });
    ($band:ident, $count:expr, Char) => (unsafe {
        let count = $count as usize;
        let mut values = Vec::with_capacity(count);
        values.set_len(count);
        if try!(::std::io::Read::read($band, &mut values)) != count {
            return raise!("failed to read as much as needed");
        }
        Ok(::std::mem::transmute(values))
    });
    ($band:ident, $count:expr) => ({
        let count = $count as usize;
        let mut values = Vec::with_capacity(count);
        for _ in 0..count {
            values.push(try!(::band::Value::read($band)));
        }
        Ok(values)
    });
);

mod char_mapping;
mod font_header;
mod horizontal_header;
mod horizontal_metrics;
mod maximum_profile;
mod naming_table;
mod offset_table;
mod postscript;
mod windows_metrics;

pub use self::char_mapping::{CharMapping, CharMappingHeader, CharMappingRecord};
pub use self::char_mapping::{CharMappingEncoding, CharMappingEncoding4, CharMappingEncoding6};
pub use self::font_header::FontHeader;
pub use self::horizontal_header::HorizontalHeader;
pub use self::horizontal_metrics::{HorizontalMetrics, LongHorizontalMetric};
pub use self::maximum_profile::{MaximumProfile, MaximumProfile05, MaximumProfile10};
pub use self::naming_table::{NamingTable, NamingTable0, NamingTable1};
pub use self::naming_table::{NameRecord, LanguageTagRecord};
pub use self::offset_table::{OffsetTable, OffsetTableHeader, OffsetTableRecord};
pub use self::postscript::{PostScript, PostScript10, PostScript30};
pub use self::windows_metrics::{WindowsMetrics, WindowsMetrics3, WindowsMetrics5};
<|endoftext|>


<commit_before>mod hash_screen;
mod test_io;

use std::collections::HashMap;
use std::path::Path;

#[test]
fn verify_completes_nestest() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let mut commands: HashMap<u32, &'static str> = HashMap::new();

    //Run the main tests
    commands.insert(10, "....T...|........");
    hashes.insert(35, "2bfe5ffe2fae65fa730c04735a3b25115c5fb65e");

    //Switch to the unofficial opcode tests and run them
    commands.insert(40, ".....S..|........");
    commands.insert(45, "....T...|........");
    hashes.insert(65, "0b6895e6ff0e8be76e805a067be6ebec89e7d6ad");

    run_system_test(70,
                    Path::new("nes-test-roms/other/nestest.nes"),
                    hashes,
                    commands);
}

fn run_system_test(frames: u32,
                   file_name: &Path,
                   hashes: HashMap<u32, &'static str>,
                   commands: HashMap<u32, &'static str>) {

    let cart = ::cart::Cart::read(file_name).expect("Failed to read ROM File");
    let mut builder = ::EmulatorBuilder::new(cart);
    builder.io = Box::new(test_io::TestIO::new(commands));
    builder.screen = Box::new(hash_screen::HashVerifier::new(hashes));
    builder.screen = Box::new(hash_screen::HashPrinter::new(builder.screen));

    let mut emulator = builder.build();

    for _ in 0..frames {
        assert!(!emulator.halted());
        emulator.run_frame();
    }
}
<commit_msg>Add more test cases using the test roms that currently work.<commit_after>mod hash_screen;
mod test_io;

use std::collections::HashMap;
use std::path::Path;

#[test]
fn verify_completes_nestest() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let mut commands: HashMap<u32, &'static str> = HashMap::new();

    //Run the main tests
    commands.insert(10, "....T...|........");
    hashes.insert(35, "2bfe5ffe2fae65fa730c04735a3b25115c5fb65e");

    //Switch to the unofficial opcode tests and run them
    commands.insert(40, ".....S..|........");
    commands.insert(45, "....T...|........");
    hashes.insert(65, "0b6895e6ff0e8be76e805a067be6ebec89e7d6ad");

    run_system_test(70,
                    Path::new("nes-test-roms/other/nestest.nes"),
                    hashes,
                    commands);
}

#[test]
fn blargg_apu_test_len_ctr() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(18, "ea9ac1696a5cec416f0a9f34c052815ca59850d5");

    run_system_test(19,
                    Path::new("nes-test-roms/apu_test/rom_singles/1-len_ctr.nes"),
                    hashes,
                    commands);
}

#[test]
fn blargg_apu_test_len_table() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(13, "90a61bd003c5794713aa5f207b9b70c8862d892b");

    run_system_test(14,
                    Path::new("nes-test-roms/apu_test/rom_singles/2-len_table.nes"),
                    hashes,
                    commands);
}

#[test]
fn blargg_apu_test_irq_flag() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(18, "09e4ad012c8fddfd8e3b4cc6d1b395c5062768c2");

    run_system_test(19,
                    Path::new("nes-test-roms/apu_test/rom_singles/3-irq_flag.nes"),
                    hashes,
                    commands);
}

#[test]
fn blargg_ppu_test_palette_ram() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(18, "cb15f68f631c1d409beefb775bcff990286096fb");

    run_system_test(19,
                    Path::new("nes-test-roms/blargg_ppu_tests_2005.09.15b/palette_ram.nes"),
                    hashes,
                    commands);
}

#[test]
fn blargg_ppu_test_sprite_ram() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(18, "cb15f68f631c1d409beefb775bcff990286096fb");

    run_system_test(19,
                    Path::new("nes-test-roms/blargg_ppu_tests_2005.09.15b/sprite_ram.nes"),
                    hashes,
                    commands);
}

#[test]
fn blargg_ppu_test_vram_access() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(18, "cb15f68f631c1d409beefb775bcff990286096fb");

    run_system_test(19,
                    Path::new("nes-test-roms/blargg_ppu_tests_2005.09.15b/vram_access.nes"),
                    hashes,
                    commands);
}

#[test]
fn oam_read() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(27, "cc2447362cceb400803a18c2e4b5d5d4e4aa2ea7");

    run_system_test(28,
                    Path::new("nes-test-roms/oam_read/oam_read.nes"),
                    hashes,
                    commands);
}

#[test]
fn sprite_hit_basics() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(33, "1437c48bb22dd3be0d37449171d2120e13877326");

    run_system_test(33,
                    Path::new("nes-test-roms/sprite_hit_tests_2005.10.05/01.basics.nes"),
                    hashes,
                    commands);
}

#[test]
fn sprite_hit_alignment() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(31, "33815f5682dda683d1a9fe7495f6358c0e741a9d");

    run_system_test(32,
                    Path::new("nes-test-roms/sprite_hit_tests_2005.10.05/02.alignment.nes"),
                    hashes,
                    commands);
}

#[test]
fn sprite_hit_corners() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(21, "760203cab0bc4df16bda48438f67a91e8a152fb9");

    run_system_test(22,
                    Path::new("nes-test-roms/sprite_hit_tests_2005.10.05/03.corners.nes"),
                    hashes,
                    commands);
}

#[test]
fn sprite_hit_flip() {
    let mut hashes: HashMap<u32, &'static str> = HashMap::new();
    let commands: HashMap<u32, &'static str> = HashMap::new();

    hashes.insert(21, "e16e43e5efdeacfd999a8ea031fa5058ec202f96");

    run_system_test(22,
                    Path::new("nes-test-roms/sprite_hit_tests_2005.10.05/04.flip.nes"),
                    hashes,
                    commands);
}

fn run_system_test(frames: u32,
                   file_name: &Path,
                   hashes: HashMap<u32, &'static str>,
                   commands: HashMap<u32, &'static str>) {

    let cart = ::cart::Cart::read(file_name).expect("Failed to read ROM File");
    let mut builder = ::EmulatorBuilder::new(cart);
    builder.io = Box::new(test_io::TestIO::new(commands));
    builder.screen = Box::new(hash_screen::HashVerifier::new(hashes));
    builder.screen = Box::new(hash_screen::HashPrinter::new(builder.screen));

    let mut emulator = builder.build();

    for _ in 0..frames {
        assert!(!emulator.halted());
        emulator.run_frame();
    }
}
<|endoftext|>


<commit_before>
use vertex::{Vertex, VertexProxy};
use edge::{Edge, EdgeProxy};
// define a traversal as a series of stages

struct VertexVisit {
    vertex: VertexProxy
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

pub enum GraphIterable {
    Vertex(VertexProxy),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

struct Path {
    path: Vec<GraphIterable>
}

impl Path {
    fn new(vertex: VertexProxy) -> Path {
		Path{path:vec![GraphIterable::Vertex(vertex)]}
    }
}

pub struct GraphQuery {
	// many paths
    paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<VertexProxy>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    fn map(closure: &Fn(Path) -> Vec<Path>) -> GraphQuery  {
        GraphQuery{paths:Vec::new()}
    }

    pub fn outV(&self) -> GraphQuery {
        let g = GraphQuery::empty();

		let f = |path: Path| {
			let mut result : Vec<Path>  = Vec::new();
			result
		};
//		let g = self.map()
        g
    }

	pub fn inv(&self) -> GraphQuery {
		let g = GraphQuery::empty();
		g
	}
}

<commit_msg>fixed signiture of map<commit_after>
use vertex::{Vertex, VertexProxy};
use edge::{Edge, EdgeProxy};
// define a traversal as a series of stages

struct VertexVisit {
    vertex: VertexProxy
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

pub enum GraphIterable {
    Vertex(VertexProxy),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

struct Path {
    path: Vec<GraphIterable>
}

impl Path {
    fn new(vertex: VertexProxy) -> Path {
		Path{path:vec![GraphIterable::Vertex(vertex)]}
    }
}

pub struct GraphQuery {
	// many paths
    paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<VertexProxy>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    fn map<F: Fn(Path) -> Vec<Path>>(&self, closure: F) -> GraphQuery  {
        GraphQuery::empty()
    }

    pub fn outV(&self) -> GraphQuery {
//        let g = GraphQuery::empty();

		let f = |path: Path| {
			let mut result : Vec<Path>  = Vec::new();
			result
		};
		self.map(f)
    }

	pub fn inv(&self) -> GraphQuery {
		let g = GraphQuery::empty();
		g
	}
}

<|endoftext|>


<commit_before>//! The types modules describes all the structures to express FITS files.

use std::str::FromStr;

#[derive(Debug, PartialEq)]
/// The primary header of a FITS file.
pub struct PrimaryHeader {
    /// The keyword records of the primary header.
    pub keyword_records: Vec<KeywordRecord>,
}

impl PrimaryHeader {
    /// Create a PrimaryHeader with a given set of keyword_records
    pub fn new(keyword_records: Vec<KeywordRecord>) -> PrimaryHeader {
        PrimaryHeader { keyword_records: keyword_records }
    }
}

#[derive(Debug, PartialEq)]
/// A keyword record contains information about a FITS header.
pub struct KeywordRecord {
    /// The keyword of this record.
    keyword: Keyword,
}

impl KeywordRecord {
    /// Create a `KeywordRecord` from a specific `Keyword`.
    pub fn new(keyword: Keyword) -> KeywordRecord {
        KeywordRecord { keyword : keyword }
    }
}

#[derive(Debug, PartialEq)]
/// A unit tuple that will act as a placeholder for blank records.
pub struct BlankRecord;

#[derive(Debug, PartialEq)]
#[allow(non_camel_case_types, missing_docs)]
/// The various keywords that can be found in headers.
pub enum Keyword {
    SIMPLE,
    BITPIX,
    NAXIS,
    NAXISn(u8),
    EXTEND,
    NEXTEND,
    EXTNAME,
    EXTVER,
    ORIGIN,
    DATE,
    CREATOR,
    PROCVER,
    FILEVER,
    TIMVERSN,
    TELESCOP,
    INSTRUME,
    OBJECT,
    KEPLERID,
    CHANNEL,
    MODULE,
    OUTPUT,
    CAMPAIGN,
    DATA_REL,
    OBSMODE,
    MISSION,
    TTABLEID,
    RADESYS,
    RA_OBJ,
    DEC_OBJ,
    EQUINOX,
    PMRA,
    PMDEC,
    PMTOTAL,
    PARALLAX,
    GLON,
    GLAT,
    GMAG,
    RMAG,
    IMAG,
    ZMAG,
    JMAG,
    HMAG,
    KMAG,
    KEPMAG,
    GRCOLOR,
    JKCOLOR,
    GKCOLOR,
    TEFF,
    LOGG,
    FEH,
    EBMINUSV,
    AV,
    RADIUS,
    TMINDEX,
    CHECKSUM,
    DATASUM,
    END,
}

/// Problems that could occur when parsing a `str` are enumerated here.
#[derive(Debug)]
pub enum ParseKeywordError {
    /// When a str can not be recognized as a keyword, this error will be returned
    UnknownKeyword
}

impl FromStr for Keyword {
    type Err = ParseKeywordError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // TODO parse NAXIS1 correctly
        match s.trim_right() {
            "SIMPLE" => Ok(Keyword::SIMPLE),
            "BITPIX" => Ok(Keyword::BITPIX),
            "NAXIS" => Ok(Keyword::NAXIS),
            "EXTEND" => Ok(Keyword::EXTEND),
            "NEXTEND" => Ok(Keyword::NEXTEND),
            "EXTNAME" => Ok(Keyword::EXTNAME),
            "EXTVER" => Ok(Keyword::EXTVER),
            "ORIGIN" => Ok(Keyword::ORIGIN),
            "DATE" => Ok(Keyword::DATE),
            "CREATOR" => Ok(Keyword::CREATOR),
            "PROCVER" => Ok(Keyword::PROCVER),
            "FILEVER" => Ok(Keyword::FILEVER),
            "TIMVERSN" => Ok(Keyword::TIMVERSN),
            "TELESCOP" => Ok(Keyword::TELESCOP),
            "INSTRUME" => Ok(Keyword::INSTRUME),
            "OBJECT" => Ok(Keyword::OBJECT),
            "KEPLERID" => Ok(Keyword::KEPLERID),
            "CHANNEL" => Ok(Keyword::CHANNEL),
            "MODULE" => Ok(Keyword::MODULE),
            "OUTPUT" => Ok(Keyword::OUTPUT),
            "CAMPAIGN" => Ok(Keyword::CAMPAIGN),
            "DATA_REL" => Ok(Keyword::DATA_REL),
            "OBSMODE" => Ok(Keyword::OBSMODE),
            "MISSION" => Ok(Keyword::MISSION),
            "TTABLEID" => Ok(Keyword::TTABLEID),
            "RADESYS" => Ok(Keyword::RADESYS),
            "RA_OBJ" => Ok(Keyword::RA_OBJ),
            "DEC_OBJ" => Ok(Keyword::DEC_OBJ),
            "EQUINOX" => Ok(Keyword::EQUINOX),
            "PMRA" => Ok(Keyword::PMRA),
            "PMDEC" => Ok(Keyword::PMDEC),
            "PMTOTAL" => Ok(Keyword::PMTOTAL),
            "PARALLAX" => Ok(Keyword::PARALLAX),
            "GLON" => Ok(Keyword::GLON),
            "GLAT" => Ok(Keyword::GLAT),
            "GMAG" => Ok(Keyword::GMAG),
            "RMAG" => Ok(Keyword::RMAG),
            "IMAG" => Ok(Keyword::IMAG),
            "ZMAG" => Ok(Keyword::ZMAG),
            "JMAG" => Ok(Keyword::JMAG),
            "HMAG" => Ok(Keyword::HMAG),
            "KMAG" => Ok(Keyword::KMAG),
            "KEPMAG" => Ok(Keyword::KEPMAG),
            "GRCOLOR" => Ok(Keyword::GRCOLOR),
            "JKCOLOR" => Ok(Keyword::JKCOLOR),
            "GKCOLOR" => Ok(Keyword::GKCOLOR),
            "TEFF" => Ok(Keyword::TEFF),
            "LOGG" => Ok(Keyword::LOGG),
            "FEH" => Ok(Keyword::FEH),
            "EBMINUSV" => Ok(Keyword::EBMINUSV),
            "AV" => Ok(Keyword::AV),
            "RADIUS" => Ok(Keyword::RADIUS),
            "TMINDEX" => Ok(Keyword::TMINDEX),
            "CHECKSUM" => Ok(Keyword::CHECKSUM),
            "DATASUM" => Ok(Keyword::DATASUM),
            "END" => Ok(Keyword::END),
            _ => Err(ParseKeywordError::UnknownKeyword)
        }
    }
}

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

    fn primary_header_constructed_from_the_new_function_shoul_eq_hand_construction() {
        assert_eq!(
            PrimaryHeader { keyword_records: vec!(
                KeywordRecord::new(Keyword::SIMPLE),
                KeywordRecord::new(Keyword::NEXTEND),
            )},
            PrimaryHeader::new(vec!(
                KeywordRecord::new(Keyword::SIMPLE),
                KeywordRecord::new(Keyword::NEXTEND),
            ))
        );
    }

    #[test]
    fn keyword_record_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            KeywordRecord { keyword: Keyword::ORIGIN },
            KeywordRecord::new(Keyword::ORIGIN));
    }

    #[test]
    fn keywords_could_be_constructed_from_str() {
        let data = vec!(
            ("SIMPLE", Keyword::SIMPLE),
            ("BITPIX", Keyword::BITPIX),
            ("NAXIS", Keyword::NAXIS),
            ("EXTEND", Keyword::EXTEND),
            ("NEXTEND", Keyword::NEXTEND),
            ("EXTVER", Keyword::EXTVER),
            ("ORIGIN", Keyword::ORIGIN),
            ("DATE", Keyword::DATE),
            ("CREATOR", Keyword::CREATOR),
            ("PROCVER", Keyword::PROCVER),
            ("FILEVER", Keyword::FILEVER),
            ("TIMVERSN", Keyword::TIMVERSN),
            ("TELESCOP", Keyword::TELESCOP),
            ("INSTRUME", Keyword::INSTRUME),
            ("OBJECT", Keyword::OBJECT),
            ("KEPLERID", Keyword::KEPLERID),
            ("CHANNEL", Keyword::CHANNEL),
            ("MODULE", Keyword::MODULE),
            ("OUTPUT", Keyword::OUTPUT),
            ("CAMPAIGN", Keyword::CAMPAIGN),
            ("DATA_REL", Keyword::DATA_REL),
            ("OBSMODE", Keyword::OBSMODE),
            ("MISSION", Keyword::MISSION),
            ("TTABLEID", Keyword::TTABLEID),
            ("RADESYS", Keyword::RADESYS),
            ("RA_OBJ", Keyword::RA_OBJ),
            ("DEC_OBJ", Keyword::DEC_OBJ),
            ("EQUINOX", Keyword::EQUINOX),
            ("PMRA", Keyword::PMRA),
            ("PMDEC", Keyword::PMDEC),
            ("PMTOTAL", Keyword::PMTOTAL),
            ("PARALLAX", Keyword::PARALLAX),
            ("GLON", Keyword::GLON),
            ("GLAT", Keyword::GLAT),
            ("GMAG", Keyword::GMAG),
            ("RMAG", Keyword::RMAG),
            ("IMAG", Keyword::IMAG),
            ("ZMAG", Keyword::ZMAG),
            ("JMAG", Keyword::JMAG),
            ("HMAG", Keyword::HMAG),
            ("KMAG", Keyword::KMAG),
            ("KEPMAG", Keyword::KEPMAG),
            ("GRCOLOR", Keyword::GRCOLOR),
            ("JKCOLOR", Keyword::JKCOLOR),
            ("GKCOLOR", Keyword::GKCOLOR),
            ("TEFF", Keyword::TEFF),
            ("LOGG", Keyword::LOGG),
            ("FEH", Keyword::FEH),
            ("EBMINUSV", Keyword::EBMINUSV),
            ("AV", Keyword::AV),
            ("RADIUS", Keyword::RADIUS),
            ("TMINDEX", Keyword::TMINDEX),
            ("CHECKSUM", Keyword::CHECKSUM),
            ("DATASUM", Keyword::DATASUM),
            ("END", Keyword::END),
        );

        for (input, expected) in data {
            assert_eq!(Keyword::from_str(input).unwrap(), expected);
        }
    }

    #[test]
    fn should_also_parse_whitespace_keywords() {
        assert_eq!(Keyword::from_str("SIMPLE  ").unwrap(), Keyword::SIMPLE);
    }
}
<commit_msg>Create a Fits structure<commit_after>//! The types modules describes all the structures to express FITS files.

use std::str::FromStr;

#[derive(Debug, PartialEq)]
/// Representation of a FITS file.
pub struct Fits {
    /// The primary header
    pub primary_header: PrimaryHeader
}

impl Fits {
    /// Create a Fits structure with a given primary header
    pub fn new(primary_header: PrimaryHeader) -> Fits {
        Fits { primary_header: primary_header }
    }
}

#[derive(Debug, PartialEq)]
/// The primary header of a FITS file.
pub struct PrimaryHeader {
    /// The keyword records of the primary header.
    pub keyword_records: Vec<KeywordRecord>,
}

impl PrimaryHeader {
    /// Create a PrimaryHeader with a given set of keyword_records
    pub fn new(keyword_records: Vec<KeywordRecord>) -> PrimaryHeader {
        PrimaryHeader { keyword_records: keyword_records }
    }
}

#[derive(Debug, PartialEq)]
/// A keyword record contains information about a FITS header.
pub struct KeywordRecord {
    /// The keyword of this record.
    keyword: Keyword,
}

impl KeywordRecord {
    /// Create a `KeywordRecord` from a specific `Keyword`.
    pub fn new(keyword: Keyword) -> KeywordRecord {
        KeywordRecord { keyword : keyword }
    }
}

#[derive(Debug, PartialEq)]
/// A unit tuple that will act as a placeholder for blank records.
pub struct BlankRecord;

#[derive(Debug, PartialEq)]
#[allow(non_camel_case_types, missing_docs)]
/// The various keywords that can be found in headers.
pub enum Keyword {
    SIMPLE,
    BITPIX,
    NAXIS,
    NAXISn(u8),
    EXTEND,
    NEXTEND,
    EXTNAME,
    EXTVER,
    ORIGIN,
    DATE,
    CREATOR,
    PROCVER,
    FILEVER,
    TIMVERSN,
    TELESCOP,
    INSTRUME,
    OBJECT,
    KEPLERID,
    CHANNEL,
    MODULE,
    OUTPUT,
    CAMPAIGN,
    DATA_REL,
    OBSMODE,
    MISSION,
    TTABLEID,
    RADESYS,
    RA_OBJ,
    DEC_OBJ,
    EQUINOX,
    PMRA,
    PMDEC,
    PMTOTAL,
    PARALLAX,
    GLON,
    GLAT,
    GMAG,
    RMAG,
    IMAG,
    ZMAG,
    JMAG,
    HMAG,
    KMAG,
    KEPMAG,
    GRCOLOR,
    JKCOLOR,
    GKCOLOR,
    TEFF,
    LOGG,
    FEH,
    EBMINUSV,
    AV,
    RADIUS,
    TMINDEX,
    CHECKSUM,
    DATASUM,
    END,
}

/// Problems that could occur when parsing a `str` are enumerated here.
#[derive(Debug)]
pub enum ParseKeywordError {
    /// When a str can not be recognized as a keyword, this error will be returned
    UnknownKeyword
}

impl FromStr for Keyword {
    type Err = ParseKeywordError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // TODO parse NAXIS1 correctly
        match s.trim_right() {
            "SIMPLE" => Ok(Keyword::SIMPLE),
            "BITPIX" => Ok(Keyword::BITPIX),
            "NAXIS" => Ok(Keyword::NAXIS),
            "EXTEND" => Ok(Keyword::EXTEND),
            "NEXTEND" => Ok(Keyword::NEXTEND),
            "EXTNAME" => Ok(Keyword::EXTNAME),
            "EXTVER" => Ok(Keyword::EXTVER),
            "ORIGIN" => Ok(Keyword::ORIGIN),
            "DATE" => Ok(Keyword::DATE),
            "CREATOR" => Ok(Keyword::CREATOR),
            "PROCVER" => Ok(Keyword::PROCVER),
            "FILEVER" => Ok(Keyword::FILEVER),
            "TIMVERSN" => Ok(Keyword::TIMVERSN),
            "TELESCOP" => Ok(Keyword::TELESCOP),
            "INSTRUME" => Ok(Keyword::INSTRUME),
            "OBJECT" => Ok(Keyword::OBJECT),
            "KEPLERID" => Ok(Keyword::KEPLERID),
            "CHANNEL" => Ok(Keyword::CHANNEL),
            "MODULE" => Ok(Keyword::MODULE),
            "OUTPUT" => Ok(Keyword::OUTPUT),
            "CAMPAIGN" => Ok(Keyword::CAMPAIGN),
            "DATA_REL" => Ok(Keyword::DATA_REL),
            "OBSMODE" => Ok(Keyword::OBSMODE),
            "MISSION" => Ok(Keyword::MISSION),
            "TTABLEID" => Ok(Keyword::TTABLEID),
            "RADESYS" => Ok(Keyword::RADESYS),
            "RA_OBJ" => Ok(Keyword::RA_OBJ),
            "DEC_OBJ" => Ok(Keyword::DEC_OBJ),
            "EQUINOX" => Ok(Keyword::EQUINOX),
            "PMRA" => Ok(Keyword::PMRA),
            "PMDEC" => Ok(Keyword::PMDEC),
            "PMTOTAL" => Ok(Keyword::PMTOTAL),
            "PARALLAX" => Ok(Keyword::PARALLAX),
            "GLON" => Ok(Keyword::GLON),
            "GLAT" => Ok(Keyword::GLAT),
            "GMAG" => Ok(Keyword::GMAG),
            "RMAG" => Ok(Keyword::RMAG),
            "IMAG" => Ok(Keyword::IMAG),
            "ZMAG" => Ok(Keyword::ZMAG),
            "JMAG" => Ok(Keyword::JMAG),
            "HMAG" => Ok(Keyword::HMAG),
            "KMAG" => Ok(Keyword::KMAG),
            "KEPMAG" => Ok(Keyword::KEPMAG),
            "GRCOLOR" => Ok(Keyword::GRCOLOR),
            "JKCOLOR" => Ok(Keyword::JKCOLOR),
            "GKCOLOR" => Ok(Keyword::GKCOLOR),
            "TEFF" => Ok(Keyword::TEFF),
            "LOGG" => Ok(Keyword::LOGG),
            "FEH" => Ok(Keyword::FEH),
            "EBMINUSV" => Ok(Keyword::EBMINUSV),
            "AV" => Ok(Keyword::AV),
            "RADIUS" => Ok(Keyword::RADIUS),
            "TMINDEX" => Ok(Keyword::TMINDEX),
            "CHECKSUM" => Ok(Keyword::CHECKSUM),
            "DATASUM" => Ok(Keyword::DATASUM),
            "END" => Ok(Keyword::END),
            _ => Err(ParseKeywordError::UnknownKeyword)
        }
    }
}

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

    fn fits_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            Fits { primary_header: PrimaryHeader::new(vec!()) },
            Fits::new(PrimaryHeader::new(vec!()))
        );
    }

    fn primary_header_constructed_from_the_new_function_shoul_eq_hand_construction() {
        assert_eq!(
            PrimaryHeader { keyword_records: vec!(
                KeywordRecord::new(Keyword::SIMPLE),
                KeywordRecord::new(Keyword::NEXTEND),
            )},
            PrimaryHeader::new(vec!(
                KeywordRecord::new(Keyword::SIMPLE),
                KeywordRecord::new(Keyword::NEXTEND),
            ))
        );
    }

    #[test]
    fn keyword_record_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            KeywordRecord { keyword: Keyword::ORIGIN },
            KeywordRecord::new(Keyword::ORIGIN));
    }

    #[test]
    fn keywords_could_be_constructed_from_str() {
        let data = vec!(
            ("SIMPLE", Keyword::SIMPLE),
            ("BITPIX", Keyword::BITPIX),
            ("NAXIS", Keyword::NAXIS),
            ("EXTEND", Keyword::EXTEND),
            ("NEXTEND", Keyword::NEXTEND),
            ("EXTVER", Keyword::EXTVER),
            ("ORIGIN", Keyword::ORIGIN),
            ("DATE", Keyword::DATE),
            ("CREATOR", Keyword::CREATOR),
            ("PROCVER", Keyword::PROCVER),
            ("FILEVER", Keyword::FILEVER),
            ("TIMVERSN", Keyword::TIMVERSN),
            ("TELESCOP", Keyword::TELESCOP),
            ("INSTRUME", Keyword::INSTRUME),
            ("OBJECT", Keyword::OBJECT),
            ("KEPLERID", Keyword::KEPLERID),
            ("CHANNEL", Keyword::CHANNEL),
            ("MODULE", Keyword::MODULE),
            ("OUTPUT", Keyword::OUTPUT),
            ("CAMPAIGN", Keyword::CAMPAIGN),
            ("DATA_REL", Keyword::DATA_REL),
            ("OBSMODE", Keyword::OBSMODE),
            ("MISSION", Keyword::MISSION),
            ("TTABLEID", Keyword::TTABLEID),
            ("RADESYS", Keyword::RADESYS),
            ("RA_OBJ", Keyword::RA_OBJ),
            ("DEC_OBJ", Keyword::DEC_OBJ),
            ("EQUINOX", Keyword::EQUINOX),
            ("PMRA", Keyword::PMRA),
            ("PMDEC", Keyword::PMDEC),
            ("PMTOTAL", Keyword::PMTOTAL),
            ("PARALLAX", Keyword::PARALLAX),
            ("GLON", Keyword::GLON),
            ("GLAT", Keyword::GLAT),
            ("GMAG", Keyword::GMAG),
            ("RMAG", Keyword::RMAG),
            ("IMAG", Keyword::IMAG),
            ("ZMAG", Keyword::ZMAG),
            ("JMAG", Keyword::JMAG),
            ("HMAG", Keyword::HMAG),
            ("KMAG", Keyword::KMAG),
            ("KEPMAG", Keyword::KEPMAG),
            ("GRCOLOR", Keyword::GRCOLOR),
            ("JKCOLOR", Keyword::JKCOLOR),
            ("GKCOLOR", Keyword::GKCOLOR),
            ("TEFF", Keyword::TEFF),
            ("LOGG", Keyword::LOGG),
            ("FEH", Keyword::FEH),
            ("EBMINUSV", Keyword::EBMINUSV),
            ("AV", Keyword::AV),
            ("RADIUS", Keyword::RADIUS),
            ("TMINDEX", Keyword::TMINDEX),
            ("CHECKSUM", Keyword::CHECKSUM),
            ("DATASUM", Keyword::DATASUM),
            ("END", Keyword::END),
        );

        for (input, expected) in data {
            assert_eq!(Keyword::from_str(input).unwrap(), expected);
        }
    }

    #[test]
    fn should_also_parse_whitespace_keywords() {
        assert_eq!(Keyword::from_str("SIMPLE  ").unwrap(), Keyword::SIMPLE);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::io::{stdout, Write};
use std::env;

use super::peg::{Pipeline, Job};
use super::input_editor::readln;
use super::status::{SUCCESS, FAILURE};

use regex::Regex;

pub struct Variables {
    variables: BTreeMap<String, String>,
}

impl Default for Variables {
    fn default() -> Variables {
        Variables { variables: BTreeMap::new() }
    }
}

impl Variables {
    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let mut out = stdout();
        for arg in args.into_iter().skip(1) {
            print!("{}=", arg.as_ref().trim());
            if let Err(message) = out.flush() {
                println!("{}: Failed to flush stdout", message);
                return FAILURE;
            }
            if let Some(value) = readln() {
                self.set_var(arg.as_ref(), value.trim());
            }
        }
        SUCCESS
    }

    pub fn let_<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        match Variables::parse_assignment(args) {
            (Some(key), Some(value)) => {
                if !Variables::is_valid_variable_name(&key) {
                    println!("Invalid variable name");
                    return FAILURE;
                }
                self.variables.insert(key.to_string(), value.to_string());
            },
            (Some(_), None) => {
                println!("Please provide a value for the variable");
                return FAILURE;
            },
            _ => {
                for (key, value) in &self.variables {
                    println!("{}={}", key, value);
                }
            }
        }
        SUCCESS
    }

    pub fn drop_variable<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let args = args.into_iter().collect::<Vec<I::Item>>();
        if args.len() <= 1 {
            println!("You must specify a variable name");
            return FAILURE;
        }
        for variable in args.iter().skip(1) {
            if let None = self.unset_var(variable.as_ref()) {
                println!("Undefined variable: {}", variable.as_ref());
                return FAILURE;
            }
        }
        SUCCESS
    }

    pub fn set_var(&mut self, name: &str, value: &str) {
        if !name.is_empty() {
            if value.is_empty() {
                self.variables.remove(&name.to_string());
            } else {
                self.variables.insert(name.to_string(), value.to_string());
            }
        }
    }

    pub fn get_var(&self, name: &str) -> Option<String> {
        self.variables.get(name).cloned().or(env::var(name).ok())
    }

    pub fn unset_var(&mut self, name: &str) -> Option<String> {
        self.variables.remove(name)
    }

    fn parse_assignment<I: IntoIterator>(args: I) -> (Option<String>, Option<String>)
        where I::Item: AsRef<str>
    {
        let args = args.into_iter();
        let string: String = args.skip(1).fold(String::new(), |string, x| string + x.as_ref());
        let mut split = string.split('=');
        (split.next().and_then(|x| if x == "" { None } else { Some(x.to_owned()) }), split.next().and_then(|x| Some(x.to_owned())))
    }

    pub fn export_variable<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        match Variables::parse_assignment(args) {
            (Some(key), Some(value)) => {
                if !Variables::is_valid_variable_name(&key) {
                    println!("Invalid variable name");
                    return FAILURE;
                }
                env::set_var(key, value);
            },
            (Some(key), None) => {
                if let Some(local_value) = self.get_var(&key) {
                    env::set_var(key, local_value);
                } else {
                    println!("Unknown variable: {}", &key);
                    return FAILURE;
                }
            },
            _ => {
                println!("Usage: export KEY=VALUE");
                return FAILURE;
            }
        }
        SUCCESS
    }

    pub fn expand_pipeline(&self, pipeline: &Pipeline) -> Pipeline {
        // TODO don't copy everything
        // TODO ugh, I made it worse
        Pipeline::new(
            pipeline.jobs.iter().map(|job| {self.expand_job(job)}).collect(),
            pipeline.stdin.clone(),
            pipeline.stdout.clone())
    }

    pub fn expand_job(&self, job: &Job) -> Job {
        // TODO don't copy everything
        Job::new(job.args
                    .iter()
                    .map(|original: &String| self.expand_string(&original))
                    .collect(),
                 job.background)
    }

    fn replace_substring(string: &mut String, start: usize, end: usize, replacement: &str) {
        let string_start = string.chars().take(start).collect::<String>();
        let string_end = string.chars().skip(end+1).collect::<String>();
        *string = string_start + replacement + &string_end;
    }

    pub fn is_valid_variable_character(c: char) -> bool {
        c.is_alphanumeric() || c == '_' || c == '?'
    }

    pub fn is_valid_variable_name(name: &str) -> bool {
        name.chars().all(Variables::is_valid_variable_character)
    }

    pub fn tilde_expansion(&self, word: String) -> String {
        let re = Regex::new("^~(.*?)((/|$).*)").unwrap();
        if let Some(cap) = re.captures_iter(&word).next() {
            if let (Some(tilde_prefix), Some(remainder)) = (cap.at(1), cap.at(2)) {
                match tilde_prefix {
                    "" => {
                        if let Some(home) = env::home_dir() {
                            return home.to_string_lossy().to_string() + remainder;
                        }
                    },
                    "+" => {
                        if let Some(pwd) = self.get_var("PWD") {
                            return pwd.to_string() + remainder;
                        } else if let Ok(pwd) = env::current_dir() {
                            return pwd.to_string_lossy().to_string() + remainder;
                        }
                    },
                    "-" => {
                        if let Some(oldpwd) = self.get_var("OLDPWD") {
                            return oldpwd.to_string() + remainder;
                        }
                    },
                    _ => (),
                }
            }
        }
        word
    }

    pub fn expand_string<'a>(&'a self, original: &'a str) -> String {
        let mut new = original.to_owned();
        new = self.tilde_expansion(new);
        let mut replacements: Vec<(usize, usize, String)> = vec![];
        for (n, _) in original.match_indices('$') {
            if n > 0 {
                if let Some(c) = original.chars().nth(n-1) {
                    if c == '\\' {
                        continue;
                    }
                }
            }
            let mut var_name = "".to_owned();
            for (i, c) in original.char_indices().skip(n+1) { // skip the dollar sign
                if Variables::is_valid_variable_character(c) {
                    var_name.push(c);
                    if i == original.len() - 1 {
                        replacements.push((n, i, var_name.clone()));
                        break;
                    }
                } else {
                    replacements.push((n, i-1, var_name.clone()));
                    break;
                }
            }
        }

        for &(start, end, ref var_name) in replacements.iter().rev() {
            if let Some(value) = self.get_var(var_name) {
                Variables::replace_substring(&mut new, start, end, &value);
            } else {
                Variables::replace_substring(&mut new, start, end, "");
            }
        }
        new.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use status::{FAILURE, SUCCESS};

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::new();
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", &expanded);
    }

    #[test]
    fn let_and_expand_a_variable() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::new();
        variables.set_var("FOO", "BAR");
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn let_fails_if_no_value() {
        let mut variables = Variables::new();
        let return_status = variables.let_(vec!["let", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn expand_several_variables() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        variables.let_(vec!["let", "X", "=", "Y"]);
        let expanded = variables.expand_string("variables: $FOO $X");
        assert_eq!("variables: BAR Y", &expanded);
    }

    #[test]
    fn replace_substring() {
        let mut string = "variable: $FOO".to_owned();
        Variables::replace_substring(&mut string, 10, 13, "BAR");
        assert_eq!("variable: BAR", string);
    }

    #[test]
    fn escape_with_backslash() {
        let variables = Variables::new();
        let expanded = variables.expand_string("\\$FOO");
        assert_eq!("\\$FOO", &expanded);
    }

    #[test]
    fn let_checks_variable_name() {
        let mut variables = Variables::new();
        let return_status = variables.let_(vec!["let", ",;!:", "=", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_deletes_variable() {
        let mut variables = Variables::new();
        variables.set_var("FOO", "BAR");
        let return_status = variables.drop_variable(vec!["drop", "FOO"]);
        assert_eq!(SUCCESS, return_status);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", expanded);
    }

    #[test]
    fn drop_fails_with_no_arguments() {
        let mut variables = Variables::new();
        let return_status = variables.drop_variable(vec!["drop"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_fails_with_undefined_variable() {
        let mut variables = Variables::new();
        let return_status = variables.drop_variable(vec!["drop", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }
}
<commit_msg>Fix the tests<commit_after>use std::collections::BTreeMap;
use std::io::{stdout, Write};
use std::env;

use super::peg::{Pipeline, Job};
use super::input_editor::readln;
use super::status::{SUCCESS, FAILURE};

use regex::Regex;

pub struct Variables {
    variables: BTreeMap<String, String>,
}

impl Default for Variables {
    fn default() -> Variables {
        Variables { variables: BTreeMap::new() }
    }
}

impl Variables {
    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let mut out = stdout();
        for arg in args.into_iter().skip(1) {
            print!("{}=", arg.as_ref().trim());
            if let Err(message) = out.flush() {
                println!("{}: Failed to flush stdout", message);
                return FAILURE;
            }
            if let Some(value) = readln() {
                self.set_var(arg.as_ref(), value.trim());
            }
        }
        SUCCESS
    }

    pub fn let_<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        match Variables::parse_assignment(args) {
            (Some(key), Some(value)) => {
                if !Variables::is_valid_variable_name(&key) {
                    println!("Invalid variable name");
                    return FAILURE;
                }
                self.variables.insert(key.to_string(), value.to_string());
            },
            (Some(_), None) => {
                println!("Please provide a value for the variable");
                return FAILURE;
            },
            _ => {
                for (key, value) in &self.variables {
                    println!("{}={}", key, value);
                }
            }
        }
        SUCCESS
    }

    pub fn drop_variable<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let args = args.into_iter().collect::<Vec<I::Item>>();
        if args.len() <= 1 {
            println!("You must specify a variable name");
            return FAILURE;
        }
        for variable in args.iter().skip(1) {
            if let None = self.unset_var(variable.as_ref()) {
                println!("Undefined variable: {}", variable.as_ref());
                return FAILURE;
            }
        }
        SUCCESS
    }

    pub fn set_var(&mut self, name: &str, value: &str) {
        if !name.is_empty() {
            if value.is_empty() {
                self.variables.remove(&name.to_string());
            } else {
                self.variables.insert(name.to_string(), value.to_string());
            }
        }
    }

    pub fn get_var(&self, name: &str) -> Option<String> {
        self.variables.get(name).cloned().or(env::var(name).ok())
    }

    pub fn unset_var(&mut self, name: &str) -> Option<String> {
        self.variables.remove(name)
    }

    fn parse_assignment<I: IntoIterator>(args: I) -> (Option<String>, Option<String>)
        where I::Item: AsRef<str>
    {
        let args = args.into_iter();
        let string: String = args.skip(1).fold(String::new(), |string, x| string + x.as_ref());
        let mut split = string.split('=');
        (split.next().and_then(|x| if x == "" { None } else { Some(x.to_owned()) }), split.next().and_then(|x| Some(x.to_owned())))
    }

    pub fn export_variable<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        match Variables::parse_assignment(args) {
            (Some(key), Some(value)) => {
                if !Variables::is_valid_variable_name(&key) {
                    println!("Invalid variable name");
                    return FAILURE;
                }
                env::set_var(key, value);
            },
            (Some(key), None) => {
                if let Some(local_value) = self.get_var(&key) {
                    env::set_var(key, local_value);
                } else {
                    println!("Unknown variable: {}", &key);
                    return FAILURE;
                }
            },
            _ => {
                println!("Usage: export KEY=VALUE");
                return FAILURE;
            }
        }
        SUCCESS
    }

    pub fn expand_pipeline(&self, pipeline: &Pipeline) -> Pipeline {
        // TODO don't copy everything
        // TODO ugh, I made it worse
        Pipeline::new(
            pipeline.jobs.iter().map(|job| {self.expand_job(job)}).collect(),
            pipeline.stdin.clone(),
            pipeline.stdout.clone())
    }

    pub fn expand_job(&self, job: &Job) -> Job {
        // TODO don't copy everything
        Job::new(job.args
                    .iter()
                    .map(|original: &String| self.expand_string(&original))
                    .collect(),
                 job.background)
    }

    fn replace_substring(string: &mut String, start: usize, end: usize, replacement: &str) {
        let string_start = string.chars().take(start).collect::<String>();
        let string_end = string.chars().skip(end+1).collect::<String>();
        *string = string_start + replacement + &string_end;
    }

    pub fn is_valid_variable_character(c: char) -> bool {
        c.is_alphanumeric() || c == '_' || c == '?'
    }

    pub fn is_valid_variable_name(name: &str) -> bool {
        name.chars().all(Variables::is_valid_variable_character)
    }

    pub fn tilde_expansion(&self, word: String) -> String {
        let re = Regex::new("^~(.*?)((/|$).*)").unwrap();
        if let Some(cap) = re.captures_iter(&word).next() {
            if let (Some(tilde_prefix), Some(remainder)) = (cap.at(1), cap.at(2)) {
                match tilde_prefix {
                    "" => {
                        if let Some(home) = env::home_dir() {
                            return home.to_string_lossy().to_string() + remainder;
                        }
                    },
                    "+" => {
                        if let Some(pwd) = self.get_var("PWD") {
                            return pwd.to_string() + remainder;
                        } else if let Ok(pwd) = env::current_dir() {
                            return pwd.to_string_lossy().to_string() + remainder;
                        }
                    },
                    "-" => {
                        if let Some(oldpwd) = self.get_var("OLDPWD") {
                            return oldpwd.to_string() + remainder;
                        }
                    },
                    _ => (),
                }
            }
        }
        word
    }

    pub fn expand_string<'a>(&'a self, original: &'a str) -> String {
        let mut new = original.to_owned();
        new = self.tilde_expansion(new);
        let mut replacements: Vec<(usize, usize, String)> = vec![];
        for (n, _) in original.match_indices('$') {
            if n > 0 {
                if let Some(c) = original.chars().nth(n-1) {
                    if c == '\\' {
                        continue;
                    }
                }
            }
            let mut var_name = "".to_owned();
            for (i, c) in original.char_indices().skip(n+1) { // skip the dollar sign
                if Variables::is_valid_variable_character(c) {
                    var_name.push(c);
                    if i == original.len() - 1 {
                        replacements.push((n, i, var_name.clone()));
                        break;
                    }
                } else {
                    replacements.push((n, i-1, var_name.clone()));
                    break;
                }
            }
        }

        for &(start, end, ref var_name) in replacements.iter().rev() {
            if let Some(value) = self.get_var(var_name) {
                Variables::replace_substring(&mut new, start, end, &value);
            } else {
                Variables::replace_substring(&mut new, start, end, "");
            }
        }
        new.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use status::{FAILURE, SUCCESS};

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::default();
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", &expanded);
    }

    #[test]
    fn let_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set_var("FOO", "BAR");
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn let_fails_if_no_value() {
        let mut variables = Variables::default();
        let return_status = variables.let_(vec!["let", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn expand_several_variables() {
        let mut variables = Variables::default();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        variables.let_(vec!["let", "X", "=", "Y"]);
        let expanded = variables.expand_string("variables: $FOO $X");
        assert_eq!("variables: BAR Y", &expanded);
    }

    #[test]
    fn replace_substring() {
        let mut string = "variable: $FOO".to_owned();
        Variables::replace_substring(&mut string, 10, 13, "BAR");
        assert_eq!("variable: BAR", string);
    }

    #[test]
    fn escape_with_backslash() {
        let variables = Variables::default();
        let expanded = variables.expand_string("\\$FOO");
        assert_eq!("\\$FOO", &expanded);
    }

    #[test]
    fn let_checks_variable_name() {
        let mut variables = Variables::default();
        let return_status = variables.let_(vec!["let", ",;!:", "=", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_deletes_variable() {
        let mut variables = Variables::default();
        variables.set_var("FOO", "BAR");
        let return_status = variables.drop_variable(vec!["drop", "FOO"]);
        assert_eq!(SUCCESS, return_status);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", expanded);
    }

    #[test]
    fn drop_fails_with_no_arguments() {
        let mut variables = Variables::default();
        let return_status = variables.drop_variable(vec!["drop"]);
        assert_eq!(FAILURE, return_status);
    }

    #[test]
    fn drop_fails_with_undefined_variable() {
        let mut variables = Variables::default();
        let return_status = variables.drop_variable(vec!["drop", "FOO"]);
        assert_eq!(FAILURE, return_status);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "secsp"]
#![crate_type = "lib"]

#[macro_use]
extern crate nom;

pub mod parser;
pub mod syntax;

pub struct ParseResult {
    pub statements: Vec<syntax::Statement>,
}

pub fn parse<R: std::io::Read>(input: &mut R) -> ParseResult {
    let mut buffer = vec![];

    input.read_to_end(&mut buffer).unwrap();
    parse_from_slice(&buffer)
}

fn parse_from_slice(input: &[u8]) -> ParseResult {
    let (_, result) = parser::statement_list(input).unwrap();

    ParseResult { statements: result }
}<commit_msg>Add top-level documentation to libsecsp<commit_after>//! This is the parsing backend library for the CSP language.
//!
//! The top level `parse` function can be used to parse a list of
//! statements from an input source implementing `Read`.  The parser combinators
//! that this library is built on are exposed under the `parser` module, and AST types
//! under the `syntax` module.
//!
//! # Examples
//! ```rust
//! use secsp::syntax::*;
//!
//! let input = b"block abc{}";
//! let parse_result = secsp::parse_from_slice(&input[..]);
//! match parse_result.statements[0] {
//!     Statement::Declaration(Declaration::Block { is_abstract, ref name, ref qualifier, ref statements }) => println!("Parsed block"),
//!     _ => panic!("Didn't find a block!")
//! }
//! ```

#![crate_name = "secsp"]
#![crate_type = "lib"]

#[macro_use]
extern crate nom;

pub mod parser;
pub mod syntax;

pub struct ParseResult {
    pub statements: Vec<syntax::Statement>,
}

pub fn parse<R: std::io::Read>(input: &mut R) -> ParseResult {
    let mut buffer = vec![];

    input.read_to_end(&mut buffer).unwrap();
    parse_from_slice(&buffer)
}

pub fn parse_from_slice(input: &[u8]) -> ParseResult {
    let (_, result) = parser::statement_list(input).unwrap();

    ParseResult { statements: result }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt::{Debug, Error, Formatter};
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref SYMBOLICATOR: Symbolicator = Symbolicator::new();
}

pub fn symbolicate<S: Into<String>>(string: S) -> Symbol {
    (*SYMBOLICATOR).symbolicate(string)
}

pub fn desymbolicate<S: AsRef<Symbol>>(symbol: &S) -> Option<String> {
    (*SYMBOLICATOR).desymbolicate(symbol)
}

#[derive(Clone)]
struct Symbolicator(Arc<Mutex<InnerSymbolicator>>);

impl Symbolicator {
    fn new() -> Self {
        let inner = InnerSymbolicator::new();
        Self(Arc::new(Mutex::new(inner)))
    }

    pub fn symbolicate<S: Into<String>>(&self, string: S) -> Symbol {
        let string = string.into();
        let mut inner = self.0.lock().unwrap();
        if let Some(existing_id) = inner.symbols.get(&string) {
            return Symbol(*existing_id);
        }
        let next_id = inner.symbols.len() as u32;
        inner.symbols.insert(string, next_id);
        Symbol(next_id)
    }

    pub fn desymbolicate<S: AsRef<Symbol>>(&self, symbol: &S) -> Option<String> {
        let inner = self.0.lock().unwrap();
        let id = symbol.as_ref().0;
        for (key, value) in inner.symbols.iter() {
            if *value == id {
                return Some(key.clone());
            }
        }
        None
    }
}

type SymbolId = u32;

#[derive(Clone, Copy, PartialEq)]
pub struct Symbol(SymbolId);

impl Symbol {
    pub fn id(&self) -> SymbolId {
        self.0
    }
}

impl AsRef<Symbol> for Symbol {
    fn as_ref(&self) -> &Symbol {
        &self
    }
}

#[cfg(not(test))]
impl Debug for Symbol {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_tuple("Symbol")
            .field(&self.0)
            .field(&(*SYMBOLICATOR).desymbolicate(&self))
            .finish()
    }
}

#[cfg(test)]
impl Debug for Symbol {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_tuple("Symbol").field(&self.0).finish()
    }
}

// Trick trait to enforce that the `Symbolicator` is thread-safe.
trait MustBeSendAndSync: Send + Sync {}

impl MustBeSendAndSync for Symbolicator {}

struct InnerSymbolicator {
    symbols: HashMap<String, SymbolId>,
}

impl InnerSymbolicator {
    pub fn new() -> Self {
        Self {
            symbols: HashMap::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::thread;

    use super::{Symbol, Symbolicator};
    use std::io::Write;

    #[test]
    fn it_symbolicates_and_desymbolicates() {
        let symbolicator = Symbolicator::new();
        let symbol = symbolicator.symbolicate("foo");
        assert_eq!(symbol, Symbol(0));
        assert_eq!(symbolicator.desymbolicate(&symbol), Some("foo".to_string()),);
        assert_eq!(symbolicator.desymbolicate(&Symbol(1)), None);
    }

    #[test]
    fn it_symbolicates_thread_safely() {
        let symbolicator = Symbolicator::new();

        // Spawn 10 of threads that will all race to symbolicate.
        (0..10)
            .into_iter()
            .map(|_| {
                let movable = symbolicator.clone();
                thread::spawn(move || {
                    assert_eq!(movable.symbolicate("foo"), Symbol(0));
                })
            })
            .map(|handle| handle.join().unwrap())
            .for_each(drop);

        // Spawn 10 of threads that will all race to desymbolicate.
        (0..10)
            .into_iter()
            .map(|_| {
                let movable = symbolicator.clone();
                thread::spawn(move || {
                    assert_eq!(movable.desymbolicate(&Symbol(0)), Some("foo".to_string()));
                })
            })
            .map(|handle| handle.join().unwrap())
            .for_each(drop);
    }
}
<commit_msg>Tweak test to interleave symbolication and desymbolication<commit_after>use std::collections::HashMap;
use std::fmt::{Debug, Error, Formatter};
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref SYMBOLICATOR: Symbolicator = Symbolicator::new();
}

pub fn symbolicate<S: Into<String>>(string: S) -> Symbol {
    (*SYMBOLICATOR).symbolicate(string)
}

pub fn desymbolicate<S: AsRef<Symbol>>(symbol: &S) -> Option<String> {
    (*SYMBOLICATOR).desymbolicate(symbol)
}

#[derive(Clone)]
struct Symbolicator(Arc<Mutex<InnerSymbolicator>>);

impl Symbolicator {
    fn new() -> Self {
        let inner = InnerSymbolicator::new();
        Self(Arc::new(Mutex::new(inner)))
    }

    pub fn symbolicate<S: Into<String>>(&self, string: S) -> Symbol {
        let string = string.into();
        let mut inner = self.0.lock().unwrap();
        if let Some(existing_id) = inner.symbols.get(&string) {
            return Symbol(*existing_id);
        }
        let next_id = inner.symbols.len() as u32;
        inner.symbols.insert(string, next_id);
        Symbol(next_id)
    }

    pub fn desymbolicate<S: AsRef<Symbol>>(&self, symbol: &S) -> Option<String> {
        let inner = self.0.lock().unwrap();
        let id = symbol.as_ref().0;
        for (key, value) in inner.symbols.iter() {
            if *value == id {
                return Some(key.clone());
            }
        }
        None
    }
}

type SymbolId = u32;

#[derive(Clone, Copy, PartialEq)]
pub struct Symbol(SymbolId);

impl Symbol {
    pub fn id(&self) -> SymbolId {
        self.0
    }
}

impl AsRef<Symbol> for Symbol {
    fn as_ref(&self) -> &Symbol {
        &self
    }
}

#[cfg(not(test))]
impl Debug for Symbol {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_tuple("Symbol")
            .field(&self.0)
            .field(&(*SYMBOLICATOR).desymbolicate(&self))
            .finish()
    }
}

#[cfg(test)]
impl Debug for Symbol {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_tuple("Symbol").field(&self.0).finish()
    }
}

// Trick trait to enforce that the `Symbolicator` is thread-safe.
trait MustBeSendAndSync: Send + Sync {}

impl MustBeSendAndSync for Symbolicator {}

struct InnerSymbolicator {
    symbols: HashMap<String, SymbolId>,
}

impl InnerSymbolicator {
    pub fn new() -> Self {
        Self {
            symbols: HashMap::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::thread;

    use super::{Symbol, Symbolicator};
    use std::io::Write;

    #[test]
    fn it_symbolicates_and_desymbolicates() {
        let symbolicator = Symbolicator::new();
        let symbol = symbolicator.symbolicate("foo");
        assert_eq!(symbol, Symbol(0));
        assert_eq!(symbolicator.desymbolicate(&symbol), Some("foo".to_string()),);
        assert_eq!(symbolicator.desymbolicate(&Symbol(1)), None);
    }

    #[test]
    fn it_symbolicates_thread_safely() {
        let symbolicator = Symbolicator::new();

        // Spawn 10 of threads that will all race to symbolicate.
        (0..10)
            .into_iter()
            .map(|_| {
                let movable = symbolicator.clone();
                thread::spawn(move || {
                    assert_eq!(movable.symbolicate("foo"), Symbol(0));
                })
            })
            .map(|handle| handle.join().unwrap())
            .for_each(drop);

        // Spawn 20 of threads that will all race to symbolicate and desymbolicate.
        (0..20)
            .into_iter()
            .map(|index| {
                let movable = symbolicator.clone();
                thread::spawn(move || {
                    if index % 2 == 1 {
                        assert_eq!(movable.symbolicate("foo"), Symbol(0));
                    } else {
                        assert_eq!(movable.desymbolicate(&Symbol(0)), Some("foo".to_string()));
                    }
                })
            })
            .map(|handle| handle.join().unwrap())
            .for_each(drop);
    }
}
<|endoftext|>


<commit_before>// use v128::*;
use x86::__m128i;

pub const _SIDD_UBYTE_OPS: i8 = 0b00000000;
pub const _SIDD_UWORD_OPS: i8 = 0b00000001;
pub const _SIDD_SBYTE_OPS: i8 = 0b00000010;
pub const _SIDD_SWORD_OPS: i8 = 0b00000011;

pub const _SIDD_CMP_EQUAL_ANY: i8 = 0b00000000;
pub const _SIDD_CMP_RANGES: i8 = 0b00000100;
pub const _SIDD_CMP_EQUAL_EACH: i8 = 0b00001000;
pub const _SIDD_CMP_EQUAL_ORDERED: i8 = 0b00001100;

pub const _SIDD_POSITIVE_POLARITY: i8 = 0b00000000;
pub const _SIDD_NEGATIVE_POLARITY: i8 = 0b00010000;
pub const _SIDD_MASKED_NEGATIVE_POLARITY: i8 = 0b00110000;

pub const _SIDD_LEAST_SIGNIFICANT: i8 = 0b00000000;
pub const _SIDD_MOST_SIGNIFICANT: i8 = 0b01000000;

#[inline(always)]
#[target_feature = "+sse4.2"]
pub fn _mm_cmpestri(
    a: __m128i,
    la: i32,
    b: __m128i,
    lb: i32,
    imm8: i8,
) -> i32 {
    unsafe { pcmpestri128(a, la, b, lb, imm8) }
}

#[allow(improper_ctypes)]
extern {
    #[link_name = "llvm.x86.sse42.pcmpestri128"]
    fn pcmpestri128(a: __m128i, la: i32, b: __m128i, lb: i32, imm8: i8) -> i32;
}

#[cfg(test)]
mod tests {
    use v128::*;
    use x86::{__m128i, sse42};

    #[test]
    #[target_feature = "+sse4.2"]
    fn _mm_cmpestri() {
        let a = &b"bar             "[..];
        let b = &b"foobar          "[..];
        let va = __m128i::from(u8x16::load(a, 0));
        let vb = __m128i::from(u8x16::load(b, 0));
        let i = sse42::_mm_cmpestri(
            va, 3, vb, 6,
            sse42::_SIDD_CMP_EQUAL_ORDERED | sse42::_SIDD_MOST_SIGNIFICANT);
        assert_eq!(3, i);
    }
}
<commit_msg>progress<commit_after>// use v128::*;
use x86::__m128i;

pub const _SIDD_UBYTE_OPS: i8 = 0b00000000;
pub const _SIDD_UWORD_OPS: i8 = 0b00000001;
pub const _SIDD_SBYTE_OPS: i8 = 0b00000010;
pub const _SIDD_SWORD_OPS: i8 = 0b00000011;

pub const _SIDD_CMP_EQUAL_ANY: i8 = 0b00000000;
pub const _SIDD_CMP_RANGES: i8 = 0b00000100;
pub const _SIDD_CMP_EQUAL_EACH: i8 = 0b00001000;
pub const _SIDD_CMP_EQUAL_ORDERED: i8 = 0b00001100;

pub const _SIDD_POSITIVE_POLARITY: i8 = 0b00000000;
pub const _SIDD_NEGATIVE_POLARITY: i8 = 0b00010000;
pub const _SIDD_MASKED_NEGATIVE_POLARITY: i8 = 0b00110000;

pub const _SIDD_LEAST_SIGNIFICANT: i8 = 0b00000000;
pub const _SIDD_MOST_SIGNIFICANT: i8 = 0b01000000;

macro_rules! constify_imm8 {
    ($imm8:expr, $expand:ident) => {
        #[allow(overflowing_literals)]
        match $imm8 & 0b1111_1111 {
            0 => $expand!(0),
            1 => $expand!(1),
            2 => $expand!(2),
            3 => $expand!(3),
            4 => $expand!(4),
            5 => $expand!(5),
            6 => $expand!(6),
            7 => $expand!(7),
            8 => $expand!(8),
            9 => $expand!(9),
            10 => $expand!(10),
            11 => $expand!(11),
            12 => $expand!(12),
            13 => $expand!(13),
            14 => $expand!(14),
            15 => $expand!(15),
            16 => $expand!(16),
            17 => $expand!(17),
            18 => $expand!(18),
            19 => $expand!(19),
            20 => $expand!(20),
            21 => $expand!(21),
            22 => $expand!(22),
            23 => $expand!(23),
            24 => $expand!(24),
            25 => $expand!(25),
            26 => $expand!(26),
            27 => $expand!(27),
            28 => $expand!(28),
            29 => $expand!(29),
            30 => $expand!(30),
            31 => $expand!(31),
            32 => $expand!(32),
            33 => $expand!(33),
            34 => $expand!(34),
            35 => $expand!(35),
            36 => $expand!(36),
            37 => $expand!(37),
            38 => $expand!(38),
            39 => $expand!(39),
            40 => $expand!(40),
            41 => $expand!(41),
            42 => $expand!(42),
            43 => $expand!(43),
            44 => $expand!(44),
            45 => $expand!(45),
            46 => $expand!(46),
            47 => $expand!(47),
            48 => $expand!(48),
            49 => $expand!(49),
            50 => $expand!(50),
            51 => $expand!(51),
            52 => $expand!(52),
            53 => $expand!(53),
            54 => $expand!(54),
            55 => $expand!(55),
            56 => $expand!(56),
            57 => $expand!(57),
            58 => $expand!(58),
            59 => $expand!(59),
            60 => $expand!(60),
            61 => $expand!(61),
            62 => $expand!(62),
            63 => $expand!(63),
            64 => $expand!(64),
            65 => $expand!(65),
            66 => $expand!(66),
            67 => $expand!(67),
            68 => $expand!(68),
            69 => $expand!(69),
            70 => $expand!(70),
            71 => $expand!(71),
            72 => $expand!(72),
            73 => $expand!(73),
            74 => $expand!(74),
            75 => $expand!(75),
            76 => $expand!(76),
            77 => $expand!(77),
            78 => $expand!(78),
            79 => $expand!(79),
            80 => $expand!(80),
            81 => $expand!(81),
            82 => $expand!(82),
            83 => $expand!(83),
            84 => $expand!(84),
            85 => $expand!(85),
            86 => $expand!(86),
            87 => $expand!(87),
            88 => $expand!(88),
            89 => $expand!(89),
            90 => $expand!(90),
            91 => $expand!(91),
            92 => $expand!(92),
            93 => $expand!(93),
            94 => $expand!(94),
            95 => $expand!(95),
            96 => $expand!(96),
            97 => $expand!(97),
            98 => $expand!(98),
            99 => $expand!(99),
            100 => $expand!(100),
            101 => $expand!(101),
            102 => $expand!(102),
            103 => $expand!(103),
            104 => $expand!(104),
            105 => $expand!(105),
            106 => $expand!(106),
            107 => $expand!(107),
            108 => $expand!(108),
            109 => $expand!(109),
            110 => $expand!(110),
            111 => $expand!(111),
            112 => $expand!(112),
            113 => $expand!(113),
            114 => $expand!(114),
            115 => $expand!(115),
            116 => $expand!(116),
            117 => $expand!(117),
            118 => $expand!(118),
            119 => $expand!(119),
            120 => $expand!(120),
            121 => $expand!(121),
            122 => $expand!(122),
            123 => $expand!(123),
            124 => $expand!(124),
            125 => $expand!(125),
            126 => $expand!(126),
            127 => $expand!(127),
            128 => $expand!(128),
            129 => $expand!(129),
            130 => $expand!(130),
            131 => $expand!(131),
            132 => $expand!(132),
            133 => $expand!(133),
            134 => $expand!(134),
            135 => $expand!(135),
            136 => $expand!(136),
            137 => $expand!(137),
            138 => $expand!(138),
            139 => $expand!(139),
            140 => $expand!(140),
            141 => $expand!(141),
            142 => $expand!(142),
            143 => $expand!(143),
            144 => $expand!(144),
            145 => $expand!(145),
            146 => $expand!(146),
            147 => $expand!(147),
            148 => $expand!(148),
            149 => $expand!(149),
            150 => $expand!(150),
            151 => $expand!(151),
            152 => $expand!(152),
            153 => $expand!(153),
            154 => $expand!(154),
            155 => $expand!(155),
            156 => $expand!(156),
            157 => $expand!(157),
            158 => $expand!(158),
            159 => $expand!(159),
            160 => $expand!(160),
            161 => $expand!(161),
            162 => $expand!(162),
            163 => $expand!(163),
            164 => $expand!(164),
            165 => $expand!(165),
            166 => $expand!(166),
            167 => $expand!(167),
            168 => $expand!(168),
            169 => $expand!(169),
            170 => $expand!(170),
            171 => $expand!(171),
            172 => $expand!(172),
            173 => $expand!(173),
            174 => $expand!(174),
            175 => $expand!(175),
            176 => $expand!(176),
            177 => $expand!(177),
            178 => $expand!(178),
            179 => $expand!(179),
            180 => $expand!(180),
            181 => $expand!(181),
            182 => $expand!(182),
            183 => $expand!(183),
            184 => $expand!(184),
            185 => $expand!(185),
            186 => $expand!(186),
            187 => $expand!(187),
            188 => $expand!(188),
            189 => $expand!(189),
            190 => $expand!(190),
            191 => $expand!(191),
            192 => $expand!(192),
            193 => $expand!(193),
            194 => $expand!(194),
            195 => $expand!(195),
            196 => $expand!(196),
            197 => $expand!(197),
            198 => $expand!(198),
            199 => $expand!(199),
            200 => $expand!(200),
            201 => $expand!(201),
            202 => $expand!(202),
            203 => $expand!(203),
            204 => $expand!(204),
            205 => $expand!(205),
            206 => $expand!(206),
            207 => $expand!(207),
            208 => $expand!(208),
            209 => $expand!(209),
            210 => $expand!(210),
            211 => $expand!(211),
            212 => $expand!(212),
            213 => $expand!(213),
            214 => $expand!(214),
            215 => $expand!(215),
            216 => $expand!(216),
            217 => $expand!(217),
            218 => $expand!(218),
            219 => $expand!(219),
            220 => $expand!(220),
            221 => $expand!(221),
            222 => $expand!(222),
            223 => $expand!(223),
            224 => $expand!(224),
            225 => $expand!(225),
            226 => $expand!(226),
            227 => $expand!(227),
            228 => $expand!(228),
            229 => $expand!(229),
            230 => $expand!(230),
            231 => $expand!(231),
            232 => $expand!(232),
            233 => $expand!(233),
            234 => $expand!(234),
            235 => $expand!(235),
            236 => $expand!(236),
            237 => $expand!(237),
            238 => $expand!(238),
            239 => $expand!(239),
            240 => $expand!(240),
            241 => $expand!(241),
            242 => $expand!(242),
            243 => $expand!(243),
            244 => $expand!(244),
            245 => $expand!(245),
            246 => $expand!(246),
            247 => $expand!(247),
            248 => $expand!(248),
            249 => $expand!(249),
            250 => $expand!(250),
            251 => $expand!(251),
            252 => $expand!(252),
            253 => $expand!(253),
            254 => $expand!(254),
            _ => $expand!(255),
        }
    }
}

#[inline(always)]
#[target_feature = "+sse4.2"]
pub fn _mm_cmpestri(
    a: __m128i,
    la: i32,
    b: __m128i,
    lb: i32,
    imm8: i8,
) -> i32 {
    macro_rules! call {
        ($imm8:expr) => {
            unsafe { pcmpestri128(a, la, b, lb, $imm8) }
        }
    }
    constify_imm8!(imm8, call)
}

#[allow(improper_ctypes)]
extern {
    #[link_name = "llvm.x86.sse42.pcmpestri128"]
    fn pcmpestri128(a: __m128i, la: i32, b: __m128i, lb: i32, imm8: i8) -> i32;
}

#[cfg(test)]
mod tests {
    use v128::*;
    use x86::{__m128i, sse42};

    #[test]
    #[target_feature = "+sse4.2"]
    fn _mm_cmpestri() {
        let a = &b"bar             "[..];
        let b = &b"foobar          "[..];
        let va = __m128i::from(u8x16::load(a, 0));
        let vb = __m128i::from(u8x16::load(b, 0));
        let i = sse42::_mm_cmpestri(
            va, 3, vb, 6,
            sse42::_SIDD_CMP_EQUAL_ORDERED | sse42::_SIDD_MOST_SIGNIFICANT);
        assert_eq!(3, i);
    }
}
<|endoftext|>


<commit_before>use crate::{auth::Credentials, pinky_swear::Pinky, Connection, ConnectionProperties, Result};
use parking_lot::Mutex;
use std::sync::Arc;

#[derive(Clone, Debug, Default)]
pub struct ConnectionStatus {
    inner: Arc<Mutex<Inner>>,
}

impl ConnectionStatus {
    pub fn state(&self) -> ConnectionState {
        self.inner.lock().state.clone()
    }

    pub(crate) fn set_state(&self, state: ConnectionState) {
        self.inner.lock().state = state
    }

    pub fn vhost(&self) -> String {
        self.inner.lock().vhost.clone()
    }

    pub(crate) fn set_vhost(&self, vhost: &str) {
        self.inner.lock().vhost = vhost.into();
    }

    pub fn username(&self) -> String {
        self.inner.lock().username.clone()
    }

    pub(crate) fn set_username(&self, username: &str) {
        self.inner.lock().username = username.into();
    }

    pub(crate) fn block(&self) {
        self.inner.lock().blocked = true;
    }

    pub(crate) fn unblock(&self) {
        self.inner.lock().blocked = false;
    }

    pub fn blocked(&self) -> bool {
        self.inner.lock().blocked
    }

    pub fn connected(&self) -> bool {
        self.inner.lock().state == ConnectionState::Connected
    }

    pub fn closing(&self) -> bool {
        self.inner.lock().state == ConnectionState::Closing
    }

    pub fn closed(&self) -> bool {
        self.inner.lock().state == ConnectionState::Closed
    }

    pub fn errored(&self) -> bool {
        self.inner.lock().state == ConnectionState::Error
    }
}

#[derive(Clone, Debug)]
pub enum ConnectionState {
    Initial,
    SentProtocolHeader(
        Pinky<Result<Connection>>,
        Credentials,
        ConnectionProperties,
    ),
    SentStartOk(Pinky<Result<Connection>>, Credentials),
    SentOpen(Pinky<Result<Connection>>),
    Connected,
    Closing,
    Closed,
    Error,
}

impl Default for ConnectionState {
    fn default() -> Self {
        ConnectionState::Initial
    }
}

impl PartialEq for ConnectionState {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (ConnectionState::Initial, ConnectionState::Initial) => true,
            (ConnectionState::SentProtocolHeader(..), ConnectionState::SentProtocolHeader(..)) => {
                true
            }
            (ConnectionState::SentStartOk(..), ConnectionState::SentStartOk(..)) => true,
            (ConnectionState::SentOpen(_), ConnectionState::SentOpen(_)) => true,
            (ConnectionState::Connected, ConnectionState::Connected) => true,
            (ConnectionState::Closing, ConnectionState::Closing) => true,
            (ConnectionState::Closed, ConnectionState::Closed) => true,
            (ConnectionState::Error, ConnectionState::Error) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
struct Inner {
    state: ConnectionState,
    vhost: String,
    username: String,
    blocked: bool,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            state: ConnectionState::default(),
            vhost: "/".into(),
            username: "guest".into(),
            blocked: false,
        }
    }
}
<commit_msg>rustfmt<commit_after>use crate::{auth::Credentials, pinky_swear::Pinky, Connection, ConnectionProperties, Result};
use parking_lot::Mutex;
use std::sync::Arc;

#[derive(Clone, Debug, Default)]
pub struct ConnectionStatus {
    inner: Arc<Mutex<Inner>>,
}

impl ConnectionStatus {
    pub fn state(&self) -> ConnectionState {
        self.inner.lock().state.clone()
    }

    pub(crate) fn set_state(&self, state: ConnectionState) {
        self.inner.lock().state = state
    }

    pub fn vhost(&self) -> String {
        self.inner.lock().vhost.clone()
    }

    pub(crate) fn set_vhost(&self, vhost: &str) {
        self.inner.lock().vhost = vhost.into();
    }

    pub fn username(&self) -> String {
        self.inner.lock().username.clone()
    }

    pub(crate) fn set_username(&self, username: &str) {
        self.inner.lock().username = username.into();
    }

    pub(crate) fn block(&self) {
        self.inner.lock().blocked = true;
    }

    pub(crate) fn unblock(&self) {
        self.inner.lock().blocked = false;
    }

    pub fn blocked(&self) -> bool {
        self.inner.lock().blocked
    }

    pub fn connected(&self) -> bool {
        self.inner.lock().state == ConnectionState::Connected
    }

    pub fn closing(&self) -> bool {
        self.inner.lock().state == ConnectionState::Closing
    }

    pub fn closed(&self) -> bool {
        self.inner.lock().state == ConnectionState::Closed
    }

    pub fn errored(&self) -> bool {
        self.inner.lock().state == ConnectionState::Error
    }
}

#[derive(Clone, Debug)]
pub enum ConnectionState {
    Initial,
    SentProtocolHeader(Pinky<Result<Connection>>, Credentials, ConnectionProperties),
    SentStartOk(Pinky<Result<Connection>>, Credentials),
    SentOpen(Pinky<Result<Connection>>),
    Connected,
    Closing,
    Closed,
    Error,
}

impl Default for ConnectionState {
    fn default() -> Self {
        ConnectionState::Initial
    }
}

impl PartialEq for ConnectionState {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (ConnectionState::Initial, ConnectionState::Initial) => true,
            (ConnectionState::SentProtocolHeader(..), ConnectionState::SentProtocolHeader(..)) => {
                true
            }
            (ConnectionState::SentStartOk(..), ConnectionState::SentStartOk(..)) => true,
            (ConnectionState::SentOpen(_), ConnectionState::SentOpen(_)) => true,
            (ConnectionState::Connected, ConnectionState::Connected) => true,
            (ConnectionState::Closing, ConnectionState::Closing) => true,
            (ConnectionState::Closed, ConnectionState::Closed) => true,
            (ConnectionState::Error, ConnectionState::Error) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
struct Inner {
    state: ConnectionState,
    vhost: String,
    username: String,
    blocked: bool,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            state: ConnectionState::default(),
            vhost: "/".into(),
            username: "guest".into(),
            blocked: false,
        }
    }
}
<|endoftext|>