<commit_before>extern crate itertools;

extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use itertools::Itertools;
use structopt::StructOpt;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum GridBuildError {
    Unsquare,
    // ^ Trying to build grid from non-square number of elements
    BadSideLen,
    // ^ Side length not divisible by 2 or 3
}

impl std::fmt::Display for GridBuildError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use GridBuildError::*;
        match *self {
            Unsquare => write!(f, "Unsquare"),
            BadSideLen => write!(f, "Bad Side Length"),
        }
    }
}

impl std::error::Error for GridBuildError {
    fn description(&self) -> &str {
        use GridBuildError::*;
        match *self {
            Unsquare => "Non-square number of elements",
            BadSideLen => "Side length not divisible by 2 or 3",
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Rule {
    before: Vec<bool>,
    after: Vec<bool>,
}

type RuleSet = std::collections::HashMap<Grid, Grid>;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Grid {
    side_len: usize,     // this shall always be divisible by 2 or 3
    contents: Vec<bool>, // this shall always have side_len * side_len rows
}

impl Grid {
    fn empty() -> Grid {
        Grid {
            side_len: 0,
            contents: Vec::new(),
        }
    }

    fn from_components(side_len: usize, contents: Vec<bool>) -> Result<Grid, GridBuildError> {
        if side_len * side_len != contents.len() {
            return Err(GridBuildError::Unsquare);
        }
        if side_len % 2 != 0 && side_len % 3 != 0 {
            return Err(GridBuildError::BadSideLen);
        }
        Ok(Grid {
            side_len: side_len,
            contents: contents,
        })
    }

    fn from_subgrids<T>(container: T) -> Result<Grid, GridBuildError>
    where
        T: IntoIterator<Item = Grid>,
        T::IntoIter: ExactSizeIterator,
    {
        // "sg" = "subgrid"
        let mut iter = container.into_iter().peekable();
        let sg_side_len = match iter.peek() {
            Some(sg) => sg.side_len,
            None => return Ok(Grid::empty()),
        };
        let side_len = ((iter.len() as f64).sqrt() as usize) * sg_side_len;
        let mut contents = vec![false; side_len * side_len];
        for (b, sg) in iter.enumerate() {
            for r in 0..sg_side_len {
                for c in 0..sg_side_len {
                    let src_row =
                        b / (side_len / sg_side_len) * sg_side_len + r;
                    let src_col =
                        b % (side_len / sg_side_len) * sg_side_len + c;
                    contents[src_row * side_len + src_col] =
                        sg.contents[r * sg_side_len + c];
                }
            }
        }
        Grid::from_components(side_len, contents)
    }

    fn from_bools<T>(container: T) -> Result<Grid, GridBuildError>
    where
        T: IntoIterator<Item = bool>,
        T::IntoIter: ExactSizeIterator,
    {
        let iter = container.into_iter();
        let side_len = (iter.len() as f64).sqrt() as usize;
        Grid::from_components(side_len, iter.collect())
    }

    fn split(&self) -> Vec<Grid> {
        // in this function, "sg" = "subgrid"
        let sg_side_len = if self.contents.len() % 4 == 0 { 2 } else { 3 };
        let mut grids = Vec::new();
        for b in 0..self.contents.len() / (sg_side_len * sg_side_len) {
            let mut sg_contents = vec![false; sg_side_len * sg_side_len];
            for r in 0..sg_side_len {
                for c in 0..sg_side_len {
                    let src_row =
                        b / (self.side_len / sg_side_len) * sg_side_len + r;
                    let src_col =
                        b % (self.side_len / sg_side_len) * sg_side_len + c;
                    sg_contents[r * sg_side_len + c] =
                        self.contents[src_row * self.side_len + src_col];
                }
            }
            grids.push(Grid {
                side_len: sg_side_len,
                contents: sg_contents,
            });
        }
        grids
    }

    fn enhance(&self, rules: &RuleSet) -> Grid {
        let contents = rules
            .get(self)
            .cloned()
            .map(|g| g.contents)
            .unwrap_or(self.contents.clone());
        Self::from_bools(contents).expect("Error enhancing grid")
    }

    fn iterate(&self, rules: &RuleSet) -> Grid {
        Grid::from_subgrids(self.split().iter().map(|grid| grid.enhance(rules)))
            .expect("Grid Iteration: Invalid subgrid produced")
    }

    fn count(&self) -> usize {
        self.contents.iter().filter(|b| **b).count()
    }

    fn rotate_ccw(&self) -> Grid {
        let mut contents = vec![false; self.contents.len()];
        for r in 0..self.side_len {
            for c in 0..self.side_len {
                let dst_row = self.side_len - c - 1;
                let dst_col = r;
                contents[dst_row * self.side_len + dst_col] =
                    self.contents[r * self.side_len + c];
            }
        }
        Grid::from_components(self.side_len, contents).expect("Error rotating")
    }

    fn flip_lr(&self) -> Grid {
        let mut contents = vec![false; self.contents.len()];
        for r in 0..self.side_len {
            for c in 0..self.side_len {
                contents[r * self.side_len + (self.side_len - c - 1)] =
                    self.contents[r * self.side_len + c];
            }
        }
        Grid::from_components(self.side_len, contents).expect("Error flipping")
    }
}

impl std::str::FromStr for Grid {
    type Err = GridBuildError;
    fn from_str(s: &str) -> Result<Grid, Self::Err> {
        let contents: Vec<_> = s.bytes()
            .filter_map(|b| match b {
                b'#' => Some(true),
                b'.' => Some(false),
                _ => None,
            })
            .collect();
        Self::from_bools(contents)
    }
}

fn parse(input: &str) -> Vec<Rule> {
    unimplemented!()
}

fn make_ruleset(rule_list: &[Rule]) -> RuleSet {
    unimplemented!()
}

fn start() -> Grid {
    Grid {
        side_len: 3,
        contents: vec![
            false, true, false, false, false, true, true, true, true
        ],
    }
}

fn part1(rules: &RuleSet) -> usize {
    itertools::iterate(start(), |g| g.iterate(rules))
        .nth(6)
        .unwrap()
        .count()
}

fn main() {
    let opt = Opt::from_args();
    let mut contents = String::new();
    if opt.input.to_str() == Some("-") {
        std::io::stdin()
            .read_to_string(&mut contents)
            .expect("could not read stdin");
    } else {
        let mut file = File::open(&opt.input)
            .expect(&format!("file {} not found", opt.input.display()));
        file.read_to_string(&mut contents)
            .expect(&format!("could not read file {}", opt.input.display()));
    }
    let rule_list = parse(&contents);
    let rules = make_ruleset(&rule_list);
    println!("Part 1: {}", part1(&rules));
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day20", about = "Advent of code 2017 day 20")]
struct Opt {
    #[structopt(help = "Input file", parse(from_os_str))]
    input: PathBuf,
}

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

    #[test]
    fn rotate_ccw_test() {
        assert_eq!(
            Grid::from_str("#...##...").unwrap().rotate_ccw(),
            Grid::from_str(".#..#.#..").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#.#.").unwrap().rotate_ccw(),
            Grid::from_str("..##").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#...##...").unwrap().rotate_ccw().rotate_ccw().rotate_ccw().rotate_ccw(),
            Grid::from_str("#...##...").unwrap()
        );
    }

    #[test]
    fn flip_lr_test() {
        assert_eq!(
            Grid::from_str("#...##...").unwrap().flip_lr(),
            Grid::from_str("..###....").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#.#.").unwrap().flip_lr(),
            Grid::from_str(".#.#").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#...##...").unwrap().flip_lr().flip_lr(),
            Grid::from_str("#...##...").unwrap(),
        );
    }

}
<commit_msg>2017 day 21 part 01<commit_after>extern crate itertools;

extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum GridBuildError {
    Unsquare,
    // ^ Trying to build grid from non-square number of elements
    BadSideLen,
    // ^ Side length not divisible by 2 or 3
}

impl std::fmt::Display for GridBuildError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use GridBuildError::*;
        match *self {
            Unsquare => write!(f, "Unsquare"),
            BadSideLen => write!(f, "Bad Side Length"),
        }
    }
}

impl std::error::Error for GridBuildError {
    fn description(&self) -> &str {
        use GridBuildError::*;
        match *self {
            Unsquare => "Non-square number of elements",
            BadSideLen => "Side length not divisible by 2 or 3",
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Rule {
    before: Grid,
    after: Grid,
}

type RuleSet = std::collections::HashMap<Grid, Grid>;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Grid {
    side_len: usize,     // this shall always be divisible by 2 or 3
    contents: Vec<bool>, // this shall always have side_len * side_len rows
}

impl Grid {
    fn empty() -> Grid {
        Grid {
            side_len: 0,
            contents: Vec::new(),
        }
    }

    fn from_components(
        side_len: usize,
        contents: Vec<bool>,
    ) -> Result<Grid, GridBuildError> {
        if side_len * side_len != contents.len() {
            return Err(GridBuildError::Unsquare);
        }
        if side_len % 2 != 0 && side_len % 3 != 0 {
            return Err(GridBuildError::BadSideLen);
        }
        Ok(Grid {
            side_len: side_len,
            contents: contents,
        })
    }

    fn from_subgrids<T>(container: T) -> Result<Grid, GridBuildError>
    where
        T: IntoIterator<Item = Grid>,
        T::IntoIter: ExactSizeIterator,
    {
        // "sg" = "subgrid"
        let mut iter = container.into_iter().peekable();
        let sg_side_len = match iter.peek() {
            Some(sg) => sg.side_len,
            None => return Ok(Grid::empty()),
        };
        let side_len = ((iter.len() as f64).sqrt() as usize) * sg_side_len;
        let mut contents = vec![false; side_len * side_len];
        for (b, sg) in iter.enumerate() {
            for r in 0..sg_side_len {
                for c in 0..sg_side_len {
                    let src_row =
                        b / (side_len / sg_side_len) * sg_side_len + r;
                    let src_col =
                        b % (side_len / sg_side_len) * sg_side_len + c;
                    contents[src_row * side_len + src_col] =
                        sg.contents[r * sg_side_len + c];
                }
            }
        }
        Grid::from_components(side_len, contents)
    }

    fn from_bools<T>(container: T) -> Result<Grid, GridBuildError>
    where
        T: IntoIterator<Item = bool>,
        T::IntoIter: ExactSizeIterator,
    {
        let iter = container.into_iter();
        let side_len = (iter.len() as f64).sqrt() as usize;
        Grid::from_components(side_len, iter.collect())
    }

    fn split(&self) -> Vec<Grid> {
        // in this function, "sg" = "subgrid"
        let sg_side_len = if self.contents.len() % 4 == 0 { 2 } else { 3 };
        let mut grids = Vec::new();
        for b in 0..self.contents.len() / (sg_side_len * sg_side_len) {
            let mut sg_contents = vec![false; sg_side_len * sg_side_len];
            for r in 0..sg_side_len {
                for c in 0..sg_side_len {
                    let src_row =
                        b / (self.side_len / sg_side_len) * sg_side_len + r;
                    let src_col =
                        b % (self.side_len / sg_side_len) * sg_side_len + c;
                    sg_contents[r * sg_side_len + c] =
                        self.contents[src_row * self.side_len + src_col];
                }
            }
            grids.push(Grid {
                side_len: sg_side_len,
                contents: sg_contents,
            });
        }
        grids
    }

    fn enhance(&self, rules: &RuleSet) -> Option<Grid> {
        rules.get(self).cloned().map(|g| {
            Self::from_bools(g.contents).expect("Error enhancing grid")
        })
    }

    fn iterate(&self, rules: &RuleSet) -> Grid {
        Grid::from_subgrids(self.split().iter().map(|grid| {
            grid.enhance(rules)
                .expect(&format!("Rule not found: \n{}", grid))
        })).expect("Grid Iteration: Invalid subgrid produced")
    }

    fn count(&self) -> usize {
        self.contents.iter().filter(|b| **b).count()
    }

    fn rotate_ccw(&self) -> Grid {
        let mut contents = vec![false; self.contents.len()];
        for r in 0..self.side_len {
            for c in 0..self.side_len {
                let dst_row = self.side_len - c - 1;
                let dst_col = r;
                contents[dst_row * self.side_len + dst_col] =
                    self.contents[r * self.side_len + c];
            }
        }
        Grid::from_components(self.side_len, contents).expect("Error rotating")
    }

    fn flip_lr(&self) -> Grid {
        let mut contents = vec![false; self.contents.len()];
        for r in 0..self.side_len {
            for c in 0..self.side_len {
                contents[r * self.side_len + (self.side_len - c - 1)] =
                    self.contents[r * self.side_len + c];
            }
        }
        Grid::from_components(self.side_len, contents).expect("Error flipping")
    }
}

impl std::str::FromStr for Grid {
    type Err = GridBuildError;
    fn from_str(s: &str) -> Result<Grid, Self::Err> {
        let contents: Vec<_> = s.bytes()
            .filter_map(|b| match b {
                b'#' => Some(true),
                b'.' => Some(false),
                _ => None,
            })
            .collect();
        Self::from_bools(contents)
    }
}

impl std::fmt::Display for Grid {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        for (pos, val) in self.contents.iter().enumerate() {
            if pos != 0 && pos % self.side_len == 0 {
                write!(f, "\n")?
            }
            write!(f, "{}", if *val { '#' } else { '.' })?
        }
        Ok(())
    }
}

fn parse(input: &str) -> Vec<Rule> {
    use std::str::FromStr;
    input
        .lines()
        .map(|line| {
            let (before, after) = line.split_at(
                line.find("=>").expect(&format!("Invalid line: {}", line)),
            );
            Rule {
                before: Grid::from_str(before)
                    .expect(&format!("Could not parse grid from {}", before)),
                after: Grid::from_str(after)
                    .expect(&format!("Could not parse grid from {}", after)),
            }
        })
        .collect()
}

fn make_ruleset(rule_list: &[Rule]) -> RuleSet {
    let mut rule_set = std::collections::HashMap::new();
    for rule in rule_list {
        let mut new_rule = rule.before.clone();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.rotate_ccw();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.rotate_ccw();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.rotate_ccw();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.flip_lr();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.rotate_ccw();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.rotate_ccw();
        rule_set.insert(new_rule.clone(), rule.after.clone());
        new_rule = new_rule.rotate_ccw();
        rule_set.insert(new_rule.clone(), rule.after.clone());
    }
    rule_set
}

fn start() -> Grid {
    Grid {
        side_len: 3,
        contents: vec![
            false, true, false, false, false, true, true, true, true
        ],
    }
}

fn part1(rules: &RuleSet) -> usize {
    itertools::iterate(start(), |g| g.iterate(rules))
        .nth(5)
        .unwrap()
        .count()
}

fn main() {
    let opt = Opt::from_args();
    let mut contents = String::new();
    if opt.input.to_str() == Some("-") {
        std::io::stdin()
            .read_to_string(&mut contents)
            .expect("could not read stdin");
    } else {
        let mut file = File::open(&opt.input)
            .expect(&format!("file {} not found", opt.input.display()));
        file.read_to_string(&mut contents)
            .expect(&format!("could not read file {}", opt.input.display()));
    }
    let rule_list = parse(&contents);
    let rules = make_ruleset(&rule_list);
    println!("Part 1: {}", part1(&rules));
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day20", about = "Advent of code 2017 day 20")]
struct Opt {
    #[structopt(help = "Input file", parse(from_os_str))]
    input: PathBuf,
}

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

    #[test]
    fn rotate_ccw_test() {
        assert_eq!(
            Grid::from_str("#...##...").unwrap().rotate_ccw(),
            Grid::from_str(".#..#.#..").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#.#.").unwrap().rotate_ccw(),
            Grid::from_str("..##").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#...##...")
                .unwrap()
                .rotate_ccw()
                .rotate_ccw()
                .rotate_ccw()
                .rotate_ccw(),
            Grid::from_str("#...##...").unwrap()
        );
    }

    #[test]
    fn flip_lr_test() {
        assert_eq!(
            Grid::from_str("#...##...").unwrap().flip_lr(),
            Grid::from_str("..###....").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#.#.").unwrap().flip_lr(),
            Grid::from_str(".#.#").unwrap(),
        );
        assert_eq!(
            Grid::from_str("#...##...").unwrap().flip_lr().flip_lr(),
            Grid::from_str("#...##...").unwrap(),
        );
    }

    #[test]
    fn split_2_test() {
        assert_eq!(
            Grid::from_str("#.##.#|#.#.##|......|.##.##|###...|#.##.#")
                .unwrap()
                .split(),
            vec![
                Grid::from_str("#.#.").unwrap(),
                Grid::from_str("###.").unwrap(),
                Grid::from_str(".###").unwrap(),
                Grid::from_str("...#").unwrap(),
                Grid::from_str("..#.").unwrap(),
                Grid::from_str("..##").unwrap(),
                Grid::from_str("###.").unwrap(),
                Grid::from_str("#.##").unwrap(),
                Grid::from_str("...#").unwrap(),
            ],
        )
    }

    #[test]
    fn from_subgrids_test() {
        assert_eq!(
            Grid::from_subgrids(vec![
                Grid::from_str("#.#.").unwrap(),
                Grid::from_str("###.").unwrap(),
                Grid::from_str(".###").unwrap(),
                Grid::from_str("...#").unwrap(),
                Grid::from_str("..#.").unwrap(),
                Grid::from_str("..##").unwrap(),
                Grid::from_str("###.").unwrap(),
                Grid::from_str("#.##").unwrap(),
                Grid::from_str("...#").unwrap(),
            ]).unwrap(),
            Grid::from_str("#.##.#|#.#.##|......|.##.##|###...|#.##.#")
                .unwrap(),
        )
    }

    #[test]
    fn enhance_test() {
        let rules: RuleSet = std::iter::once((
            Grid::from_str("#.#.").unwrap(),
            Grid::from_str(".##.##.##").unwrap(),
        )).collect();
        assert_eq!(
            Grid::from_str("#.#.").unwrap().enhance(&rules),
            Some(Grid::from_str(".##.##.##").unwrap())
        );
        assert_eq!(Grid::from_str(".#.#").unwrap().enhance(&rules), None);
    }

    #[test]
    fn iterate_test() {
        let input: Vec<Rule> = vec![
            Rule {
                before: Grid::from_str("../.#").unwrap(),
                after: Grid::from_str("##./#../...").unwrap(),
            },
            Rule {
                before: Grid::from_str(".#./..#/###").unwrap(),
                after: Grid::from_str("#..#/..../..../#..#").unwrap(),
            },
        ];
        let ruleset = make_ruleset(&input);
        let res = start().iterate(&ruleset).iterate(&ruleset).count();
        assert_eq!(res, 12);
    }
}
<|endoftext|>


<commit_before>use sodiumoxide::crypto::hash::sha256;
use sodiumoxide::crypto::sign;
use sodiumoxide::randombytes;
use bs58;

mod error;
pub use self::error::*;

const PUB_ADDRESS_PREFIX: &str = "GOD";
const PRIV_BUF_PREFIX: u8 = 0x01;
const PUB_BUF_PREFIX: u8 = 0x02;

pub trait Wif<T> {
    fn from_wif(s: &str) -> Result<T, WifError>;
    fn to_wif(&self) -> Box<str>;
}

#[derive(Debug, Clone, PartialEq)]
pub struct PublicKey {
    key: sign::PublicKey
}

impl PublicKey {
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        self.key.as_ref()
    }

    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &sign::Signature) -> bool {
        sign::verify_detached(sig, msg, &self.key)
    }

    #[inline]
    pub fn from_bytes(bytes: &[u8]) -> Option<PublicKey> {
        let key = sign::PublicKey::from_slice(bytes)?;
        Some(PublicKey { key })
    }
}

impl Wif<PublicKey> for PublicKey {
    fn from_wif(s: &str) -> Result<PublicKey, WifError> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix))
        }
        let raw = match bs58::decode(&s[3..]).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => return Err(WifError::new(WifErrorKind::InvalidBs58Encoding))
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen))
        } else if raw[0] != PUB_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix))
        }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum))
            }
        }

        let key = &prefixed_key[1 .. prefixed_key.len()];
        Ok(PublicKey {
            key: sign::PublicKey::from_slice(key).unwrap()
        })
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(PUB_BUF_PREFIX);
        buf.extend_from_slice(self.key.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

#[derive(Debug, Clone)]
pub struct PrivateKey {
    seed: sign::Seed,
    key: sign::SecretKey
}

impl PrivateKey {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> sign::Signature {
        sign::sign_detached(msg, &self.key)
    }

    #[inline]
    pub fn as_bytes(&self) -> ([u8; sign::SEEDBYTES], [u8; sign::SECRETKEYBYTES]) {
        (self.seed.0, self.key.0)
    }

    pub fn from_bytes(seed: &[u8; sign::SEEDBYTES],
                        key: &[u8; sign::SECRETKEYBYTES]) -> Option<PrivateKey> {
        Some(PrivateKey {
            seed: sign::Seed::from_slice(seed)?,
            key: sign::SecretKey::from_slice(key)?
        })
    }
}

impl Wif<KeyPair> for PrivateKey {
    fn from_wif(s: &str) -> Result<KeyPair, WifError> {
        let raw = match bs58::decode(s).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => return Err(WifError::new(WifErrorKind::InvalidBs58Encoding))
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen))
        } else if raw[0] != PRIV_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix))
        }

        let key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let checksum_b = &double_sha256(key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum))
            }
        }

        let seed = sign::Seed::from_slice(&key[1..]).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        Ok(KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        }))
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf = Vec::<u8>::with_capacity(37);
        buf.push(PRIV_BUF_PREFIX);
        buf.extend_from_slice(&self.seed.0);

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        bs58::encode(buf).into_string().into_boxed_str()
    }
}

#[derive(Debug, Clone)]
pub struct KeyPair(pub PublicKey, pub PrivateKey);

impl KeyPair {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> SigPair {
        SigPair {
            pub_key: self.0.clone(),
            signature: self.1.sign(msg)
        }
    }

    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &sign::Signature) -> bool {
        PublicKey::verify(&self.0, msg, sig)
    }

    pub fn gen_keypair() -> KeyPair {
        let mut raw_seed: [u8; sign::SEEDBYTES] = [0; sign::SEEDBYTES];
        randombytes::randombytes_into(&mut raw_seed);
        let seed = sign::Seed::from_slice(&raw_seed).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        })
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct SigPair {
    pub pub_key: PublicKey,
    pub signature: sign::Signature
}

impl SigPair {
    #[inline]
    pub fn verify(&self, msg: &[u8]) -> bool {
        sign::verify_detached(&self.signature, msg, &self.pub_key.key)
    }
}

#[inline]
pub fn double_sha256(buf: &[u8]) -> sha256::Digest {
    sha256::hash(sha256::hash(buf).as_ref())
}

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

    #[test]
    fn test_create_and_recover_keys() {
        let kp = KeyPair::gen_keypair();

        let pk = &*kp.0.to_wif();
        assert_eq!(&*PublicKey::from_wif(pk).unwrap().to_wif(), pk);

        let sk = &*kp.1.to_wif();
        assert_eq!(&*PrivateKey::from_wif(sk).unwrap().1.to_wif(), sk);
    }

    #[test]
    fn test_import_keys_from_wif() {
        let kp = PrivateKey::from_wif("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").unwrap();
        assert_eq!(&*kp.1.to_wif(), "3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM");
        assert_eq!(&*kp.0.to_wif(), "GOD52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8");
    }

    #[test]
    fn test_invalid_prefix() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").into_vec().unwrap();
        bytes[0] = 255;
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(PrivateKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidPrefix);

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8").into_vec().unwrap();
        bytes[0] = 255;
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(PublicKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidPrefix);
    }

    #[test]
    fn test_invalid_checksum() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").into_vec().unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(PrivateKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidChecksum);

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8").into_vec().unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(PublicKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidChecksum);
    }

    #[test]
    fn test_sign_message() {
        let msg = "Hello world!".as_bytes();
        let kp = KeyPair::gen_keypair();

        let sig = &kp.1.sign(msg);
        assert!(kp.0.verify(msg, sig));

        let pair = SigPair {
            pub_key: kp.0,
            signature: *sig
        };
        assert!(pair.verify(msg));

        // Test bad keys
        let kp = KeyPair::gen_keypair();
        assert!(!kp.verify(msg, sig));
    }
}
<commit_msg>Use u8 slices instead of arrays in the from_bytes function<commit_after>use sodiumoxide::crypto::hash::sha256;
use sodiumoxide::crypto::sign;
use sodiumoxide::randombytes;
use bs58;

mod error;
pub use self::error::*;

const PUB_ADDRESS_PREFIX: &str = "GOD";
const PRIV_BUF_PREFIX: u8 = 0x01;
const PUB_BUF_PREFIX: u8 = 0x02;

pub trait Wif<T> {
    fn from_wif(s: &str) -> Result<T, WifError>;
    fn to_wif(&self) -> Box<str>;
}

#[derive(Debug, Clone, PartialEq)]
pub struct PublicKey {
    key: sign::PublicKey
}

impl PublicKey {
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        self.key.as_ref()
    }

    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &sign::Signature) -> bool {
        sign::verify_detached(sig, msg, &self.key)
    }

    #[inline]
    pub fn from_bytes(bytes: &[u8]) -> Option<PublicKey> {
        let key = sign::PublicKey::from_slice(bytes)?;
        Some(PublicKey { key })
    }
}

impl Wif<PublicKey> for PublicKey {
    fn from_wif(s: &str) -> Result<PublicKey, WifError> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix))
        }
        let raw = match bs58::decode(&s[3..]).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => return Err(WifError::new(WifErrorKind::InvalidBs58Encoding))
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen))
        } else if raw[0] != PUB_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix))
        }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum))
            }
        }

        let key = &prefixed_key[1 .. prefixed_key.len()];
        Ok(PublicKey {
            key: sign::PublicKey::from_slice(key).unwrap()
        })
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(PUB_BUF_PREFIX);
        buf.extend_from_slice(self.key.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

#[derive(Debug, Clone)]
pub struct PrivateKey {
    seed: sign::Seed,
    key: sign::SecretKey
}

impl PrivateKey {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> sign::Signature {
        sign::sign_detached(msg, &self.key)
    }

    #[inline]
    pub fn as_bytes(&self) -> ([u8; sign::SEEDBYTES], [u8; sign::SECRETKEYBYTES]) {
        (self.seed.0, self.key.0)
    }

    #[inline]
    pub fn from_bytes(seed: &[u8], key: &[u8]) -> Option<PrivateKey> {
        Some(PrivateKey {
            seed: sign::Seed::from_slice(seed)?,
            key: sign::SecretKey::from_slice(key)?
        })
    }
}

impl Wif<KeyPair> for PrivateKey {
    fn from_wif(s: &str) -> Result<KeyPair, WifError> {
        let raw = match bs58::decode(s).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => return Err(WifError::new(WifErrorKind::InvalidBs58Encoding))
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen))
        } else if raw[0] != PRIV_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix))
        }

        let key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4 .. raw.len()];
            let checksum_b = &double_sha256(key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum))
            }
        }

        let seed = sign::Seed::from_slice(&key[1..]).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        Ok(KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        }))
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf = Vec::<u8>::with_capacity(37);
        buf.push(PRIV_BUF_PREFIX);
        buf.extend_from_slice(&self.seed.0);

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        bs58::encode(buf).into_string().into_boxed_str()
    }
}

#[derive(Debug, Clone)]
pub struct KeyPair(pub PublicKey, pub PrivateKey);

impl KeyPair {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> SigPair {
        SigPair {
            pub_key: self.0.clone(),
            signature: self.1.sign(msg)
        }
    }

    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &sign::Signature) -> bool {
        PublicKey::verify(&self.0, msg, sig)
    }

    pub fn gen_keypair() -> KeyPair {
        let mut raw_seed: [u8; sign::SEEDBYTES] = [0; sign::SEEDBYTES];
        randombytes::randombytes_into(&mut raw_seed);
        let seed = sign::Seed::from_slice(&raw_seed).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        KeyPair(PublicKey {
            key: pk
        }, PrivateKey {
            seed,
            key: sk
        })
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct SigPair {
    pub pub_key: PublicKey,
    pub signature: sign::Signature
}

impl SigPair {
    #[inline]
    pub fn verify(&self, msg: &[u8]) -> bool {
        sign::verify_detached(&self.signature, msg, &self.pub_key.key)
    }
}

#[inline]
pub fn double_sha256(buf: &[u8]) -> sha256::Digest {
    sha256::hash(sha256::hash(buf).as_ref())
}

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

    #[test]
    fn test_create_and_recover_keys() {
        let kp = KeyPair::gen_keypair();

        let pk = &*kp.0.to_wif();
        assert_eq!(&*PublicKey::from_wif(pk).unwrap().to_wif(), pk);

        let sk = &*kp.1.to_wif();
        assert_eq!(&*PrivateKey::from_wif(sk).unwrap().1.to_wif(), sk);
    }

    #[test]
    fn test_import_keys_from_wif() {
        let kp = PrivateKey::from_wif("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").unwrap();
        assert_eq!(&*kp.1.to_wif(), "3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM");
        assert_eq!(&*kp.0.to_wif(), "GOD52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8");
    }

    #[test]
    fn test_invalid_prefix() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").into_vec().unwrap();
        bytes[0] = 255;
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(PrivateKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidPrefix);

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8").into_vec().unwrap();
        bytes[0] = 255;
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(PublicKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidPrefix);
    }

    #[test]
    fn test_invalid_checksum() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").into_vec().unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(PrivateKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidChecksum);

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8").into_vec().unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(PublicKey::from_wif(&wif).unwrap_err().kind, WifErrorKind::InvalidChecksum);
    }

    #[test]
    fn test_sign_message() {
        let msg = "Hello world!".as_bytes();
        let kp = KeyPair::gen_keypair();

        let sig = &kp.1.sign(msg);
        assert!(kp.0.verify(msg, sig));

        let pair = SigPair {
            pub_key: kp.0,
            signature: *sig
        };
        assert!(pair.verify(msg));

        // Test bad keys
        let kp = KeyPair::gen_keypair();
        assert!(!kp.verify(msg, sig));
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use super::*;
use super::super::sim::*;
use moonlander_gp::{Number};
use rand;

#[derive(Debug,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub enum Expression {
	  Constant(Number),
	  Sensor(Box<Sensor>),
	  Plus(Box<Expression>, Box<Expression>),
	  Minus(Box<Expression>, Box<Expression>),
	  Multiply(Box<Expression>, Box<Expression>),
	  Divide(Box<Expression>, Box<Expression>),
}

impl_astnode!(Expression, 3,
              leaf Constant((data n random_constant)),
              leaf Sensor(sensor),
              int Plus(left, right),
              int Minus(left, right),
              int Multiply(left, right),
              int Divide(left, right));

fn random_constant(rng: &mut rand::Rng) -> Number {
        rng.next_f32() * 100.0 - 50.0
}

impl fmt::Display for Expression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expression::Constant(ref n)        => write!(f, "{}", n),
            Expression::Sensor(ref s)          => write!(f, "{}", s),
            Expression::Plus(ref l, ref r)     => write!(f, "({} + {})", l, r),
            Expression::Minus(ref l, ref r)    => write!(f, "({} - {})", l, r),
            Expression::Multiply(ref l, ref r) => write!(f, "({} * {})", l, r),
            Expression::Divide(ref l, ref r)   => write!(f, "({} / {})", l, r),
        }
    }
}

impl NumericValue for Expression {
	fn num_value(&self, sensor_data: &SensorData) -> Number {
		match *self {
			Expression::Constant(value)               => value,
			Expression::Sensor(ref sensor)            => sensor.num_value(sensor_data),
			Expression::Plus(ref left, ref right)     => left.num_value(sensor_data) + right.num_value(sensor_data),
			Expression::Minus(ref left, ref right)    => left.num_value(sensor_data) - right.num_value(sensor_data),
			Expression::Multiply(ref left, ref right) => left.num_value(sensor_data) * right.num_value(sensor_data),
			Expression::Divide(ref left, ref right)   => left.num_value(sensor_data) / right.num_value(sensor_data)
		}
	}
}

<commit_msg>Make division not accidentally break<commit_after>use std::fmt;
use super::*;
use super::super::sim::*;
use moonlander_gp::{Number};
use rand;

#[derive(Debug,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub enum Expression {
	  Constant(Number),
	  Sensor(Box<Sensor>),
	  Plus(Box<Expression>, Box<Expression>),
	  Minus(Box<Expression>, Box<Expression>),
	  Multiply(Box<Expression>, Box<Expression>),
	  Divide(Box<Expression>, Box<Expression>),
}

impl_astnode!(Expression, 3,
              leaf Constant((data n random_constant)),
              leaf Sensor(sensor),
              int Plus(left, right),
              int Minus(left, right),
              int Multiply(left, right),
              int Divide(left, right));

fn random_constant(rng: &mut rand::Rng) -> Number {
        rng.next_f32() * 100.0 - 50.0
}

impl fmt::Display for Expression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expression::Constant(ref n)        => write!(f, "{}", n),
            Expression::Sensor(ref s)          => write!(f, "{}", s),
            Expression::Plus(ref l, ref r)     => write!(f, "({} + {})", l, r),
            Expression::Minus(ref l, ref r)    => write!(f, "({} - {})", l, r),
            Expression::Multiply(ref l, ref r) => write!(f, "({} * {})", l, r),
            Expression::Divide(ref l, ref r)   => write!(f, "({} / {})", l, r),
        }
    }
}

impl NumericValue for Expression {
	fn num_value(&self, sensor_data: &SensorData) -> Number {
		match *self {
			Expression::Constant(value)               => value,
			Expression::Sensor(ref sensor)            => sensor.num_value(sensor_data),
			Expression::Plus(ref left, ref right)     => left.num_value(sensor_data) + right.num_value(sensor_data),
			Expression::Minus(ref left, ref right)    => left.num_value(sensor_data) - right.num_value(sensor_data),
			Expression::Multiply(ref left, ref right) => left.num_value(sensor_data) * right.num_value(sensor_data),
			Expression::Divide(ref left, ref right)   => {
                let right = right.num_value(sensor_data);
                // Not correct but at least it prevents a division by zero
                if right == 0.0 {
                    left.num_value(sensor_data)
                } else {
                    left.num_value(sensor_data) / right
                }
            }
		}
	}
}

<|endoftext|>


<commit_before>use collections::str::{from_utf8};

/// Checks if the nickname is valid
pub fn valid_nick(nick: &str) -> bool {
    // <nick>       ::= <letter> { <letter> | <number> | <special> }
    //<special>    ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
    //
    // As of http://tools.ietf.org/html/rfc2812#section-2.3.1
    // nickname   =  ( letter / special ) *8( letter / digit / special / "-" )
    // special    =  %x5B-60 / %x7B-7D
    for (i, char) in nick.chars().enumerate() {
        if i == 9 {
            return false
        }
        match char {
            'a'..'z' | 'A'..'Z' | '\x5B'..'\x60' | '\x7B'..'\x7D'
                if i == 0 => {},
            'a'..'z' | 'A'..'Z' | '0'..'9' | '\x5B'..'\x60' | '\x7B'..'\x7D' | '-'
                if i != 0 => {},
            _ => return false
        }
    }
    true
}

/// Validates the raw nickname and converts it into a string.
pub fn verify_nick<'a>(nick: &'a [u8]) -> Option<&'a str> {
    match from_utf8(nick) {
        None => None,
        Some(nick) => if valid_nick(nick) { Some(nick) } else { None }
    }
}

pub fn valid_channel(channel: &str) -> bool {
    for (i, char) in channel.chars().enumerate() {
        match char {
            '#' | '&' if i == 0 => {},
            _ if i == 0 => { return false },
            ' ' | '\x07' | ',' => { return false }
            _ => {}
        }
    }
    true
}

/// Validates the raw channel name and converts it into a string.
pub fn verify_channel<'a>(channel: &'a [u8]) -> Option<&'a str> {
    match from_utf8(channel) {
        None => None,
        Some(channel) =>
            if valid_channel(channel) {
                Some(channel)
            } else { None }
    }
}

#[deriving(Clone)]
pub enum Receiver {
    ChannelName(String),
    NickName(String),
    InvalidReceiver(Vec<u8>)
}

/// Validates the raw channel name and converts it into a string.
pub fn verify_receiver<'a>(recv: &'a [u8]) -> Receiver {
    match from_utf8(recv) {
        None => InvalidReceiver(recv.to_vec()),
        Some(name) =>
            if valid_channel(name) {
                ChannelName(name.to_string())
            } else if valid_nick(name) {
                NickName(name.to_string())
            } else { InvalidReceiver(recv.to_vec()) }
    }
}

#[deriving(Hash, PartialEq, Eq, Clone)]
/// A host mask in the form "*!*@*.*"
pub struct HostMask {
    mask: String
}

impl HostMask {
    pub fn new(mask: String) -> HostMask {
        HostMask {
            mask: mask
        }
    }
    pub fn from_parts(nick: &str, name: &str, host: &str) -> HostMask {
        HostMask {
            mask: format!("{}!{}@{}", nick, name, host)
        }
    }
    /// checks if the host mask matches another mask
    ///
    /// "*!*@*.com" would match "a!b@example.com"
    pub fn matches(&self, mask: &str) -> bool {
        let mut mask_chars = mask.chars().peekable();
        let mut chars = self.mask.as_slice().chars().peekable();
        for c in chars {
            match c {
                '*' => match chars.peek() {
                    // Consume all chars until next match is found
                    Some(next) => while match mask_chars.peek() {
                        Some(mask_cha) => mask_cha != next,
                        None => false } { let _ = mask_chars.next(); },
                    // * at end of the string matches the whole rest
                    None => return true
                },
                cha => match mask_chars.next() {
                    None => return false,
                    Some(mask_cha) => if cha != mask_cha { return false }
                }
            }
        }
        !mask_chars.next().is_some()
    }

    /// Returns the hostname
    pub fn host(&self) -> Option<&str> {
        self.mask.as_slice().split('@').last()
    }
    /// Returns the username
    pub fn user(&self) -> Option<&str> {
        self.mask.as_slice().split('@').nth(0).and_then(|v|
            v.split('!').last()
        )
    }
    /// Returns the nickname
    pub fn nick(&self) -> Option<&str> {
        self.mask.as_slice().split('!').nth(0)
    }

    /// Returns a view into the mask
    pub fn as_str(&self) -> &str {
        return self.mask.as_slice()
    }
}

#[cfg(test)]
mod tests {
	use super::{valid_nick, valid_channel, HostMask};
	#[test]
	/// Test the nickname validation function
	fn test_nickname_validation() {
		assert!(valid_nick("FooBar123"))
		assert_eq!(valid_nick("FooBar1234"), false)
		assert_eq!(valid_nick("1FooBar12"), false)
	}
	#[test]
	/// Test the nickname validation function
	fn test_channel_name_validation() {
		assert!(valid_channel("#Foobar"))
		assert_eq!(valid_channel("Foobar"), false)
		assert_eq!(valid_channel("#Foo,bar"), false)
		assert_eq!(valid_channel("Foo bar"), false)
	}

    #[test]
    /// Test the hostname masks
	fn test_masks() {
		assert!(HostMask::new("*!*@*.com".to_string()).matches("a!b@example.com"))
		assert!(!HostMask::new("*!*@*.com".to_string()).matches("*!*@*.edu"))
		assert!(!HostMask::new("*!*@*.com".to_string()).matches("*!*@*.cop"))
		assert!(!HostMask::new("*!*@*.com".to_string()).matches("*!*@*.coma"))
		assert!(HostMask::new("*!*@example.com".to_string()).matches("a!b@example.com"))
		assert!(HostMask::new("foo!*@*.com".to_string()).matches("foo!bar@example.com"))
		assert!(!HostMask::new("foo!*@*.com".to_string()).matches("baz!bar@example.com"))
		assert!(HostMask::new("*!bar@*.com".to_string()).matches("foo!bar@example.com"))
		assert!(!HostMask::new("*!bar@*.com".to_string()).matches("foo!baz@example.com"))
	}

}
<commit_msg>update to latest rust<commit_after>use collections::str::{from_utf8};

/// Checks if the nickname is valid
pub fn valid_nick(nick: &str) -> bool {
    // <nick>       ::= <letter> { <letter> | <number> | <special> }
    //<special>    ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
    //
    // As of http://tools.ietf.org/html/rfc2812#section-2.3.1
    // nickname   =  ( letter / special ) *8( letter / digit / special / "-" )
    // special    =  %x5B-60 / %x7B-7D
    for (i, char) in nick.chars().enumerate() {
        if i == 9 {
            return false
        }
        match char {
            'a'..'z' | 'A'..'Z' | '\x5B'..'\x60' | '\x7B'..'\x7D'
                if i == 0 => {},
            'a'..'z' | 'A'..'Z' | '0'..'9' | '\x5B'..'\x60' | '\x7B'..'\x7D' | '-'
                if i != 0 => {},
            _ => return false
        }
    }
    true
}

/// Validates the raw nickname and converts it into a string.
pub fn verify_nick<'a>(nick: &'a [u8]) -> Option<&'a str> {
    match from_utf8(nick) {
        None => None,
        Some(nick) => if valid_nick(nick) { Some(nick) } else { None }
    }
}

pub fn valid_channel(channel: &str) -> bool {
    for (i, char) in channel.chars().enumerate() {
        match char {
            '#' | '&' if i == 0 => {},
            _ if i == 0 => { return false },
            ' ' | '\x07' | ',' => { return false }
            _ => {}
        }
    }
    true
}

/// Validates the raw channel name and converts it into a string.
pub fn verify_channel<'a>(channel: &'a [u8]) -> Option<&'a str> {
    match from_utf8(channel) {
        None => None,
        Some(channel) =>
            if valid_channel(channel) {
                Some(channel)
            } else { None }
    }
}

#[deriving(Clone)]
pub enum Receiver {
    ChannelName(String),
    NickName(String),
    InvalidReceiver(Vec<u8>)
}

/// Validates the raw channel name and converts it into a string.
pub fn verify_receiver<'a>(recv: &'a [u8]) -> Receiver {
    match from_utf8(recv) {
        None => InvalidReceiver(recv.to_vec()),
        Some(name) =>
            if valid_channel(name) {
                ChannelName(name.to_string())
            } else if valid_nick(name) {
                NickName(name.to_string())
            } else { InvalidReceiver(recv.to_vec()) }
    }
}

#[deriving(Hash, PartialEq, Eq, Clone)]
/// A host mask in the form "*!*@*.*"
pub struct HostMask {
    mask: String
}

impl HostMask {
    pub fn new(mask: String) -> HostMask {
        HostMask {
            mask: mask
        }
    }
    pub fn from_parts(nick: &str, name: &str, host: &str) -> HostMask {
        HostMask {
            mask: format!("{}!{}@{}", nick, name, host)
        }
    }
    /// checks if the host mask matches another mask
    ///
    /// "*!*@*.com" would match "a!b@example.com"
    pub fn matches(&self, mask: &str) -> bool {
        let mut mask_chars = mask.chars().peekable();
        let mut chars = self.mask.as_slice().chars().peekable();
        loop {
            match chars.next() {
                Some('*') => match chars.peek() {
                    // Consume all chars until next match is found
                    Some(next) => while match mask_chars.peek() {
                        Some(mask_cha) => mask_cha != next,
                        None => false } { let _ = mask_chars.next(); },
                    // * at end of the string matches the whole rest
                    None => return true
                },
                Some(cha) => match mask_chars.next() {
                    None => return false,
                    Some(mask_cha) => if cha != mask_cha { return false }
                },
                None => break
            }
        }
        !mask_chars.next().is_some()
    }

    /// Returns the hostname
    pub fn host(&self) -> Option<&str> {
        self.mask.as_slice().split('@').last()
    }
    /// Returns the username
    pub fn user(&self) -> Option<&str> {
        self.mask.as_slice().split('@').nth(0).and_then(|v|
            v.split('!').last()
        )
    }
    /// Returns the nickname
    pub fn nick(&self) -> Option<&str> {
        self.mask.as_slice().split('!').nth(0)
    }

    /// Returns a view into the mask
    pub fn as_str(&self) -> &str {
        return self.mask.as_slice()
    }
}

#[cfg(test)]
mod tests {
	use super::{valid_nick, valid_channel, HostMask};
	#[test]
	/// Test the nickname validation function
	fn test_nickname_validation() {
		assert!(valid_nick("FooBar123"))
		assert_eq!(valid_nick("FooBar1234"), false)
		assert_eq!(valid_nick("1FooBar12"), false)
	}
	#[test]
	/// Test the nickname validation function
	fn test_channel_name_validation() {
		assert!(valid_channel("#Foobar"))
		assert_eq!(valid_channel("Foobar"), false)
		assert_eq!(valid_channel("#Foo,bar"), false)
		assert_eq!(valid_channel("Foo bar"), false)
	}

    #[test]
    /// Test the hostname masks
	fn test_masks() {
		assert!(HostMask::new("*!*@*.com".to_string()).matches("a!b@example.com"))
		assert!(!HostMask::new("*!*@*.com".to_string()).matches("*!*@*.edu"))
		assert!(!HostMask::new("*!*@*.com".to_string()).matches("*!*@*.cop"))
		assert!(!HostMask::new("*!*@*.com".to_string()).matches("*!*@*.coma"))
		assert!(HostMask::new("*!*@example.com".to_string()).matches("a!b@example.com"))
		assert!(HostMask::new("foo!*@*.com".to_string()).matches("foo!bar@example.com"))
		assert!(!HostMask::new("foo!*@*.com".to_string()).matches("baz!bar@example.com"))
		assert!(HostMask::new("*!bar@*.com".to_string()).matches("foo!bar@example.com"))
		assert!(!HostMask::new("*!bar@*.com".to_string()).matches("foo!baz@example.com"))
	}

}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Result as FmtResult};

/// Encode a string as xtext
pub struct XText<'a>(pub &'a str);

impl<'a> Display for XText<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let mut rest = self.0;
        while let Some(idx) = rest.find(|c| {
            c < '!' || c == '+' || c == '='
        }) {
            let (start, end) = rest.split_at(idx);
            f.write_str(start)?;

            let mut end_iter = end.char_indices();
            let (_, c) = end_iter.next().expect("char");
            write!(f, "+{:X}", c as u8)?;

            if let Some((idx, _)) = end_iter.next() {
                rest = &end[idx..];
            } else {
                rest = end;
            }
        }
        f.write_str(rest)
    }
}

#[cfg(test)]
mod tests {
    use util::{XText};

    #[test]
    fn test() {
        for (input, expect) in vec![
            ("bjorn", "bjorn"),
            ("bjørn", "bjørn"),
            ("Ø+= ❤‰", "Ø+2B+3D+20❤‰"),
        ] {
            assert_eq!(format!("{}", XText(input)), expect);
        }
    }
}
<commit_msg>Fix xtext encoder infinite loop.<commit_after>use std::fmt::{Display, Formatter, Result as FmtResult};

/// Encode a string as xtext
pub struct XText<'a>(pub &'a str);

impl<'a> Display for XText<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let mut rest = self.0;
        while let Some(idx) = rest.find(|c| {
            c < '!' || c == '+' || c == '='
        }) {
            let (start, end) = rest.split_at(idx);
            f.write_str(start)?;

            let mut end_iter = end.char_indices();
            let (_, c) = end_iter.next().expect("char");
            write!(f, "+{:X}", c as u8)?;

            if let Some((idx, _)) = end_iter.next() {
                rest = &end[idx..];
            } else {
                rest = "";
            }
        }
        f.write_str(rest)
    }
}

#[cfg(test)]
mod tests {
    use util::{XText};

    #[test]
    fn test() {
        for (input, expect) in vec![
            ("bjorn", "bjorn"),
            ("bjørn", "bjørn"),
            ("Ø+= ❤‰", "Ø+2B+3D+20❤‰"),
            ("+", "+2B"),
        ] {
            assert_eq!(format!("{}", XText(input)), expect);
        }
    }
}
<|endoftext|>


<commit_before>use vm::VmResult;
use internal::js::{JsObject, Value, ValueInternal, Object, build};
use internal::mem::Handle;
use internal::vm::{Lock, LockState};
use scope::Scope;
use neon_sys;
use neon_sys::raw;
use neon_sys::buf::Buf;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct JsBuffer(raw::Local);

impl JsBuffer {
    pub fn new<'a, T: Scope<'a>>(_: &mut T, size: u32) -> VmResult<Handle<'a, JsObject>> {
        build(|out| { unsafe { neon_sys::buffer::new(out, size) } })
    }
}

impl ValueInternal for JsBuffer {
    fn to_raw(self) -> raw::Local { self.0 }

    fn from_raw(h: raw::Local) -> Self { JsBuffer(h) }

    fn is_typeof<Other: Value>(other: Other) -> bool {
        unsafe { neon_sys::tag::is_buffer(other.to_raw()) }
    }
}

impl Value for JsBuffer { }

impl Object for JsBuffer { }

impl<'a> Lock for Handle<'a, JsBuffer> {
    type Internals = Buf<'a>;

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        let mut result = Buf::uninitialized();
        neon_sys::buffer::data(&mut result, self.to_raw());
        state.use_buffer(&result);
        result
    }
}
<commit_msg>oops: JsBuffer::new should return a JsBuffer, not a JsObject<commit_after>use vm::VmResult;
use internal::js::{JsObject, Value, ValueInternal, Object, build};
use internal::mem::Handle;
use internal::vm::{Lock, LockState};
use scope::Scope;
use neon_sys;
use neon_sys::raw;
use neon_sys::buf::Buf;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct JsBuffer(raw::Local);

impl JsBuffer {
    pub fn new<'a, T: Scope<'a>>(_: &mut T, size: u32) -> VmResult<Handle<'a, JsBuffer>> {
        build(|out| { unsafe { neon_sys::buffer::new(out, size) } })
    }
}

impl ValueInternal for JsBuffer {
    fn to_raw(self) -> raw::Local { self.0 }

    fn from_raw(h: raw::Local) -> Self { JsBuffer(h) }

    fn is_typeof<Other: Value>(other: Other) -> bool {
        unsafe { neon_sys::tag::is_buffer(other.to_raw()) }
    }
}

impl Value for JsBuffer { }

impl Object for JsBuffer { }

impl<'a> Lock for Handle<'a, JsBuffer> {
    type Internals = Buf<'a>;

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        let mut result = Buf::uninitialized();
        neon_sys::buffer::data(&mut result, self.to_raw());
        state.use_buffer(&result);
        result
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use config;
use config::parameter_matchable::ParameterMatchable;
use env::Env;
use library::{self, TypeId, ParameterScope};
use nameutil;
use super::conversion_type::ConversionType;
use super::rust_type::rust_type;
use super::ref_mode::RefMode;
use super::out_parameters::can_as_return;
use super::override_string_type::override_string_type_parameter;
use traits::IntoString;

//TODO: remove unused fields
#[derive(Clone, Debug)]
pub struct RustParameter {
    pub ind_c: usize, //index in `Vec<CParameter>`
    pub name: String,
    pub typ: TypeId,
    pub allow_none: bool,
}

#[derive(Clone, Debug)]
pub struct CParameter {
    pub name: String,
    pub typ: TypeId,
    pub c_type: String,
    pub instance_parameter: bool,
    pub direction: library::ParameterDirection,
    pub nullable: library::Nullable,
    pub transfer: library::Transfer,
    pub caller_allocates: bool,
    pub is_error: bool,
    pub scope: ParameterScope,
    /// Index of the user data parameter associated with the callback.
    pub user_data_index: Option<usize>,
    /// Index of the destroy notification parameter associated with the callback.
    pub destroy_index: Option<usize>,

    //analysis fields
    pub ref_mode: RefMode,
}

#[derive(Clone, Debug)]
pub enum TransformationType {
    ToGlibDirect { name: String },
    ToGlibScalar {
        name: String,
        nullable: library::Nullable,
    },
    ToGlibPointer {
        name: String,
        instance_parameter: bool,
        transfer: library::Transfer,
        ref_mode: RefMode,
        //filled by functions
        to_glib_extra: String,
        explicit_target_type: String,
        pointer_cast: String,
        in_trait: bool,
        nullable: bool,
    },
    ToGlibBorrow,
    ToGlibUnknown { name: String },
    Into { name: String },
    Length {
        array_name: String,
        array_length_name: String,
        array_length_type: String,
    },
    IntoRaw(String),
    ToSome(String),
}

impl TransformationType {
    pub fn is_to_glib(&self) -> bool {
        use self::TransformationType::*;
        match *self {
            ToGlibDirect { .. } |
            ToGlibScalar { .. } |
            ToGlibPointer { .. } |
            ToGlibBorrow |
            ToGlibUnknown { .. } |
            ToSome(_) |
            IntoRaw(_) => true,
            _ => false,
        }
    }

    pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) {
        if let TransformationType::ToGlibPointer {
            ref mut to_glib_extra,
            ..
        } = *self
        {
            *to_glib_extra = to_glib_extra_.to_owned();
        }
    }
}

#[derive(Clone, Debug)]
pub struct Transformation {
    pub ind_c: usize,            //index in `Vec<CParameter>`
    pub ind_rust: Option<usize>, //index in `Vec<RustParameter>`
    pub transformation_type: TransformationType,
}

#[derive(Clone, Default, Debug)]
pub struct Parameters {
    pub rust_parameters: Vec<RustParameter>,
    pub c_parameters: Vec<CParameter>,
    pub transformations: Vec<Transformation>,
}

impl Parameters {
    fn new(capacity: usize) -> Parameters {
        Parameters {
            rust_parameters: Vec::with_capacity(capacity),
            c_parameters: Vec::with_capacity(capacity),
            transformations: Vec::with_capacity(capacity),
        }
    }

    pub fn analyze_return(&mut self, env: &Env, ret: &Option<library::Parameter>) {
        let array_length = if let Some(array_length) = ret.as_ref().and_then(|r| r.array_length) {
            array_length
        } else {
            return;
        };

        let ind_c = array_length as usize;

        let par = if let Some(par) = self.c_parameters.get(ind_c) {
            par
        } else {
            return;
        };

        let transformation = Transformation {
            ind_c,
            ind_rust: None,
            transformation_type: get_length_type(env, "", &par.name, par.typ),
        };
        self.transformations.push(transformation);
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn analyze(
    env: &Env,
    function_parameters: &[library::Parameter],
    configured_functions: &[&config::functions::Function],
    disable_length_detect: bool,
    async_func: bool,
    in_trait: bool,
) -> Parameters {
    let mut parameters = Parameters::new(function_parameters.len());

    // Map: length argument position => array name
    let array_lengths: HashMap<u32, String> = function_parameters
        .iter()
        .filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
        .collect();

    for (pos, par) in function_parameters.iter().enumerate() {
        let name = if par.instance_parameter {
            par.name.clone()
        } else {
            nameutil::mangle_keywords(&*par.name).into_owned()
        };

        let configured_parameters = configured_functions.matched_parameters(&name);

        let c_type = par.c_type.clone();
        let typ = override_string_type_parameter(env, par.typ, &configured_parameters);

        let ind_c = parameters.c_parameters.len();
        let mut ind_rust = Some(parameters.rust_parameters.len());

        let mut add_rust_parameter = match par.direction {
            library::ParameterDirection::In | library::ParameterDirection::InOut => true,
            library::ParameterDirection::Return => false,
            library::ParameterDirection::Out => !can_as_return(env, par) && !async_func,
        };

        if async_func && async_param_to_remove(&par.name) {
            add_rust_parameter = false;
        }

        let mut array_name = configured_parameters
            .iter()
            .filter_map(|p| p.length_of.as_ref())
            .next();
        if array_name.is_none() {
            array_name = array_lengths.get(&(pos as u32))
        }
        if array_name.is_none() && !disable_length_detect {
            array_name = detect_length(env, pos, par, function_parameters);
        }
        if let Some(array_name) = array_name {
            let array_name = nameutil::mangle_keywords(&array_name[..]);
            add_rust_parameter = false;

            let transformation = Transformation {
                ind_c,
                ind_rust: None,
                transformation_type: get_length_type(env, &array_name, &par.name, typ),
            };
            parameters.transformations.push(transformation);
        }

        let mut caller_allocates = par.caller_allocates;
        let mut transfer = par.transfer;
        let conversion = ConversionType::of(env, typ);
        if conversion == ConversionType::Direct || conversion == ConversionType::Scalar {
            //For simply types no reason to have these flags
            caller_allocates = false;
            transfer = library::Transfer::None;
        }

        let immutable = configured_parameters.iter().any(|p| p.constant);
        let ref_mode = RefMode::without_unneeded_mut(env, par, immutable,
                                                     in_trait && par.instance_parameter);

        let nullable_override = configured_parameters
            .iter()
            .filter_map(|p| p.nullable)
            .next();
        let nullable = nullable_override.unwrap_or(par.nullable);

        let c_par = CParameter {
            name: name.clone(),
            typ,
            c_type,
            instance_parameter: par.instance_parameter,
            direction: par.direction,
            transfer,
            caller_allocates,
            nullable,
            ref_mode,
            is_error: par.is_error,
            scope: par.scope,
            user_data_index: par.closure,
            destroy_index: par.destroy,
        };
        parameters.c_parameters.push(c_par);

        let data_param_name = "user_data";
        let callback_param_name = "callback";

        let mut nullable_into = false;

        if add_rust_parameter {
            let rust_par = RustParameter {
                name: name.clone(),
                typ,
                ind_c,
                allow_none: par.allow_none,
            };
            parameters.rust_parameters.push(rust_par);

            if *nullable && is_into(env, par) && !(async_func && (name == data_param_name || name == callback_param_name)) {
                let transformation = Transformation {
                    ind_c,
                    ind_rust,
                    transformation_type: TransformationType::Into { name: name.clone() },
                };
                parameters.transformations.push(transformation);
                nullable_into = true;
            }
        } else {
            ind_rust = None;
        }

        let transformation_type = match ConversionType::of(env, typ) {
            ConversionType::Direct => TransformationType::ToGlibDirect { name },
            ConversionType::Scalar => TransformationType::ToGlibScalar {
                name,
                nullable,
            },
            ConversionType::Pointer => TransformationType::ToGlibPointer {
                name,
                instance_parameter: par.instance_parameter,
                transfer,
                ref_mode,
                to_glib_extra: String::new(),
                explicit_target_type: String::new(),
                pointer_cast: String::new(),
                in_trait,
                nullable: nullable_into,
            },
            ConversionType::Borrow => TransformationType::ToGlibBorrow,
            ConversionType::Unknown => TransformationType::ToGlibUnknown { name },
        };

        let mut transformation = Transformation {
            ind_c,
            ind_rust,
            transformation_type,
        };
        let mut transformation_type = None;
        match transformation.transformation_type {
            TransformationType::ToGlibDirect { ref name, .. } |
            TransformationType::ToGlibUnknown { ref name, .. } => {
                if async_func && name == callback_param_name {
                    // Remove the conversion of callback for async functions.
                    transformation_type = Some(TransformationType::ToSome(name.clone()));
                }
            }
            TransformationType::ToGlibPointer { ref name, .. } => {
                if async_func && name == data_param_name {
                    // Do the conversion of user_data for async functions.
                    // In async functions, this argument is used to send the callback.
                    transformation_type = Some(TransformationType::IntoRaw(name.clone()));
                }
            }
            _ => (),
        }
        if let Some(transformation_type) = transformation_type {
            transformation.transformation_type = transformation_type;
        }
        parameters.transformations.push(transformation);
    }

    parameters
}

fn is_into(env: &Env, par: &library::Parameter) -> bool {
    fn is_into_inner(env: &Env, par: &library::Type) -> bool {
        match *par {
            library::Type::Fundamental(fund) => match fund {
                library::Fundamental::Utf8 | library::Fundamental::Type => true,
                _ => false,
            },
            library::Type::List(_) | library::Type::SList(_) | library::Type::CArray(_) => false,
            library::Type::Alias(ref alias) => is_into_inner(env, env.library.type_(alias.typ)),
            _ => true,
        }
    }
    !par.instance_parameter && is_into_inner(env, env.library.type_(par.typ))
}

fn get_length_type(
    env: &Env,
    array_name: &str,
    length_name: &str,
    length_typ: TypeId,
) -> TransformationType {
    let array_length_type = rust_type(env, length_typ).into_string();
    TransformationType::Length {
        array_name: array_name.to_string(),
        array_length_name: length_name.to_string(),
        array_length_type,
    }
}

fn detect_length<'a>(
    env: &Env,
    pos: usize,
    par: &library::Parameter,
    parameters: &'a [library::Parameter],
) -> Option<&'a String> {
    if !is_length(par) {
        return None;
    }

    let array = parameters
        .get(pos - 1)
        .and_then(|p| if has_length(env, p.typ) {
            Some(p)
        } else {
            None
        });
    array.map(|p| &p.name)
}

fn is_length(par: &library::Parameter) -> bool {
    if par.direction != library::ParameterDirection::In {
        return false;
    }

    let len = par.name.len();
    if len >= 3 && &par.name[len - 3..len] == "len" {
        return true;
    }
    if par.name.find("length").is_some() {
        return true;
    }

    false
}

fn has_length(env: &Env, typ: TypeId) -> bool {
    use library::Type;
    let typ = env.library.type_(typ);
    match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            match fund {
                Utf8 => true,
                Filename => true,
                OsString => true,
                _ => false,
            }
        }
        Type::CArray(..) |
        Type::FixedArray(..) |
        Type::Array(..) |
        Type::PtrArray(..) |
        Type::List(..) |
        Type::SList(..) |
        Type::HashTable(..) => true,
        Type::Alias(ref alias) => has_length(env, alias.typ),
        _ => false,
    }
}

pub fn async_param_to_remove(name: &str) -> bool {
    name == "user_data" || name.ends_with("data") // FIXME: use async indexes instead
}
<commit_msg>No more into for user callbacks<commit_after>use std::collections::HashMap;

use config;
use config::parameter_matchable::ParameterMatchable;
use env::Env;
use library::{self, TypeId, ParameterScope};
use nameutil;
use super::conversion_type::ConversionType;
use super::rust_type::rust_type;
use super::ref_mode::RefMode;
use super::out_parameters::can_as_return;
use super::override_string_type::override_string_type_parameter;
use traits::IntoString;

//TODO: remove unused fields
#[derive(Clone, Debug)]
pub struct RustParameter {
    pub ind_c: usize, //index in `Vec<CParameter>`
    pub name: String,
    pub typ: TypeId,
    pub allow_none: bool,
}

#[derive(Clone, Debug)]
pub struct CParameter {
    pub name: String,
    pub typ: TypeId,
    pub c_type: String,
    pub instance_parameter: bool,
    pub direction: library::ParameterDirection,
    pub nullable: library::Nullable,
    pub transfer: library::Transfer,
    pub caller_allocates: bool,
    pub is_error: bool,
    pub scope: ParameterScope,
    /// Index of the user data parameter associated with the callback.
    pub user_data_index: Option<usize>,
    /// Index of the destroy notification parameter associated with the callback.
    pub destroy_index: Option<usize>,

    //analysis fields
    pub ref_mode: RefMode,
}

#[derive(Clone, Debug)]
pub enum TransformationType {
    ToGlibDirect { name: String },
    ToGlibScalar {
        name: String,
        nullable: library::Nullable,
    },
    ToGlibPointer {
        name: String,
        instance_parameter: bool,
        transfer: library::Transfer,
        ref_mode: RefMode,
        //filled by functions
        to_glib_extra: String,
        explicit_target_type: String,
        pointer_cast: String,
        in_trait: bool,
        nullable: bool,
    },
    ToGlibBorrow,
    ToGlibUnknown { name: String },
    Into { name: String },
    Length {
        array_name: String,
        array_length_name: String,
        array_length_type: String,
    },
    IntoRaw(String),
    ToSome(String),
}

impl TransformationType {
    pub fn is_to_glib(&self) -> bool {
        use self::TransformationType::*;
        match *self {
            ToGlibDirect { .. } |
            ToGlibScalar { .. } |
            ToGlibPointer { .. } |
            ToGlibBorrow |
            ToGlibUnknown { .. } |
            ToSome(_) |
            IntoRaw(_) => true,
            _ => false,
        }
    }

    pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) {
        if let TransformationType::ToGlibPointer {
            ref mut to_glib_extra,
            ..
        } = *self
        {
            *to_glib_extra = to_glib_extra_.to_owned();
        }
    }
}

#[derive(Clone, Debug)]
pub struct Transformation {
    pub ind_c: usize,            //index in `Vec<CParameter>`
    pub ind_rust: Option<usize>, //index in `Vec<RustParameter>`
    pub transformation_type: TransformationType,
}

#[derive(Clone, Default, Debug)]
pub struct Parameters {
    pub rust_parameters: Vec<RustParameter>,
    pub c_parameters: Vec<CParameter>,
    pub transformations: Vec<Transformation>,
}

impl Parameters {
    fn new(capacity: usize) -> Parameters {
        Parameters {
            rust_parameters: Vec::with_capacity(capacity),
            c_parameters: Vec::with_capacity(capacity),
            transformations: Vec::with_capacity(capacity),
        }
    }

    pub fn analyze_return(&mut self, env: &Env, ret: &Option<library::Parameter>) {
        let array_length = if let Some(array_length) = ret.as_ref().and_then(|r| r.array_length) {
            array_length
        } else {
            return;
        };

        let ind_c = array_length as usize;

        let par = if let Some(par) = self.c_parameters.get(ind_c) {
            par
        } else {
            return;
        };

        let transformation = Transformation {
            ind_c,
            ind_rust: None,
            transformation_type: get_length_type(env, "", &par.name, par.typ),
        };
        self.transformations.push(transformation);
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn analyze(
    env: &Env,
    function_parameters: &[library::Parameter],
    configured_functions: &[&config::functions::Function],
    disable_length_detect: bool,
    async_func: bool,
    in_trait: bool,
) -> Parameters {
    let mut parameters = Parameters::new(function_parameters.len());

    // Map: length argument position => array name
    let array_lengths: HashMap<u32, String> = function_parameters
        .iter()
        .filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
        .collect();

    for (pos, par) in function_parameters.iter().enumerate() {
        let name = if par.instance_parameter {
            par.name.clone()
        } else {
            nameutil::mangle_keywords(&*par.name).into_owned()
        };

        let configured_parameters = configured_functions.matched_parameters(&name);

        let c_type = par.c_type.clone();
        let typ = override_string_type_parameter(env, par.typ, &configured_parameters);

        let ind_c = parameters.c_parameters.len();
        let mut ind_rust = Some(parameters.rust_parameters.len());

        let mut add_rust_parameter = match par.direction {
            library::ParameterDirection::In | library::ParameterDirection::InOut => true,
            library::ParameterDirection::Return => false,
            library::ParameterDirection::Out => !can_as_return(env, par) && !async_func,
        };

        if async_func && async_param_to_remove(&par.name) {
            add_rust_parameter = false;
        }

        let mut array_name = configured_parameters
            .iter()
            .filter_map(|p| p.length_of.as_ref())
            .next();
        if array_name.is_none() {
            array_name = array_lengths.get(&(pos as u32))
        }
        if array_name.is_none() && !disable_length_detect {
            array_name = detect_length(env, pos, par, function_parameters);
        }
        if let Some(array_name) = array_name {
            let array_name = nameutil::mangle_keywords(&array_name[..]);
            add_rust_parameter = false;

            let transformation = Transformation {
                ind_c,
                ind_rust: None,
                transformation_type: get_length_type(env, &array_name, &par.name, typ),
            };
            parameters.transformations.push(transformation);
        }

        let mut caller_allocates = par.caller_allocates;
        let mut transfer = par.transfer;
        let conversion = ConversionType::of(env, typ);
        if conversion == ConversionType::Direct || conversion == ConversionType::Scalar {
            //For simply types no reason to have these flags
            caller_allocates = false;
            transfer = library::Transfer::None;
        }

        let immutable = configured_parameters.iter().any(|p| p.constant);
        let ref_mode = RefMode::without_unneeded_mut(env, par, immutable,
                                                     in_trait && par.instance_parameter);

        let nullable_override = configured_parameters
            .iter()
            .filter_map(|p| p.nullable)
            .next();
        let nullable = nullable_override.unwrap_or(par.nullable);

        let c_par = CParameter {
            name: name.clone(),
            typ,
            c_type,
            instance_parameter: par.instance_parameter,
            direction: par.direction,
            transfer,
            caller_allocates,
            nullable,
            ref_mode,
            is_error: par.is_error,
            scope: par.scope,
            user_data_index: par.closure,
            destroy_index: par.destroy,
        };
        parameters.c_parameters.push(c_par);

        let data_param_name = "user_data";
        let callback_param_name = "callback";

        let mut nullable_into = false;

        if add_rust_parameter {
            let rust_par = RustParameter {
                name: name.clone(),
                typ,
                ind_c,
                allow_none: par.allow_none,
            };
            parameters.rust_parameters.push(rust_par);

            if *nullable && is_into(env, par) && !env.library.type_(par.typ).is_function() &&
               !(async_func && (name == data_param_name || name == callback_param_name)) {
                let transformation = Transformation {
                    ind_c,
                    ind_rust,
                    transformation_type: TransformationType::Into { name: name.clone() },
                };
                parameters.transformations.push(transformation);
                nullable_into = true;
            }
        } else {
            ind_rust = None;
        }

        let transformation_type = match ConversionType::of(env, typ) {
            ConversionType::Direct => TransformationType::ToGlibDirect { name },
            ConversionType::Scalar => TransformationType::ToGlibScalar {
                name,
                nullable,
            },
            ConversionType::Pointer => TransformationType::ToGlibPointer {
                name,
                instance_parameter: par.instance_parameter,
                transfer,
                ref_mode,
                to_glib_extra: String::new(),
                explicit_target_type: String::new(),
                pointer_cast: String::new(),
                in_trait,
                nullable: nullable_into,
            },
            ConversionType::Borrow => TransformationType::ToGlibBorrow,
            ConversionType::Unknown => TransformationType::ToGlibUnknown { name },
        };

        let mut transformation = Transformation {
            ind_c,
            ind_rust,
            transformation_type,
        };
        let mut transformation_type = None;
        match transformation.transformation_type {
            TransformationType::ToGlibDirect { ref name, .. } |
            TransformationType::ToGlibUnknown { ref name, .. } => {
                if async_func && name == callback_param_name {
                    // Remove the conversion of callback for async functions.
                    transformation_type = Some(TransformationType::ToSome(name.clone()));
                }
            }
            TransformationType::ToGlibPointer { ref name, .. } => {
                if async_func && name == data_param_name {
                    // Do the conversion of user_data for async functions.
                    // In async functions, this argument is used to send the callback.
                    transformation_type = Some(TransformationType::IntoRaw(name.clone()));
                }
            }
            _ => (),
        }
        if let Some(transformation_type) = transformation_type {
            transformation.transformation_type = transformation_type;
        }
        parameters.transformations.push(transformation);
    }

    parameters
}

fn is_into(env: &Env, par: &library::Parameter) -> bool {
    fn is_into_inner(env: &Env, par: &library::Type) -> bool {
        match *par {
            library::Type::Fundamental(fund) => match fund {
                library::Fundamental::Utf8 | library::Fundamental::Type => true,
                _ => false,
            },
            library::Type::List(_) | library::Type::SList(_) | library::Type::CArray(_) => false,
            library::Type::Alias(ref alias) => is_into_inner(env, env.library.type_(alias.typ)),
            _ => true,
        }
    }
    !par.instance_parameter && is_into_inner(env, env.library.type_(par.typ))
}

fn get_length_type(
    env: &Env,
    array_name: &str,
    length_name: &str,
    length_typ: TypeId,
) -> TransformationType {
    let array_length_type = rust_type(env, length_typ).into_string();
    TransformationType::Length {
        array_name: array_name.to_string(),
        array_length_name: length_name.to_string(),
        array_length_type,
    }
}

fn detect_length<'a>(
    env: &Env,
    pos: usize,
    par: &library::Parameter,
    parameters: &'a [library::Parameter],
) -> Option<&'a String> {
    if !is_length(par) {
        return None;
    }

    let array = parameters
        .get(pos - 1)
        .and_then(|p| if has_length(env, p.typ) {
            Some(p)
        } else {
            None
        });
    array.map(|p| &p.name)
}

fn is_length(par: &library::Parameter) -> bool {
    if par.direction != library::ParameterDirection::In {
        return false;
    }

    let len = par.name.len();
    if len >= 3 && &par.name[len - 3..len] == "len" {
        return true;
    }
    if par.name.find("length").is_some() {
        return true;
    }

    false
}

fn has_length(env: &Env, typ: TypeId) -> bool {
    use library::Type;
    let typ = env.library.type_(typ);
    match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            match fund {
                Utf8 => true,
                Filename => true,
                OsString => true,
                _ => false,
            }
        }
        Type::CArray(..) |
        Type::FixedArray(..) |
        Type::Array(..) |
        Type::PtrArray(..) |
        Type::List(..) |
        Type::SList(..) |
        Type::HashTable(..) => true,
        Type::Alias(ref alias) => has_length(env, alias.typ),
        _ => false,
    }
}

pub fn async_param_to_remove(name: &str) -> bool {
    name == "user_data" || name.ends_with("data") // FIXME: use async indexes instead
}
<|endoftext|>


<commit_before>use matching_brackets::brackets_are_balanced;

#[test]
fn paired_square_brackets() {
    assert!(brackets_are_balanced("[]"));
}

#[test]
#[ignore]
fn empty_string() {
    assert!(brackets_are_balanced(""));
}

#[test]
#[ignore]
fn unpaired_brackets() {
    assert!(!brackets_are_balanced("[["));
}

#[test]
#[ignore]
fn wrong_ordered_brackets() {
    assert!(!brackets_are_balanced("}{"));
}

#[test]
#[ignore]
fn wrong_closing_bracket() {
    assert!(!brackets_are_balanced("{]"));
}

#[test]
#[ignore]
fn paired_with_whitespace() {
    assert!(brackets_are_balanced("{ }"));
}

#[test]
#[ignore]
fn partially_paired_brackets() {
    assert!(!brackets_are_balanced("{[])"));
}

#[test]
#[ignore]
fn simple_nested_brackets() {
    assert!(brackets_are_balanced("{[]}"));
}

#[test]
#[ignore]
fn several_paired_brackets() {
    assert!(brackets_are_balanced("{}[]"));
}

#[test]
#[ignore]
fn paired_and_nested_brackets() {
    assert!(brackets_are_balanced("([{}({}[])])"));
}

#[test]
#[ignore]
fn unopened_closing_brackets() {
    assert!(!brackets_are_balanced("{[)][]}"));
}

#[test]
#[ignore]
fn unpaired_and_nested_brackets() {
    assert!(!brackets_are_balanced("([{])"));
}

#[test]
#[ignore]
fn paired_and_wrong_nested_brackets() {
    assert!(!brackets_are_balanced("[({]})"));
}

#[test]
#[ignore]
fn paired_and_incomplete_brackets() {
    assert!(!brackets_are_balanced("{}["));
}

#[test]
#[ignore]
fn too_many_closing_brackets() {
    assert!(!brackets_are_balanced("[]]"));
}

#[test]
#[ignore]
fn math_expression() {
    assert!(brackets_are_balanced("(((185 + 223.85) * 15) - 543)/2"));
}

#[test]
#[ignore]
fn complex_latex_expression() {
    let input = "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \
                 \\end{array}\\right)";
    assert!(brackets_are_balanced(input));
}
<commit_msg>Add testcases to matching brackets (#946)<commit_after>use matching_brackets::brackets_are_balanced;

#[test]
fn paired_square_brackets() {
    assert!(brackets_are_balanced("[]"));
}

#[test]
#[ignore]
fn empty_string() {
    assert!(brackets_are_balanced(""));
}

#[test]
#[ignore]
fn unpaired_brackets() {
    assert!(!brackets_are_balanced("[["));
}

#[test]
#[ignore]
fn wrong_ordered_brackets() {
    assert!(!brackets_are_balanced("}{"));
}

#[test]
#[ignore]
fn wrong_closing_bracket() {
    assert!(!brackets_are_balanced("{]"));
}

#[test]
#[ignore]
fn paired_with_whitespace() {
    assert!(brackets_are_balanced("{ }"));
}

#[test]
#[ignore]
fn partially_paired_brackets() {
    assert!(!brackets_are_balanced("{[])"));
}

#[test]
#[ignore]
fn simple_nested_brackets() {
    assert!(brackets_are_balanced("{[]}"));
}

#[test]
#[ignore]
fn several_paired_brackets() {
    assert!(brackets_are_balanced("{}[]"));
}

#[test]
#[ignore]
fn paired_and_nested_brackets() {
    assert!(brackets_are_balanced("([{}({}[])])"));
}

#[test]
#[ignore]
fn unopened_closing_brackets() {
    assert!(!brackets_are_balanced("{[)][]}"));
}

#[test]
#[ignore]
fn unpaired_and_nested_brackets() {
    assert!(!brackets_are_balanced("([{])"));
}

#[test]
#[ignore]
fn paired_and_wrong_nested_brackets() {
    assert!(!brackets_are_balanced("[({]})"));
}

#[test]
#[ignore]
fn paired_and_incomplete_brackets() {
    assert!(!brackets_are_balanced("{}["));
}

#[test]
#[ignore]
fn too_many_closing_brackets() {
    assert!(!brackets_are_balanced("[]]"));
}

#[test]
#[ignore]
fn early_incomplete_brackets() {
    assert!(!brackets_are_balanced(")()"));
}

#[test]
#[ignore]
fn early_mismatched_brackets() {
    assert!(!brackets_are_balanced("{)()"));
}

#[test]
#[ignore]
fn math_expression() {
    assert!(brackets_are_balanced("(((185 + 223.85) * 15) - 543)/2"));
}

#[test]
#[ignore]
fn complex_latex_expression() {
    let input = "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \
                 \\end{array}\\right)";
    assert!(brackets_are_balanced(input));
}
<|endoftext|>


<commit_before>//! Tests for rail-fence-cipher
//!
//! Generated by [script][script] using [canonical data][canonical-data]
//!
//! [script]: https://github.com/exercism/rust/blob/master/bin/init_exercise.py
//! [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/rail-fence-cipher/canonical_data.json
//!
//! The tests do not expect any normalization or cleaning.
//! That trade is tested in enough other exercises.

use rail_fence_cipher::*;

/// Process a single test case for the property `encode`
///
/// All cases for the `encode` property are implemented
/// in terms of this function.
fn process_encode_case(input: &str, rails: u32, expected: &str) {
    let rail_fence = RailFence::new(rails);
    assert_eq!(rail_fence.encode(input), expected);
}

/// Process a single test case for the property `decode`
///
/// All cases for the `decode` property are implemented
/// in terms of this function.
fn process_decode_case(input: &str, rails: u32, expected: &str) {
    let rail_fence = RailFence::new(rails);
    assert_eq!(rail_fence.decode(input), expected);
}

// encode

#[test]
/// encode with two rails
fn test_encode_with_two_rails() {
    process_encode_case("XOXOXOXOXOXOXOXOXO", 2, "XXXXXXXXXOOOOOOOOO");
}

#[test]
#[ignore]
/// encode with three rails
fn test_encode_with_three_rails() {
    process_encode_case("WEAREDISCOVEREDFLEEATONCE", 3, "WECRLTEERDSOEEFEAOCAIVDEN");
}

#[test]
#[ignore]
/// encode with ending in the middle
fn test_encode_with_ending_in_the_middle() {
    process_encode_case("EXERCISES", 4, "ESXIEECSR");
}

// decode

#[test]
#[ignore]
/// decode with three rails
fn test_decode_with_three_rails() {
    process_decode_case("TEITELHDVLSNHDTISEIIEA", 3, "THEDEVILISINTHEDETAILS");
}

#[test]
#[ignore]
/// decode with five rails
fn test_decode_with_five_rails() {
    process_decode_case("EIEXMSMESAORIWSCE", 5, "EXERCISMISAWESOME");
}

#[test]
#[ignore]
/// decode with six rails
fn test_decode_with_six_rails() {
    process_decode_case(
        "133714114238148966225439541018335470986172518171757571896261",
        6,
        "112358132134558914423337761098715972584418167651094617711286",
    );
}

#[test]
#[ignore]
/// encode wide characters
///
/// normally unicode is not part of exercism exercises, but in an exercise
/// specifically oriented around shuffling characters, it seems worth ensuring
/// that wide characters are handled properly
///
/// this text is possibly one of the most famous haiku of all time, by
/// Matsuo Bashō (松尾芭蕉)
fn test_encode_wide_characters() {
    process_encode_case(
        "古池 蛙飛び込む 水の音",
        3,
        "古飛 池蛙びむ水音 込の",
    );
}
<commit_msg>rail fence cipher: remove spaces from wide char test<commit_after>//! Tests for rail-fence-cipher
//!
//! Generated by [script][script] using [canonical data][canonical-data]
//!
//! [script]: https://github.com/exercism/rust/blob/master/bin/init_exercise.py
//! [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/rail-fence-cipher/canonical_data.json
//!
//! The tests do not expect any normalization or cleaning.
//! That trade is tested in enough other exercises.

use rail_fence_cipher::*;

/// Process a single test case for the property `encode`
///
/// All cases for the `encode` property are implemented
/// in terms of this function.
fn process_encode_case(input: &str, rails: u32, expected: &str) {
    let rail_fence = RailFence::new(rails);
    assert_eq!(rail_fence.encode(input), expected);
}

/// Process a single test case for the property `decode`
///
/// All cases for the `decode` property are implemented
/// in terms of this function.
fn process_decode_case(input: &str, rails: u32, expected: &str) {
    let rail_fence = RailFence::new(rails);
    assert_eq!(rail_fence.decode(input), expected);
}

// encode

#[test]
/// encode with two rails
fn test_encode_with_two_rails() {
    process_encode_case("XOXOXOXOXOXOXOXOXO", 2, "XXXXXXXXXOOOOOOOOO");
}

#[test]
#[ignore]
/// encode with three rails
fn test_encode_with_three_rails() {
    process_encode_case("WEAREDISCOVEREDFLEEATONCE", 3, "WECRLTEERDSOEEFEAOCAIVDEN");
}

#[test]
#[ignore]
/// encode with ending in the middle
fn test_encode_with_ending_in_the_middle() {
    process_encode_case("EXERCISES", 4, "ESXIEECSR");
}

// decode

#[test]
#[ignore]
/// decode with three rails
fn test_decode_with_three_rails() {
    process_decode_case("TEITELHDVLSNHDTISEIIEA", 3, "THEDEVILISINTHEDETAILS");
}

#[test]
#[ignore]
/// decode with five rails
fn test_decode_with_five_rails() {
    process_decode_case("EIEXMSMESAORIWSCE", 5, "EXERCISMISAWESOME");
}

#[test]
#[ignore]
/// decode with six rails
fn test_decode_with_six_rails() {
    process_decode_case(
        "133714114238148966225439541018335470986172518171757571896261",
        6,
        "112358132134558914423337761098715972584418167651094617711286",
    );
}

#[test]
#[ignore]
/// encode wide characters
///
/// normally unicode is not part of exercism exercises, but in an exercise
/// specifically oriented around shuffling characters, it seems worth ensuring
/// that wide characters are handled properly
///
/// this text is possibly one of the most famous haiku of all time, by
/// Matsuo Bashō (松尾芭蕉)
fn test_encode_wide_characters() {
    process_encode_case(
        "古池蛙飛び込む水の音",
        3,
        "古びの池飛込水音蛙む",
    );
}
<|endoftext|>