<commit_before>use std::collections::HashMap;
use termion::event::Key;

const DEFAULT_KEYBINDS: &'static str = r#"^Q: Quit
^W: CloseFile
^O: OpenFile
^S: SaveFile
^X: Cut
^C: Copy
^V: Paste
^F: Find
^H: FindReplace
"#;

macro_attr! {
    #[derive(Clone, EnumDisplay!, EnumFromStr!)]
    pub enum Command {
        Quit,
        CloseFile,
        OpenFile,
        SaveFile,
        Cut,
        Copy,
        Paste,
        Find,
        FindReplace
    }
}

pub struct KeybindTable {
    table: HashMap<Key, Command>
}

impl KeybindTable {
    pub fn lookup(&self, key: Key) -> Option<Command> {
        self.table.get(&key).cloned()
    }

    pub fn entries(&self) -> Vec<(String, String)> {
        self.table.iter().map(|(key, command)| {
            let key = match key {
                &Key::Ctrl(k) => format!("^{}", k).to_uppercase(),
                _ => String::from("???")
            };
            (key, format!("{}", command))
        }).collect()
    }
}

impl Default for KeybindTable {
    fn default() -> Self {
        Self::from(DEFAULT_KEYBINDS)
    }
}

fn decode_key_spec(spec: &str) -> Option<Key> {
    if spec.len() != 2 {
        println!("Bad key specifier: {}", spec);
        return None;
    }
    let (modifier, key) = spec.split_at(1);
    let modifier = modifier.chars().next().unwrap();
    let key = key.chars().next().unwrap();
    if modifier != '^' {
        println!("Bad key specifier: {}", spec);
        return None;
    }
    Some(Key::Ctrl(key))
}

impl<'a> From<&'a str> for KeybindTable {
    fn from(text: &'a str) -> Self {
        let mut result = KeybindTable {
            table: HashMap::new()
        };
        for line in text.lines() {
            let data: Vec<_> = line.split(": ").collect();
            if data.len() != 2 {
                println!("Bad keybind specifier: {}", line);
                continue
            }
            if let Ok(command) = data[1].parse::<Command>() {
                let key_spec = data[0].to_lowercase();
                match decode_key_spec(&key_spec) {
                    Some(key) => {
                        result.table.insert(key, command);
                    },
                    _ => {}
                }
            } else {
                println!("Bad command: {}", data[1]);
            }
        }
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn keybind_parsing_works() {
        let keys = KeybindTable::from("^Q: Quit");
        match keys.lookup(Key::Ctrl('q')) {
            Some(Command::Quit) => (),
            _ => panic!("Looking up ^Q failed!")
        }
        match keys.lookup(Key::Ctrl('x')) {
            None => (),
            _ => panic!("Looking up ^X succeeded!")
        }
        let keys = KeybindTable::from("^X: Quit");
        match keys.lookup(Key::Ctrl('x')) {
            Some(Command::Quit) => (),
            _ => panic!("Looking up ^X failed!")
        }
        match keys.lookup(Key::Ctrl('q')) {
            None => (),
            _ => panic!("Looking up ^Q succeeded!")
        }
    }
}
<commit_msg>Add more default keybinds I forgot about<commit_after>use std::collections::HashMap;
use termion::event::Key;

const DEFAULT_KEYBINDS: &'static str = r#"^Q: Quit
^W: CloseFile
^O: OpenFile
^S: SaveFile
^X: Cut
^C: Copy
^V: Paste
^F: Find
^H: FindReplace
^Z: Undo
^Y: Redo
"#;

macro_attr! {
    #[derive(Clone, EnumDisplay!, EnumFromStr!)]
    pub enum Command {
        Quit,
        CloseFile,
        OpenFile,
        SaveFile,
        Cut,
        Copy,
        Paste,
        Find,
        FindReplace,
        Undo,
        Redo
    }
}

pub struct KeybindTable {
    table: HashMap<Key, Command>
}

impl KeybindTable {
    pub fn lookup(&self, key: Key) -> Option<Command> {
        self.table.get(&key).cloned()
    }

    pub fn entries(&self) -> Vec<(String, String)> {
        self.table.iter().map(|(key, command)| {
            let key = match key {
                &Key::Ctrl(k) => format!("^{}", k).to_uppercase(),
                _ => String::from("???")
            };
            (key, format!("{}", command))
        }).collect()
    }
}

impl Default for KeybindTable {
    fn default() -> Self {
        Self::from(DEFAULT_KEYBINDS)
    }
}

fn decode_key_spec(spec: &str) -> Option<Key> {
    if spec.len() != 2 {
        println!("Bad key specifier: {}", spec);
        return None;
    }
    let (modifier, key) = spec.split_at(1);
    let modifier = modifier.chars().next().unwrap();
    let key = key.chars().next().unwrap();
    if modifier != '^' {
        println!("Bad key specifier: {}", spec);
        return None;
    }
    Some(Key::Ctrl(key))
}

impl<'a> From<&'a str> for KeybindTable {
    fn from(text: &'a str) -> Self {
        let mut result = KeybindTable {
            table: HashMap::new()
        };
        for line in text.lines() {
            let data: Vec<_> = line.split(": ").collect();
            if data.len() != 2 {
                println!("Bad keybind specifier: {}", line);
                continue
            }
            if let Ok(command) = data[1].parse::<Command>() {
                let key_spec = data[0].to_lowercase();
                match decode_key_spec(&key_spec) {
                    Some(key) => {
                        result.table.insert(key, command);
                    },
                    _ => {}
                }
            } else {
                println!("Bad command: {}", data[1]);
            }
        }
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn keybind_parsing_works() {
        let keys = KeybindTable::from("^Q: Quit");
        match keys.lookup(Key::Ctrl('q')) {
            Some(Command::Quit) => (),
            _ => panic!("Looking up ^Q failed!")
        }
        match keys.lookup(Key::Ctrl('x')) {
            None => (),
            _ => panic!("Looking up ^X succeeded!")
        }
        let keys = KeybindTable::from("^X: Quit");
        match keys.lookup(Key::Ctrl('x')) {
            Some(Command::Quit) => (),
            _ => panic!("Looking up ^X failed!")
        }
        match keys.lookup(Key::Ctrl('q')) {
            None => (),
            _ => panic!("Looking up ^Q succeeded!")
        }
    }
}
<|endoftext|>


<commit_before>//! Languages we can hyphenate and their default parameters, as provided by
//! the TeX `hyph-utf8` package.

#![allow(non_camel_case_types)]

use exception::{Exceptions};
use pattern::{Patterns};

/// A `Corpus` carries hyphenation data and parameters.
///
/// It comprises the working language, the set of applicable patterns and
/// exceptions, as well as the left and right intra-word hyphenation boundaries.
#[derive(Clone, Debug)]
pub struct Corpus {
    pub language: Language,
    pub patterns: Patterns,
    pub exceptions: Option<Exceptions>,
    pub left_min: usize,
    pub right_min: usize
}

use self::Language::*;

/// The set of available languages.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Language {
    Afrikaans,
    Armenian,
    Assamese,
    Basque,
    Bengali,
    Bulgarian,
    Catalan,
    Chinese,
    Coptic,
    Croatian,
    Czech,
    Danish,
    Dutch,
    English_GB,
    English_US,
    Esperanto,
    Estonian,
    Ethiopic,
    Finnish,
    French,
    Friulan,
    Galician,
    Georgian,
    German_1901,
    German_1996,
    German_Swiss,
    Greek_Ancient,
    Greek_Mono,
    Greek_Poly,
    Gujarati,
    Hindi,
    Hungarian,
    Icelandic,
    Indonesian,
    Interlingua,
    Irish,
    Italian,
    Kannada,
    Kurmanji,
    Latin_Classic,
    Latin,
    Latvian,
    Lithuanian,
    Malayalam,
    Marathi,
    Mongolian,
    Norwegian_Bokmal,
    Norwegian_Nynorsk,
    Occitan,
    Oriya,
    Panjabi,
    Piedmontese,
    Polish,
    Portuguese,
    Romanian,
    Romansh,
    Russian,
    Sanskrit,
    Serbian_Cyrillic,
    Serbocroatian_Cyrillic,
    Serbocroatian_Latin,
    Slavonic_Church,
    Slovak,
    Slovenian,
    Spanish,
    Swedish,
    Tamil,
    Telugu,
    Thai,
    Turkish,
    Turkmen,
    Ukrainian,
    Uppersorbian,
    Welsh
}

/// The TeX tag for a given language.
pub fn tag(lang: Language) -> &'static str {
    match lang {
        Afrikaans => "af",
        Armenian => "hy",
        Assamese => "as",
        Basque => "eu",
        Bengali => "bn",
        Bulgarian => "bg",
        Catalan => "ca",
        Chinese => "zh-latn-pinyin",
        Coptic => "cop",
        Croatian => "hr",
        Czech => "cs",
        Danish => "da",
        Dutch => "nl",
        English_GB => "en-gb",
        English_US => "en-us",
        Esperanto => "eo",
        Estonian => "et",
        Ethiopic => "mul-ethi",
        Finnish => "fi",
        French => "fr",
        Friulan => "fur",
        Galician => "gl",
        Georgian => "ka",
        German_1901  => "de-1901",
        German_1996  => "de-1996",
        German_Swiss => "de-ch-1901",
        Greek_Ancient => "grc",
        Greek_Mono => "el-monoton",
        Greek_Poly => "el-polyton",
        Gujarati => "gu",
        Hindi => "hi",
        Hungarian => "hu",
        Icelandic => "is",
        Indonesian => "id",
        Interlingua => "ia",
        Irish => "ga",
        Italian => "it",
        Kannada => "kn",
        Kurmanji => "kmr",
        Latin => "la",
        Latin_Classic => "la-x-classic",
        Latvian => "lv",
        Lithuanian => "lt",
        Malayalam => "ml",
        Marathi => "mr",
        Mongolian => "mn-cyrl",
        Norwegian_Bokmal  => "nb",
        Norwegian_Nynorsk => "nn",
        Occitan => "oc",
        Oriya => "or",
        Panjabi => "pa",
        Piedmontese => "pms",
        Polish => "pl",
        Portuguese => "pt",
        Romanian => "ro",
        Romansh => "rm",
        Russian => "ru",
        Sanskrit => "sa",
        Serbian_Cyrillic => "sr-cyrl",
        Serbocroatian_Cyrillic => "sh-cyrl",
        Serbocroatian_Latin => "sh-latn",
        Slavonic_Church => "cu",
        Slovak => "sk",
        Slovenian => "sl",
        Spanish => "es",
        Swedish => "sv",
        Tamil => "ta",
        Telugu => "te",
        Thai => "th",
        Turkish => "tr",
        Turkmen => "tk",
        Ukrainian => "uk",
        Uppersorbian => "hsb",
        Welsh => "cy"
    }
}

/// The default number of characters from the start and end of a word
/// which shall not be hyphenated.
pub fn mins(lang: Language) -> (usize, usize) {
    match lang {
        Afrikaans => (1, 2),
        Armenian => (1, 2),
        Assamese => (1, 1),
        Basque => (2, 2),
        Bengali => (1, 1),
        Bulgarian => (2, 2),
        Catalan => (2, 2),
        Chinese => (1, 1),
        Coptic => (1, 1),
        Croatian => (2, 2),
        Czech => (2, 3),
        Danish => (2, 2),
        Dutch => (2, 2),
        English_GB => (2, 3),
        English_US => (2, 3),
        Esperanto => (2, 2),
        Estonian => (2, 3),
        Ethiopic => (1, 1),
        Finnish => (2, 2),
        French => (2, 3),
        Friulan => (2, 2),
        Galician => (2, 2),
        Georgian => (1, 2),
        German_1901 => (2, 2),
        German_1996 => (2, 2),
        German_Swiss => (2, 2),
        Greek_Ancient => (1, 1),
        Greek_Mono => (1, 1),
        Greek_Poly => (1, 1),
        Gujarati => (1, 1),
        Hindi => (1, 1),
        Hungarian => (2, 2),
        Icelandic => (2, 2),
        Indonesian => (2, 2),
        Interlingua => (2, 2),
        Irish => (2, 3),
        Italian => (2, 2),
        Kannada => (1, 1),
        Kurmanji => (2, 2),
        Latin => (2, 2),
        Latin_Classic => (2, 2),
        Latvian => (2, 2),
        Lithuanian => (2, 2),
        Malayalam => (1, 1),
        Marathi => (1, 1),
        Mongolian => (2, 2),
        Norwegian_Bokmal => (2, 2),
        Norwegian_Nynorsk => (2, 2),
        Occitan => (2, 2),
        Oriya => (1, 1),
        Panjabi => (1, 1),
        Piedmontese => (2, 2),
        Polish => (2, 2),
        Portuguese => (2, 3),
        Romanian => (2, 2),
        Romansh => (2, 2),
        Russian => (2, 2),
        Sanskrit => (1, 3),
        Serbian_Cyrillic => (2, 2),
        Serbocroatian_Cyrillic => (2, 2),
        Serbocroatian_Latin => (2, 2),
        Slavonic_Church => (1, 2),  // NOTE: potential complications, refer to TeX package
        Slovak => (2, 3),
        Slovenian => (2, 2),
        Spanish => (2, 2),
        Swedish => (2, 2),
        Tamil => (1, 1),
        Telugu => (1, 1),
        Thai => (2, 3),
        Turkish => (2, 2),
        Turkmen => (2, 2),
        Ukrainian => (2, 2),
        Uppersorbian => (2, 2),
        Welsh => (2, 3)
    }
}
<commit_msg>Remove note about Church Slavonic hyphenation boundaries<commit_after>//! Languages we can hyphenate and their default parameters, as provided by
//! the TeX `hyph-utf8` package.

#![allow(non_camel_case_types)]

use exception::{Exceptions};
use pattern::{Patterns};

/// A `Corpus` carries hyphenation data and parameters.
///
/// It comprises the working language, the set of applicable patterns and
/// exceptions, as well as the left and right intra-word hyphenation boundaries.
#[derive(Clone, Debug)]
pub struct Corpus {
    pub language: Language,
    pub patterns: Patterns,
    pub exceptions: Option<Exceptions>,
    pub left_min: usize,
    pub right_min: usize
}

use self::Language::*;

/// The set of available languages.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Language {
    Afrikaans,
    Armenian,
    Assamese,
    Basque,
    Bengali,
    Bulgarian,
    Catalan,
    Chinese,
    Coptic,
    Croatian,
    Czech,
    Danish,
    Dutch,
    English_GB,
    English_US,
    Esperanto,
    Estonian,
    Ethiopic,
    Finnish,
    French,
    Friulan,
    Galician,
    Georgian,
    German_1901,
    German_1996,
    German_Swiss,
    Greek_Ancient,
    Greek_Mono,
    Greek_Poly,
    Gujarati,
    Hindi,
    Hungarian,
    Icelandic,
    Indonesian,
    Interlingua,
    Irish,
    Italian,
    Kannada,
    Kurmanji,
    Latin_Classic,
    Latin,
    Latvian,
    Lithuanian,
    Malayalam,
    Marathi,
    Mongolian,
    Norwegian_Bokmal,
    Norwegian_Nynorsk,
    Occitan,
    Oriya,
    Panjabi,
    Piedmontese,
    Polish,
    Portuguese,
    Romanian,
    Romansh,
    Russian,
    Sanskrit,
    Serbian_Cyrillic,
    Serbocroatian_Cyrillic,
    Serbocroatian_Latin,
    Slavonic_Church,
    Slovak,
    Slovenian,
    Spanish,
    Swedish,
    Tamil,
    Telugu,
    Thai,
    Turkish,
    Turkmen,
    Ukrainian,
    Uppersorbian,
    Welsh
}

/// The TeX tag for a given language.
pub fn tag(lang: Language) -> &'static str {
    match lang {
        Afrikaans => "af",
        Armenian => "hy",
        Assamese => "as",
        Basque => "eu",
        Bengali => "bn",
        Bulgarian => "bg",
        Catalan => "ca",
        Chinese => "zh-latn-pinyin",
        Coptic => "cop",
        Croatian => "hr",
        Czech => "cs",
        Danish => "da",
        Dutch => "nl",
        English_GB => "en-gb",
        English_US => "en-us",
        Esperanto => "eo",
        Estonian => "et",
        Ethiopic => "mul-ethi",
        Finnish => "fi",
        French => "fr",
        Friulan => "fur",
        Galician => "gl",
        Georgian => "ka",
        German_1901  => "de-1901",
        German_1996  => "de-1996",
        German_Swiss => "de-ch-1901",
        Greek_Ancient => "grc",
        Greek_Mono => "el-monoton",
        Greek_Poly => "el-polyton",
        Gujarati => "gu",
        Hindi => "hi",
        Hungarian => "hu",
        Icelandic => "is",
        Indonesian => "id",
        Interlingua => "ia",
        Irish => "ga",
        Italian => "it",
        Kannada => "kn",
        Kurmanji => "kmr",
        Latin => "la",
        Latin_Classic => "la-x-classic",
        Latvian => "lv",
        Lithuanian => "lt",
        Malayalam => "ml",
        Marathi => "mr",
        Mongolian => "mn-cyrl",
        Norwegian_Bokmal  => "nb",
        Norwegian_Nynorsk => "nn",
        Occitan => "oc",
        Oriya => "or",
        Panjabi => "pa",
        Piedmontese => "pms",
        Polish => "pl",
        Portuguese => "pt",
        Romanian => "ro",
        Romansh => "rm",
        Russian => "ru",
        Sanskrit => "sa",
        Serbian_Cyrillic => "sr-cyrl",
        Serbocroatian_Cyrillic => "sh-cyrl",
        Serbocroatian_Latin => "sh-latn",
        Slavonic_Church => "cu",
        Slovak => "sk",
        Slovenian => "sl",
        Spanish => "es",
        Swedish => "sv",
        Tamil => "ta",
        Telugu => "te",
        Thai => "th",
        Turkish => "tr",
        Turkmen => "tk",
        Ukrainian => "uk",
        Uppersorbian => "hsb",
        Welsh => "cy"
    }
}

/// The default number of characters from the start and end of a word
/// which shall not be hyphenated.
pub fn mins(lang: Language) -> (usize, usize) {
    match lang {
        Afrikaans => (1, 2),
        Armenian => (1, 2),
        Assamese => (1, 1),
        Basque => (2, 2),
        Bengali => (1, 1),
        Bulgarian => (2, 2),
        Catalan => (2, 2),
        Chinese => (1, 1),
        Coptic => (1, 1),
        Croatian => (2, 2),
        Czech => (2, 3),
        Danish => (2, 2),
        Dutch => (2, 2),
        English_GB => (2, 3),
        English_US => (2, 3),
        Esperanto => (2, 2),
        Estonian => (2, 3),
        Ethiopic => (1, 1),
        Finnish => (2, 2),
        French => (2, 3),
        Friulan => (2, 2),
        Galician => (2, 2),
        Georgian => (1, 2),
        German_1901 => (2, 2),
        German_1996 => (2, 2),
        German_Swiss => (2, 2),
        Greek_Ancient => (1, 1),
        Greek_Mono => (1, 1),
        Greek_Poly => (1, 1),
        Gujarati => (1, 1),
        Hindi => (1, 1),
        Hungarian => (2, 2),
        Icelandic => (2, 2),
        Indonesian => (2, 2),
        Interlingua => (2, 2),
        Irish => (2, 3),
        Italian => (2, 2),
        Kannada => (1, 1),
        Kurmanji => (2, 2),
        Latin => (2, 2),
        Latin_Classic => (2, 2),
        Latvian => (2, 2),
        Lithuanian => (2, 2),
        Malayalam => (1, 1),
        Marathi => (1, 1),
        Mongolian => (2, 2),
        Norwegian_Bokmal => (2, 2),
        Norwegian_Nynorsk => (2, 2),
        Occitan => (2, 2),
        Oriya => (1, 1),
        Panjabi => (1, 1),
        Piedmontese => (2, 2),
        Polish => (2, 2),
        Portuguese => (2, 3),
        Romanian => (2, 2),
        Romansh => (2, 2),
        Russian => (2, 2),
        Sanskrit => (1, 3),
        Serbian_Cyrillic => (2, 2),
        Serbocroatian_Cyrillic => (2, 2),
        Serbocroatian_Latin => (2, 2),
        Slavonic_Church => (1, 2),
        Slovak => (2, 3),
        Slovenian => (2, 2),
        Spanish => (2, 2),
        Swedish => (2, 2),
        Tamil => (1, 1),
        Telugu => (1, 1),
        Thai => (2, 3),
        Turkish => (2, 2),
        Turkmen => (2, 2),
        Ukrainian => (2, 2),
        Uppersorbian => (2, 2),
        Welsh => (2, 3)
    }
}
<|endoftext|>


<commit_before>

/**
 * Bindings the runtime's random number generator (ISAAC).
 */
native "rust" mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(rctx c) -> u32;
    fn rand_free(rctx c);
}

type rng =
    obj {
        fn next() -> u32 ;
    };

fn mk_rng() -> rng {
    obj rt_rng(rustrt::rctx c) {
        fn next() -> u32 {
            ret rustrt::rand_next(c);
        }drop { rustrt::rand_free(c); }
    }
    ret rt_rng(rustrt::rand_new());
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Fix a bunch of compile-command lines to use RBUILD<commit_after>

/**
 * Bindings the runtime's random number generator (ISAAC).
 */
native "rust" mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(rctx c) -> u32;
    fn rand_free(rctx c);
}

type rng =
    obj {
        fn next() -> u32 ;
    };

fn mk_rng() -> rng {
    obj rt_rng(rustrt::rctx c) {
        fn next() -> u32 {
            ret rustrt::rand_next(c);
        }drop { rustrt::rand_free(c); }
    }
    ret rt_rng(rustrt::rand_new());
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>
use std::iter;
use std::num::{Float, NumCast};

/// An iterator of `n` evenly spaced floats.
///
/// Iterator element type is `F`.
pub type Linspace<F> = iter::Take<iter::Counter<F>>;

/// Return an iterator with `n` elements, where the first
/// element is `a` and the last element is `b`.
///
/// Iterator element type is `F`.
///
/// ```
/// use itertools as it;
/// let mut xs = it::linspace::<f32>(0., 1., 5);
/// assert_eq!(xs.collect::<Vec<_>>(),
///            vec![0., 0.25, 0.5, 0.75, 1.0]);
/// ```
#[inline]
pub fn linspace<F: Float>(a: F, b: F, n: usize) -> Linspace<F>
{
    if n != 0 {
        let nf: F = NumCast::from(n).unwrap();
        let step = (b - a)/(nf - Float::one());
        iter::count(a, step).take(n)
    } else {
        iter::count(a, Float::one()).take(n)
    }
}
<commit_msg>!= 0 check did not prevent div by zero and is irrelevant for floats anyway<commit_after>
use std::iter;
use std::num::{Float, NumCast};

/// An iterator of `n` evenly spaced floats.
///
/// Iterator element type is `F`.
pub type Linspace<F> = iter::Take<iter::Counter<F>>;

/// Return an iterator with `n` elements, where the first
/// element is `a` and the last element is `b`.
///
/// Iterator element type is `F`.
///
/// ```
/// use itertools as it;
/// let mut xs = it::linspace::<f32>(0., 1., 5);
/// assert_eq!(xs.collect::<Vec<_>>(),
///            vec![0., 0.25, 0.5, 0.75, 1.0]);
/// ```
#[inline]
pub fn linspace<F: Float>(a: F, b: F, n: usize) -> Linspace<F>
{
    let nf: F = NumCast::from(n).unwrap();
    let step = (b - a)/(nf - Float::one());
    iter::count(a, step).take(n)
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Script to check the validity of `href` links in our HTML documentation.
//!
//! In the past we've been quite error prone to writing in broken links as most
//! of them are manually rather than automatically added. As files move over
//! time or apis change old links become stale or broken. The purpose of this
//! script is to check all relative links in our documentation to make sure they
//! actually point to a valid place.
//!
//! Currently this doesn't actually do any HTML parsing or anything fancy like
//! that, it just has a simple "regex" to search for `href` and `id` tags.
//! These values are then translated to file URLs if possible and then the
//! destination is asserted to exist.
//!
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.

extern crate url;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;

use url::{Url, UrlParser};

use Redirect::*;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

fn main() {
    let docs = env::args().nth(1).unwrap();
    let docs = env::current_dir().unwrap().join(docs);
    let mut url = Url::from_file_path(&docs).unwrap();
    let mut errors = false;
    walk(&mut HashMap::new(), &docs, &docs, &mut url, &mut errors);
    if errors {
        panic!("found some broken links");
    }
}

#[derive(Debug)]
pub enum LoadError {
    IOError(std::io::Error),
    BrokenRedirect(PathBuf, std::io::Error),
    IsRedirect,
}

enum Redirect {
    SkipRedirect,
    FromRedirect(bool),
}

struct FileEntry {
    source: String,
    ids: HashSet<String>,
}

type Cache = HashMap<PathBuf, FileEntry>;

impl FileEntry {
    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
        if self.ids.is_empty() {
            with_attrs_in_source(contents, " id", |fragment, i| {
                let frag = fragment.trim_left_matches("#").to_owned();
                if !self.ids.insert(frag) {
                    *errors = true;
                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
                }
            });
        }
    }
}

fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut bool) {
    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
        let path = entry.path();
        let kind = t!(entry.file_type());
        url.path_mut().unwrap().push(entry.file_name().into_string().unwrap());
        if kind.is_dir() {
            walk(cache, root, &path, url, errors);
        } else {
            let pretty_path = check(cache, root, &path, url, errors);
            if let Some(pretty_path) = pretty_path {
                let entry = cache.get_mut(&pretty_path).unwrap();
                // we don't need the source anymore,
                // so drop to reduce memory-usage
                entry.source = String::new();
            }
        }
        url.path_mut().unwrap().pop();
    }
}

fn check(cache: &mut Cache,
         root: &Path,
         file: &Path,
         base: &Url,
         errors: &mut bool)
         -> Option<PathBuf> {
    // ignore js files as they are not prone to errors as the rest of the
    // documentation is and they otherwise bring up false positives.
    if file.extension().and_then(|s| s.to_str()) == Some("js") {
        return None;
    }

    // Unfortunately we're not 100% full of valid links today to we need a few
    // whitelists to get this past `make check` today.
    // FIXME(#32129)
    if file.ends_with("std/string/struct.String.html") {
        return None;
    }
    // FIXME(#32553)
    if file.ends_with("collections/string/struct.String.html") {
        return None;
    }
    // FIXME(#32130)
    if file.ends_with("btree_set/struct.BTreeSet.html") ||
       file.ends_with("collections/struct.BTreeSet.html") ||
       file.ends_with("collections/btree_map/struct.BTreeMap.html") ||
       file.ends_with("collections/hash_map/struct.HashMap.html") {
        return None;
    }

    if file.ends_with("std/sys/ext/index.html") {
        return None;
    }

    if let Some(file) = file.to_str() {
        // FIXME(#31948)
        if file.contains("ParseFloatError") {
            return None;
        }
        // weird reexports, but this module is on its way out, so chalk it up to
        // "rustdoc weirdness" and move on from there
        if file.contains("scoped_tls") {
            return None;
        }
    }

    let mut parser = UrlParser::new();
    parser.base_url(base);

    let res = load_file(cache, root, PathBuf::from(file), SkipRedirect);
    let (pretty_file, contents) = match res {
        Ok(res) => res,
        Err(_) => return None,
    };
    {
        cache.get_mut(&pretty_file)
             .unwrap()
             .parse_ids(&pretty_file, &contents, errors);
    }

    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
    with_attrs_in_source(&contents, " href", |url, i| {
        // Once we've plucked out the URL, parse it using our base url and
        // then try to extract a file path. If either of these fail then we
        // just keep going.
        let (parsed_url, path) = match url_to_file_path(&parser, url) {
            Some((url, path)) => (url, PathBuf::from(path)),
            None => return,
        };

        // Alright, if we've found a file name then this file had better
        // exist! If it doesn't then we register and print an error.
        if path.exists() {
            if path.is_dir() {
                // Links to directories show as directory listings when viewing
                // the docs offline so it's best to avoid them.
                *errors = true;
                let pretty_path = path.strip_prefix(root).unwrap_or(&path);
                println!("{}:{}: directory link - {}",
                         pretty_file.display(),
                         i + 1,
                         pretty_path.display());
                return;
            }
            let res = load_file(cache, root, path.clone(), FromRedirect(false));
            let (pretty_path, contents) = match res {
                Ok(res) => res,
                Err(LoadError::IOError(err)) => panic!(format!("{}", err)),
                Err(LoadError::BrokenRedirect(target, _)) => {
                    print!("{}:{}: broken redirect to {}",
                           pretty_file.display(),
                           i + 1,
                           target.display());
                    return;
                }
                Err(LoadError::IsRedirect) => unreachable!(),
            };

            if let Some(ref fragment) = parsed_url.fragment {
                // Fragments like `#1-6` are most likely line numbers to be
                // interpreted by javascript, so we're ignoring these
                if fragment.splitn(2, '-')
                           .all(|f| f.chars().all(|c| c.is_numeric())) {
                    return;
                }

                let entry = &mut cache.get_mut(&pretty_path).unwrap();
                entry.parse_ids(&pretty_path, &contents, errors);

                if !entry.ids.contains(fragment) {
                    *errors = true;
                    print!("{}:{}: broken link fragment  ",
                           pretty_file.display(),
                           i + 1);
                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
                };
            }
        } else {
            *errors = true;
            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
            println!("{}", pretty_path.display());
        }
    });
    Some(pretty_file)
}

fn load_file(cache: &mut Cache,
             root: &Path,
             file: PathBuf,
             redirect: Redirect)
             -> Result<(PathBuf, String), LoadError> {
    let mut contents = String::new();
    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));

    let maybe_redirect = match cache.entry(pretty_file.clone()) {
        Entry::Occupied(entry) => {
            contents = entry.get().source.clone();
            None
        }
        Entry::Vacant(entry) => {
            let mut fp = try!(File::open(file.clone()).map_err(|err| {
                if let FromRedirect(true) = redirect {
                    LoadError::BrokenRedirect(file.clone(), err)
                } else {
                    LoadError::IOError(err)
                }
            }));
            try!(fp.read_to_string(&mut contents)
                   .map_err(|err| LoadError::IOError(err)));

            let maybe = maybe_redirect(&contents);
            if maybe.is_some() {
                if let SkipRedirect = redirect {
                    return Err(LoadError::IsRedirect);
                }
            } else {
                entry.insert(FileEntry {
                    source: contents.clone(),
                    ids: HashSet::new(),
                });
            }
            maybe
        }
    };
    let base = Url::from_file_path(&file).unwrap();
    let mut parser = UrlParser::new();
    parser.base_url(&base);

    match maybe_redirect.and_then(|url| url_to_file_path(&parser, &url)) {
        Some((_, redirect_file)) => {
            let path = PathBuf::from(redirect_file);
            load_file(cache, root, path, FromRedirect(true))
        }
        None => Ok((pretty_file, contents)),
    }
}

fn maybe_redirect(source: &str) -> Option<String> {
    const REDIRECT: &'static str = "
Redirecting to  l,
        None => return None,
    };

    redirect_line.find(REDIRECT).map(|i| {
        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
        let pos_quote = rest.find('"').unwrap();
        rest[..pos_quote].to_owned()
    })
}

fn url_to_file_path(parser: &UrlParser, url: &str) -> Option<(Url, PathBuf)> {
    parser.parse(url)
          .ok()
          .and_then(|parsed_url| parsed_url.to_file_path().ok().map(|f| (parsed_url, f)))
}

fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str, attr: &str, mut f: F) {
    for (i, mut line) in contents.lines().enumerate() {
        while let Some(j) = line.find(attr) {
            let rest = &line[j + attr.len()..];
            line = rest;
            let pos_equals = match rest.find("=") {
                Some(i) => i,
                None => continue,
            };
            if rest[..pos_equals].trim_left_matches(" ") != "" {
                continue;
            }

            let rest = &rest[pos_equals + 1..];

            let pos_quote = match rest.find(&['"', '\''][..]) {
                Some(i) => i,
                None => continue,
            };
            let quote_delim = rest.as_bytes()[pos_quote] as char;

            if rest[..pos_quote].trim_left_matches(" ") != "" {
                continue;
            }
            let rest = &rest[pos_quote + 1..];
            let url = match rest.find(quote_delim) {
                Some(i) => &rest[..i],
                None => continue,
            };
            f(url, i)
        }
    }
}
<commit_msg>Reject invalid urls in linkchecker<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Script to check the validity of `href` links in our HTML documentation.
//!
//! In the past we've been quite error prone to writing in broken links as most
//! of them are manually rather than automatically added. As files move over
//! time or apis change old links become stale or broken. The purpose of this
//! script is to check all relative links in our documentation to make sure they
//! actually point to a valid place.
//!
//! Currently this doesn't actually do any HTML parsing or anything fancy like
//! that, it just has a simple "regex" to search for `href` and `id` tags.
//! These values are then translated to file URLs if possible and then the
//! destination is asserted to exist.
//!
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.

extern crate url;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;

use url::{Url, UrlParser};

use Redirect::*;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

fn main() {
    let docs = env::args().nth(1).unwrap();
    let docs = env::current_dir().unwrap().join(docs);
    let mut url = Url::from_file_path(&docs).unwrap();
    let mut errors = false;
    walk(&mut HashMap::new(), &docs, &docs, &mut url, &mut errors);
    if errors {
        panic!("found some broken links");
    }
}

#[derive(Debug)]
pub enum LoadError {
    IOError(std::io::Error),
    BrokenRedirect(PathBuf, std::io::Error),
    IsRedirect,
}

enum Redirect {
    SkipRedirect,
    FromRedirect(bool),
}

struct FileEntry {
    source: String,
    ids: HashSet<String>,
}

type Cache = HashMap<PathBuf, FileEntry>;

impl FileEntry {
    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
        if self.ids.is_empty() {
            with_attrs_in_source(contents, " id", |fragment, i| {
                let frag = fragment.trim_left_matches("#").to_owned();
                if !self.ids.insert(frag) {
                    *errors = true;
                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
                }
            });
        }
    }
}

fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut bool) {
    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
        let path = entry.path();
        let kind = t!(entry.file_type());
        url.path_mut().unwrap().push(entry.file_name().into_string().unwrap());
        if kind.is_dir() {
            walk(cache, root, &path, url, errors);
        } else {
            let pretty_path = check(cache, root, &path, url, errors);
            if let Some(pretty_path) = pretty_path {
                let entry = cache.get_mut(&pretty_path).unwrap();
                // we don't need the source anymore,
                // so drop to reduce memory-usage
                entry.source = String::new();
            }
        }
        url.path_mut().unwrap().pop();
    }
}

fn check(cache: &mut Cache,
         root: &Path,
         file: &Path,
         base: &Url,
         errors: &mut bool)
         -> Option<PathBuf> {
    // ignore js files as they are not prone to errors as the rest of the
    // documentation is and they otherwise bring up false positives.
    if file.extension().and_then(|s| s.to_str()) == Some("js") {
        return None;
    }

    // Unfortunately we're not 100% full of valid links today to we need a few
    // whitelists to get this past `make check` today.
    // FIXME(#32129)
    if file.ends_with("std/string/struct.String.html") {
        return None;
    }
    // FIXME(#32553)
    if file.ends_with("collections/string/struct.String.html") {
        return None;
    }
    // FIXME(#32130)
    if file.ends_with("btree_set/struct.BTreeSet.html") ||
       file.ends_with("collections/struct.BTreeSet.html") ||
       file.ends_with("collections/btree_map/struct.BTreeMap.html") ||
       file.ends_with("collections/hash_map/struct.HashMap.html") {
        return None;
    }

    let mut parser = UrlParser::new();
    parser.base_url(base);

    let res = load_file(cache, root, PathBuf::from(file), SkipRedirect);
    let (pretty_file, contents) = match res {
        Ok(res) => res,
        Err(_) => return None,
    };
    {
        cache.get_mut(&pretty_file)
             .unwrap()
             .parse_ids(&pretty_file, &contents, errors);
    }

    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
    with_attrs_in_source(&contents, " href", |url, i| {
        // Ignore external URLs
        if url.starts_with("http:") || url.starts_with("https:") ||
           url.starts_with("javascript:") || url.starts_with("ftp:") ||
           url.starts_with("irc:") || url.starts_with("data:") {
            return;
        }
        // Once we've plucked out the URL, parse it using our base url and
        // then try to extract a file path.
        let (parsed_url, path) = match url_to_file_path(&parser, url) {
            Some((url, path)) => (url, PathBuf::from(path)),
            None => {
                *errors = true;
                println!("{}:{}: invalid link - {}",
                         pretty_file.display(),
                         i + 1,
                         url);
                return;
            }
        };

        // Alright, if we've found a file name then this file had better
        // exist! If it doesn't then we register and print an error.
        if path.exists() {
            if path.is_dir() {
                // Links to directories show as directory listings when viewing
                // the docs offline so it's best to avoid them.
                *errors = true;
                let pretty_path = path.strip_prefix(root).unwrap_or(&path);
                println!("{}:{}: directory link - {}",
                         pretty_file.display(),
                         i + 1,
                         pretty_path.display());
                return;
            }
            let res = load_file(cache, root, path.clone(), FromRedirect(false));
            let (pretty_path, contents) = match res {
                Ok(res) => res,
                Err(LoadError::IOError(err)) => panic!(format!("{}", err)),
                Err(LoadError::BrokenRedirect(target, _)) => {
                    *errors = true;
                    println!("{}:{}: broken redirect to {}",
                             pretty_file.display(),
                             i + 1,
                             target.display());
                    return;
                }
                Err(LoadError::IsRedirect) => unreachable!(),
            };

            if let Some(ref fragment) = parsed_url.fragment {
                // Fragments like `#1-6` are most likely line numbers to be
                // interpreted by javascript, so we're ignoring these
                if fragment.splitn(2, '-')
                           .all(|f| f.chars().all(|c| c.is_numeric())) {
                    return;
                }

                let entry = &mut cache.get_mut(&pretty_path).unwrap();
                entry.parse_ids(&pretty_path, &contents, errors);

                if !entry.ids.contains(fragment) {
                    *errors = true;
                    print!("{}:{}: broken link fragment  ",
                           pretty_file.display(),
                           i + 1);
                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
                };
            }
        } else {
            *errors = true;
            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
            println!("{}", pretty_path.display());
        }
    });
    Some(pretty_file)
}

fn load_file(cache: &mut Cache,
             root: &Path,
             file: PathBuf,
             redirect: Redirect)
             -> Result<(PathBuf, String), LoadError> {
    let mut contents = String::new();
    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));

    let maybe_redirect = match cache.entry(pretty_file.clone()) {
        Entry::Occupied(entry) => {
            contents = entry.get().source.clone();
            None
        }
        Entry::Vacant(entry) => {
            let mut fp = try!(File::open(file.clone()).map_err(|err| {
                if let FromRedirect(true) = redirect {
                    LoadError::BrokenRedirect(file.clone(), err)
                } else {
                    LoadError::IOError(err)
                }
            }));
            try!(fp.read_to_string(&mut contents)
                   .map_err(|err| LoadError::IOError(err)));

            let maybe = maybe_redirect(&contents);
            if maybe.is_some() {
                if let SkipRedirect = redirect {
                    return Err(LoadError::IsRedirect);
                }
            } else {
                entry.insert(FileEntry {
                    source: contents.clone(),
                    ids: HashSet::new(),
                });
            }
            maybe
        }
    };
    let base = Url::from_file_path(&file).unwrap();
    let mut parser = UrlParser::new();
    parser.base_url(&base);

    match maybe_redirect.and_then(|url| url_to_file_path(&parser, &url)) {
        Some((_, redirect_file)) => {
            let path = PathBuf::from(redirect_file);
            load_file(cache, root, path, FromRedirect(true))
        }
        None => Ok((pretty_file, contents)),
    }
}

fn maybe_redirect(source: &str) -> Option<String> {
    const REDIRECT: &'static str = "
Redirecting to  l,
        None => return None,
    };

    redirect_line.find(REDIRECT).map(|i| {
        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
        let pos_quote = rest.find('"').unwrap();
        rest[..pos_quote].to_owned()
    })
}

fn url_to_file_path(parser: &UrlParser, url: &str) -> Option<(Url, PathBuf)> {
    parser.parse(url)
          .ok()
          .and_then(|parsed_url| parsed_url.to_file_path().ok().map(|f| (parsed_url, f)))
}

fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str, attr: &str, mut f: F) {
    for (i, mut line) in contents.lines().enumerate() {
        while let Some(j) = line.find(attr) {
            let rest = &line[j + attr.len()..];
            line = rest;
            let pos_equals = match rest.find("=") {
                Some(i) => i,
                None => continue,
            };
            if rest[..pos_equals].trim_left_matches(" ") != "" {
                continue;
            }

            let rest = &rest[pos_equals + 1..];

            let pos_quote = match rest.find(&['"', '\''][..]) {
                Some(i) => i,
                None => continue,
            };
            let quote_delim = rest.as_bytes()[pos_quote] as char;

            if rest[..pos_quote].trim_left_matches(" ") != "" {
                continue;
            }
            let rest = &rest[pos_quote + 1..];
            let url = match rest.find(quote_delim) {
                Some(i) => &rest[..i],
                None => continue,
            };
            f(url, i)
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Derek Chiang <derekchiang93@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::path::Path;
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "strip last component from file name";

mod options {
    pub const ZERO: &str = "zero";
    pub const DIR: &str = "dir";
}

fn get_usage() -> String {
    format!("{0} [OPTION] NAME...", executable!())
}

fn get_long_usage() -> String {
    String::from(
        "Output each NAME with its last non-slash component and trailing slashes
        removed; if NAME contains no /'s, output '.' (meaning the current directory).",
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let separator = if matches.is_present(options::ZERO) {
        "\0"
    } else {
        "\n"
    };

    let dirnames: Vec<String> = matches
        .values_of(options::DIR)
        .unwrap_or_default()
        .map(str::to_owned)
        .collect();

    if !dirnames.is_empty() {
        for path in dirnames.iter() {
            let p = Path::new(path);
            match p.parent() {
                Some(d) => {
                    if d.components().next() == None {
                        print!(".")
                    } else {
                        print!("{}", d.to_string_lossy());
                    }
                }
                None => {
                    if p.is_absolute() || path == "/" {
                        print!("/");
                    } else {
                        print!(".");
                    }
                }
            }
            print!("{}", separator);
        }
    } else {
        show_usage_error!("missing operand");
        return 1;
    }

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .about(ABOUT)
        .version(crate_version!())
        .arg(
            Arg::with_name(options::ZERO)
                .long(options::ZERO)
                .short("z")
                .help("separate output with NUL rather than newline"),
        )
        .arg(Arg::with_name(options::DIR).hidden(true).multiple(true))
}
<commit_msg>Added UResult for dirname<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Derek Chiang <derekchiang93@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::path::Path;
use uucore::error::{UResult, USimpleError};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "strip last component from file name";

mod options {
    pub const ZERO: &str = "zero";
    pub const DIR: &str = "dir";
}

fn get_usage() -> String {
    format!("{0} [OPTION] NAME...", executable!())
}

fn get_long_usage() -> String {
    String::from(
        "Output each NAME with its last non-slash component and trailing slashes
        removed; if NAME contains no /'s, output '.' (meaning the current directory).",
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let separator = if matches.is_present(options::ZERO) {
        "\0"
    } else {
        "\n"
    };

    let dirnames: Vec<String> = matches
        .values_of(options::DIR)
        .unwrap_or_default()
        .map(str::to_owned)
        .collect();

    if !dirnames.is_empty() {
        for path in dirnames.iter() {
            let p = Path::new(path);
            match p.parent() {
                Some(d) => {
                    if d.components().next() == None {
                        print!(".")
                    } else {
                        print!("{}", d.to_string_lossy());
                    }
                }
                None => {
                    if p.is_absolute() || path == "/" {
                        print!("/");
                    } else {
                        print!(".");
                    }
                }
            }
            print!("{}", separator);
        }
    } else {
        return Err(USimpleError::new(1, format!("missing operand")));
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .about(ABOUT)
        .version(crate_version!())
        .arg(
            Arg::with_name(options::ZERO)
                .long(options::ZERO)
                .short("z")
                .help("separate output with NUL rather than newline"),
        )
        .arg(Arg::with_name(options::DIR).hidden(true).multiple(true))
}
<|endoftext|>


<commit_before>// spell-checker:ignore (ToDO) fperm

extern crate libc;
use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};

use uucore::mode;

pub fn parse_mode(mode: Option<String>) -> Result<mode_t, String> {
    let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
    if let Some(mode) = mode {
        let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
        let result = if mode.contains(arr) {
            mode::parse_numeric(fperm as u32, mode.as_str())
        } else {
            mode::parse_symbolic(fperm as u32, mode.as_str(), true)
        };
        result.map(|mode| mode as mode_t)
    } else {
        Ok(fperm)
    }
}

#[cfg(test)]
mod test {
    /// Test if the program is running under WSL
    // ref: <https://github.com/microsoft/WSL/issues/4555> @@ <https://archive.is/dP0bz>
    // ToDO: test on WSL2 which likely doesn't need special handling; plan change to `is_wsl_1()` if WSL2 is less needy
    pub fn is_wsl() -> bool {
        #[cfg(target_os = "linux")]
        {
            if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") {
                if let Ok(s) = std::str::from_utf8(&b) {
                    let a = s.to_ascii_lowercase();
                    return a.contains("microsoft") || a.contains("wsl");
                }
            }
        }
        false
    }

    #[test]
    fn symbolic_modes() {
        assert_eq!(super::parse_mode(Some("u+x".to_owned())).unwrap(), 0o766);
        assert_eq!(super::parse_mode(Some("+x".to_owned())).unwrap(), if !is_wsl() { 0o777 } else {0o776});
        assert_eq!(super::parse_mode(Some("a-w".to_owned())).unwrap(), 0o444);
        assert_eq!(super::parse_mode(Some("g-r".to_owned())).unwrap(), 0o626);
    }

    #[test]
    fn numeric_modes() {
        assert_eq!(super::parse_mode(Some("644".to_owned())).unwrap(), 0o644);
        assert_eq!(super::parse_mode(Some("+100".to_owned())).unwrap(), 0o766);
        assert_eq!(super::parse_mode(Some("-4".to_owned())).unwrap(), 0o662);
        assert_eq!(super::parse_mode(None).unwrap(), 0o666);
    }
}
<commit_msg>refactor/polish ~ `cargo fmt`<commit_after>// spell-checker:ignore (ToDO) fperm

extern crate libc;
use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};

use uucore::mode;

pub fn parse_mode(mode: Option<String>) -> Result<mode_t, String> {
    let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
    if let Some(mode) = mode {
        let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
        let result = if mode.contains(arr) {
            mode::parse_numeric(fperm as u32, mode.as_str())
        } else {
            mode::parse_symbolic(fperm as u32, mode.as_str(), true)
        };
        result.map(|mode| mode as mode_t)
    } else {
        Ok(fperm)
    }
}

#[cfg(test)]
mod test {
    /// Test if the program is running under WSL
    // ref: <https://github.com/microsoft/WSL/issues/4555> @@ <https://archive.is/dP0bz>
    // ToDO: test on WSL2 which likely doesn't need special handling; plan change to `is_wsl_1()` if WSL2 is less needy
    pub fn is_wsl() -> bool {
        #[cfg(target_os = "linux")]
        {
            if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") {
                if let Ok(s) = std::str::from_utf8(&b) {
                    let a = s.to_ascii_lowercase();
                    return a.contains("microsoft") || a.contains("wsl");
                }
            }
        }
        false
    }

    #[test]
    fn symbolic_modes() {
        assert_eq!(super::parse_mode(Some("u+x".to_owned())).unwrap(), 0o766);
        assert_eq!(
            super::parse_mode(Some("+x".to_owned())).unwrap(),
            if !is_wsl() { 0o777 } else { 0o776 }
        );
        assert_eq!(super::parse_mode(Some("a-w".to_owned())).unwrap(), 0o444);
        assert_eq!(super::parse_mode(Some("g-r".to_owned())).unwrap(), 0o626);
    }

    #[test]
    fn numeric_modes() {
        assert_eq!(super::parse_mode(Some("644".to_owned())).unwrap(), 0o644);
        assert_eq!(super::parse_mode(Some("+100".to_owned())).unwrap(), 0o766);
        assert_eq!(super::parse_mode(Some("-4".to_owned())).unwrap(), 0o662);
        assert_eq!(super::parse_mode(None).unwrap(), 0o666);
    }
}
<|endoftext|>


<commit_before>pub use svm::slist::List::{Cons,Nil};
use std::fmt;
use std::ops::Index;

/// Convenience macro for making lists.
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// assert_eq!(
///     list!(1i32, 2i32, 3i32),
///     Cons(1i32, Box::new(Cons(2i32, Box::new(Cons(3i32, Box::new(Nil))))))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( @Empty )
);

/// Common functions for an immutable Stack abstract data type.
pub trait Stack<T> {

    /// Push an item to the top of the stack, returning a new stack
    fn push(self, item : T) -> Self;

    /// Pop the top element of the stack. Returns an Option on a T and
    /// a new Stack<T> to replace this.
    fn pop(self)            -> Option<(T, Self)>;

    /// Peek at the top item of the stack.
    ///
    /// Returns Some<T> if there is an item on top of the stack,
    /// and None if the stack is empty.
    fn peek(&self)          -> Option<&T>;

    /// Returns an empty stack.
    fn empty()              -> Self;
}

/// Stack implementation using a cons list
impl<T> Stack<T> for List<T> {

    /// Push an item to the top of the stack, returning a new stack.
    ///
    /// # Examples:
    /// ```
    /// use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// assert_eq!(s.peek(), None);
    /// s = s.push(1);
    /// assert_eq!(s.peek(), Some(&1));
    /// s = s.push(6);
    /// assert_eq!(s.peek(), Some(&6));
    /// ```
    fn push(self, item: T) -> List<T> {
        Cons(item, box self)
    }

    /// Pop the top element of the stack.
    ///
    /// Pop the top element of the stack. Returns an
    /// `Option<(T,List<T>)>` containing the top element and a new
    /// `List<T>` with that item removed, or `None` if the stack is
    /// empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn pop(self) -> Option<(T,List<T>)> {
        match self {
            Cons(item, new_self)    => Some((item, *new_self)),
            Nil                     => None
        }
    }

    fn empty() -> List<T> {
        Nil
    }

    /// Peek at the top element of the stack.
    ///
    /// Peek at the top element of the stack. Returns an `Option<&T>`
    /// with a borrowed pointer to the top element, or `None` if the
    /// stack is empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn peek(&self) -> Option<&T> {
        match self {
            &Nil => None,
            &Cons(ref it,_) => Some(it)
        }
    }

}

/// Singly-linked cons list.
///
/// This is used internally to represent list primitives in the
/// machine.
#[derive(PartialEq,Clone,Debug)]
pub enum List<T> {
    /// Cons cell containing a `T` and a link to the tail
    Cons(T, Box<List<T>>),
    /// The empty list.
    Nil,
}

/// Public implementation for List.
impl<T> List<T> {

    /// Creates a new empty list
    pub fn new() -> List<T> {
        Nil
    }

    /// Prepends the given item to the list.
    ///
    /// Returns the list containing the new  head item.
    /// This is an O(1) operation.
    pub fn prepend(self, it: T) -> List<T> {
        Cons(it, box self)
    }

    /// Appends an item to the end of the list.
    ///
    /// This is an O(n) operation.
    pub fn append(self, it: T) {
        unimplemented!()
    }

    /// Returns the length of the list.
    pub fn length (&self) -> usize {
        match *self {
            Cons(_, ref tail) => 1 + tail.length(),
            Nil => 0
        }
    }

    /// Provide a forward iterator
    #[inline]
    pub fn iter<'a>(&'a self) -> ListIterator<'a, T> {
        ListIterator{current: self}
    }

    pub fn last(&self) -> &T {
        match *self {
            Cons(ref car, box Nil) => &car,
            Cons(_, ref cdr @ box Cons(_,_)) => cdr.last(),
            Nil => panic!("Last called on empty list")
        }
    }
}

impl<'a, T> fmt::Display for List<T> where T: fmt::Display{

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: replace toString with this
        match *self {
            Cons(ref head, ref tail) => write!(f, "({}, {})", head, tail),
            Nil => write!(f,"nil")
        }
    }
}

/// Wraps a List<T> to allow it to be used as an Iterator<T>
pub struct ListIterator<'a, T:'a> {
    current: &'a List<T>
}

/// Implementation of Iterator for List. This allows iteration by
/// link hopping.
impl<'a, T> Iterator for ListIterator<'a, T> {
    type Item = &'a T;

    /// Get the next element from the list.
    ///
    /// Get the next element from the list. Returns a `Some<T>`, or `Nil`
    /// if at the end of the list.
    ///
    /// # Examples:
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let list = list!(1,2,3);
    /// let mut iter = list.iter();
    /// assert_eq!(iter.next().unwrap(), &1);
    /// assert_eq!(iter.next().unwrap(), &2);
    /// assert_eq!(iter.next().unwrap(), &3);
    /// # }
    /// ```
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let l: List<isize> = list!(1,2,3,4,5,6);
    /// let mut string = String::new();
    /// for item in l.iter() {
    ///     string.push_str((item.to_string() + ", ").as_slice());
    /// }
    /// assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    /// # }
    /// ```
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cons(ref head, box ref tail) => { self.current = tail; Some(head) },
            &Nil => None
        }
    }
}

impl<'a, T> ExactSizeIterator for ListIterator<'a, T> {
    fn len(&self) -> usize {
        self.current.length()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0us], 1);
/// # }
/// ```
impl<T> Index<usize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        match *_index {
            0us => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1us => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() => self.last(),
            i if i > self.length()  => panic!("List index {:?} out of range.", _index),
            i if i > 1us => {
                let mut it = self.iter();
                for _ in 0 .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0is], 1);
/// # }
/// ```
impl<T> Index<isize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &isize) -> &'a T {
        match *_index {
            0is => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1is => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() as isize => self.last(),
            i if i > self.length() as isize => panic!("List index {:?} out of range.", _index),
            i if i > 1is => {
                let mut it = self.iter();
                for _ in 0 .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{List, Stack};
    use super::List::{Cons,Nil};

    #[test]
    fn test_list_length() {
        let full_list: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_list: List<i32> = List::new();
        assert_eq!(full_list.length(), 3);
        assert_eq!(empty_list.length(), 0);
    }

    #[test]
    fn test_list_to_string() {
        let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))");
    }

    #[test]
    fn test_stack_length() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.length(), 3);
        assert_eq!(empty_stack.length(), 0);
    }

    #[test]
    fn test_stack_peek() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.peek(), Some(&1));
        assert_eq!(empty_stack.peek(), None);
    }

    #[test]
    fn test_stack_push() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
    }

    #[test]
    fn test_stack_pop() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
        let pop_result = s.pop().unwrap(); // should not break
        s = pop_result.1;
        assert_eq!(s.peek(), Some(&1));
        assert_eq!(pop_result.0, 6);
    }
/*
    #[test]
    fn test_list_usize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0us],1);
        assert_eq!(l[1us],2);
        assert_eq!(l[2us],3);
        assert_eq!(l[3us],4);
        assert_eq!(l[4us],5);
        assert_eq!(l[5us],6);
    }*/

    #[test]
    fn test_list_isize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0is],1);
        assert_eq!(l[1is],2);
        assert_eq!(l[2is],3);
        assert_eq!(l[3is],4);
        assert_eq!(l[4is],5);
        assert_eq!(l[5is],6);
    }

    #[test]
    fn test_list_macro() {
        let l: List<i32> = list!(1i32, 2i32, 3i32);
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))")
    }

    #[test]
    fn test_list_iter() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        let mut string = String::new();
        for item in l.iter() {
            string.push_str((item.to_string() + ", ").as_slice());
        }
        assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    }

}
<commit_msg>Add feature attributes (should fix build on CI)<commit_after>#![feature(box_syntax)]
#![feature(core)]

pub use svm::slist::List::{Cons,Nil};
use std::fmt;
use std::ops::Index;

/// Convenience macro for making lists.
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// assert_eq!(
///     list!(1i32, 2i32, 3i32),
///     Cons(1i32, Box::new(Cons(2i32, Box::new(Cons(3i32, Box::new(Nil))))))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( @Empty )
);

/// Common functions for an immutable Stack abstract data type.
pub trait Stack<T> {

    /// Push an item to the top of the stack, returning a new stack
    fn push(self, item : T) -> Self;

    /// Pop the top element of the stack. Returns an Option on a T and
    /// a new Stack<T> to replace this.
    fn pop(self)            -> Option<(T, Self)>;

    /// Peek at the top item of the stack.
    ///
    /// Returns Some<T> if there is an item on top of the stack,
    /// and None if the stack is empty.
    fn peek(&self)          -> Option<&T>;

    /// Returns an empty stack.
    fn empty()              -> Self;
}

/// Stack implementation using a cons list
impl<T> Stack<T> for List<T> {

    /// Push an item to the top of the stack, returning a new stack.
    ///
    /// # Examples:
    /// ```
    /// use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// assert_eq!(s.peek(), None);
    /// s = s.push(1);
    /// assert_eq!(s.peek(), Some(&1));
    /// s = s.push(6);
    /// assert_eq!(s.peek(), Some(&6));
    /// ```
    fn push(self, item: T) -> List<T> {
        Cons(item, box self)
    }

    /// Pop the top element of the stack.
    ///
    /// Pop the top element of the stack. Returns an
    /// `Option<(T,List<T>)>` containing the top element and a new
    /// `List<T>` with that item removed, or `None` if the stack is
    /// empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn pop(self) -> Option<(T,List<T>)> {
        match self {
            Cons(item, new_self)    => Some((item, *new_self)),
            Nil                     => None
        }
    }

    fn empty() -> List<T> {
        Nil
    }

    /// Peek at the top element of the stack.
    ///
    /// Peek at the top element of the stack. Returns an `Option<&T>`
    /// with a borrowed pointer to the top element, or `None` if the
    /// stack is empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn peek(&self) -> Option<&T> {
        match self {
            &Nil => None,
            &Cons(ref it,_) => Some(it)
        }
    }

}

/// Singly-linked cons list.
///
/// This is used internally to represent list primitives in the
/// machine.
#[derive(PartialEq,Clone,Debug)]
pub enum List<T> {
    /// Cons cell containing a `T` and a link to the tail
    Cons(T, Box<List<T>>),
    /// The empty list.
    Nil,
}

/// Public implementation for List.
impl<T> List<T> {

    /// Creates a new empty list
    pub fn new() -> List<T> {
        Nil
    }

    /// Prepends the given item to the list.
    ///
    /// Returns the list containing the new  head item.
    /// This is an O(1) operation.
    pub fn prepend(self, it: T) -> List<T> {
        Cons(it, box self)
    }

    /// Appends an item to the end of the list.
    ///
    /// This is an O(n) operation.
    pub fn append(self, it: T) {
        unimplemented!()
    }

    /// Returns the length of the list.
    pub fn length (&self) -> usize {
        match *self {
            Cons(_, ref tail) => 1 + tail.length(),
            Nil => 0
        }
    }

    /// Provide a forward iterator
    #[inline]
    pub fn iter<'a>(&'a self) -> ListIterator<'a, T> {
        ListIterator{current: self}
    }

    pub fn last(&self) -> &T {
        match *self {
            Cons(ref car, box Nil) => &car,
            Cons(_, ref cdr @ box Cons(_,_)) => cdr.last(),
            Nil => panic!("Last called on empty list")
        }
    }
}

impl<'a, T> fmt::Display for List<T> where T: fmt::Display{

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: replace toString with this
        match *self {
            Cons(ref head, ref tail) => write!(f, "({}, {})", head, tail),
            Nil => write!(f,"nil")
        }
    }
}

/// Wraps a List<T> to allow it to be used as an Iterator<T>
pub struct ListIterator<'a, T:'a> {
    current: &'a List<T>
}

/// Implementation of Iterator for List. This allows iteration by
/// link hopping.
impl<'a, T> Iterator for ListIterator<'a, T> {
    type Item = &'a T;

    /// Get the next element from the list.
    ///
    /// Get the next element from the list. Returns a `Some<T>`, or `Nil`
    /// if at the end of the list.
    ///
    /// # Examples:
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let list = list!(1,2,3);
    /// let mut iter = list.iter();
    /// assert_eq!(iter.next().unwrap(), &1);
    /// assert_eq!(iter.next().unwrap(), &2);
    /// assert_eq!(iter.next().unwrap(), &3);
    /// # }
    /// ```
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let l: List<isize> = list!(1,2,3,4,5,6);
    /// let mut string = String::new();
    /// for item in l.iter() {
    ///     string.push_str((item.to_string() + ", ").as_slice());
    /// }
    /// assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    /// # }
    /// ```
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cons(ref head, box ref tail) => { self.current = tail; Some(head) },
            &Nil => None
        }
    }
}

impl<'a, T> ExactSizeIterator for ListIterator<'a, T> {
    fn len(&self) -> usize {
        self.current.length()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0us], 1);
/// # }
/// ```
impl<T> Index<usize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        match *_index {
            0us => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1us => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() => self.last(),
            i if i > self.length()  => panic!("List index {:?} out of range.", _index),
            i if i > 1us => {
                let mut it = self.iter();
                for _ in 0 .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0is], 1);
/// # }
/// ```
impl<T> Index<isize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &isize) -> &'a T {
        match *_index {
            0is => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1is => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() as isize => self.last(),
            i if i > self.length() as isize => panic!("List index {:?} out of range.", _index),
            i if i > 1is => {
                let mut it = self.iter();
                for _ in 0 .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{List, Stack};
    use super::List::{Cons,Nil};

    #[test]
    fn test_list_length() {
        let full_list: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_list: List<i32> = List::new();
        assert_eq!(full_list.length(), 3);
        assert_eq!(empty_list.length(), 0);
    }

    #[test]
    fn test_list_to_string() {
        let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))");
    }

    #[test]
    fn test_stack_length() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.length(), 3);
        assert_eq!(empty_stack.length(), 0);
    }

    #[test]
    fn test_stack_peek() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.peek(), Some(&1));
        assert_eq!(empty_stack.peek(), None);
    }

    #[test]
    fn test_stack_push() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
    }

    #[test]
    fn test_stack_pop() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
        let pop_result = s.pop().unwrap(); // should not break
        s = pop_result.1;
        assert_eq!(s.peek(), Some(&1));
        assert_eq!(pop_result.0, 6);
    }
/*
    #[test]
    fn test_list_usize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0us],1);
        assert_eq!(l[1us],2);
        assert_eq!(l[2us],3);
        assert_eq!(l[3us],4);
        assert_eq!(l[4us],5);
        assert_eq!(l[5us],6);
    }*/

    #[test]
    fn test_list_isize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0is],1);
        assert_eq!(l[1is],2);
        assert_eq!(l[2is],3);
        assert_eq!(l[3is],4);
        assert_eq!(l[4is],5);
        assert_eq!(l[5is],6);
    }

    #[test]
    fn test_list_macro() {
        let l: List<i32> = list!(1i32, 2i32, 3i32);
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))")
    }

    #[test]
    fn test_list_iter() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        let mut string = String::new();
        for item in l.iter() {
            string.push_str((item.to_string() + ", ").as_slice());
        }
        assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    }

}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::cmp::min;

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();

    match compute_match_length(&choice, &query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &str, chars: &str) -> Option<usize> {
    let (first_char, rest) = match chars.slice_shift_char() {
        Some((f, r)) => (f, r),
        None => return None,
    };
    let indices = find_char_in_string(string, first_char);

    let mut current_min = None;
    for i in indices.iter() {
        let last_index = find_end_of_match(string, rest, *i);
        if last_index.is_some() {
            let idx = last_index.unwrap() - *i + 1;
            if current_min.is_some() {
                let cm = min(current_min.unwrap(), idx);
                current_min = Some(cm);
            } else {
                current_min = Some(idx)
            }
        }
    }
    return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    let mut i = 0;
    for c in string.chars() {
        if c == char {
            indices.push(i);
        }
        i = i + 1;
    }
    return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    let chars_in_string = string.chars().collect::<Vec<_>>().len();
    for c in rest_of_query.chars() {
        let current_substring = string.slice_chars(last_index, chars_in_string);
        match current_substring.find(c) {
            None => return None,
            Some(ref i) => {
                last_index += *i + 1;
            }
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match("a", "a", 0), None);
    assert_eq!(find_end_of_match("ba", "a", 1), None);
    assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
    assert_eq!(find_end_of_match("aaa", "b", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
    assert_eq!(find_end_of_match("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "ust", 2), Some(5));
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Replace manual indexing with enumerate()<commit_after>use std::ascii::AsciiExt;
use std::cmp::min;

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();

    match compute_match_length(&choice, &query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &str, chars: &str) -> Option<usize> {
    let (first_char, rest) = match chars.slice_shift_char() {
        Some((f, r)) => (f, r),
        None => return None,
    };
    let indices = find_char_in_string(string, first_char);

    let mut current_min = None;
    for i in indices.iter() {
        let last_index = find_end_of_match(string, rest, *i);
        if last_index.is_some() {
            let idx = last_index.unwrap() - *i + 1;
            if current_min.is_some() {
                let cm = min(current_min.unwrap(), idx);
                current_min = Some(cm);
            } else {
                current_min = Some(idx)
            }
        }
    }
    return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.chars().enumerate() {
        if char == c {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    let chars_in_string = string.chars().collect::<Vec<_>>().len();
    for c in rest_of_query.chars() {
        let current_substring = string.slice_chars(last_index, chars_in_string);
        match current_substring.find(c) {
            None => return None,
            Some(ref i) => {
                last_index += *i + 1;
            }
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match("a", "a", 0), None);
    assert_eq!(find_end_of_match("ba", "a", 1), None);
    assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
    assert_eq!(find_end_of_match("aaa", "b", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
    assert_eq!(find_end_of_match("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "ust", 2), Some(5));
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use num::{One, Zero};
use point::Point2D;
use rect::Rect;
use size::Size2D;
use std::ops::{Add, Mul, Sub};

#[derive(Clone, Copy)]
pub struct Matrix2D<T> {
    m11: T, m12: T,
    m21: T, m22: T,
    m31: T, m32: T
}

impl<T:Add<T, Output=T> +
       Copy +
       Clone +
       Mul<T, Output=T> +
       One +
       PartialOrd +
       Sub<T, Output=T> +
       Zero> Matrix2D<T> {
    pub fn new(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Matrix2D<T> {
        Matrix2D {
            m11: m11, m12: m12,
            m21: m21, m22: m22,
            m31: m31, m32: m32
        }
    }

    pub fn mul(&self, m: &Matrix2D<T>) -> Matrix2D<T> {
        Matrix2D::new(m.m11*self.m11 + m.m12*self.m21,
                      m.m11*self.m12 + m.m12*self.m22,
                      m.m21*self.m11 + m.m22*self.m21,
                      m.m21*self.m12 + m.m22*self.m22,
                      m.m31*self.m11 + m.m32*self.m21 + self.m31,
                      m.m31*self.m12 + m.m32*self.m22 + self.m32)
    }

    pub fn translate(&self, x: T, y: T) -> Matrix2D<T> {
         let (_0, _1): (T, T) = (Zero::zero(), One::one());
         let matrix = Matrix2D::new(_1.clone(), _0.clone(),
                                    _0.clone(), _1.clone(),
                                    x, y);
        return self.mul(&matrix);
    }

    pub fn scale(&self, x: T, y: T) -> Matrix2D<T> {
        Matrix2D::new(self.m11 * x,     self.m12.clone(),
                      self.m21.clone(), self.m22 * y,
                      self.m31.clone(), self.m32.clone())
    }

    pub fn identity() -> Matrix2D<T> {
        let (_0, _1): (T, T) = (Zero::zero(), One::one());
        return Matrix2D::new(_1.clone(), _0.clone(),
                             _0.clone(), _1.clone(),
                             _0.clone(), _0.clone());
    }

    pub fn to_array(&self) -> [T; 6] {
        [
            self.m11.clone(), self.m12.clone(),
            self.m21.clone(), self.m22.clone(),
            self.m31.clone(), self.m32.clone()
        ]
    }

    /// Returns the given point transformed by this matrix.
    #[inline]
    pub fn transform_point(&self, point: &Point2D<T>) -> Point2D<T> {
        Point2D::new(point.x * self.m11 + point.y * self.m21 + self.m31,
                     point.x * self.m12 + point.y * self.m22 + self.m32)
    }

    /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
    /// matrix.
    #[inline]
    pub fn transform_rect(&self, rect: &Rect<T>) -> Rect<T> {
        let top_left = self.transform_point(&rect.origin);
        let top_right = self.transform_point(&rect.top_right());
        let bottom_left = self.transform_point(&rect.bottom_left());
        let bottom_right = self.transform_point(&rect.bottom_right());
        let (mut min_x, mut min_y) = (top_left.x.clone(), top_left.y.clone());
        let (mut max_x, mut max_y) = (min_x.clone(), min_y.clone());
        for point in [ top_right, bottom_left, bottom_right ].iter() {
            if point.x < min_x {
                min_x = point.x.clone()
            }
            if point.x > max_x {
                max_x = point.x.clone()
            }
            if point.y < min_y {
                min_y = point.y.clone()
            }
            if point.y > max_y {
                max_y = point.y.clone()
            }
        }
        Rect::new(Point2D::new(min_x.clone(), min_y.clone()),
                  Size2D::new(max_x - min_x, max_y - min_y))
    }
}
<commit_msg>Make `Matrix2D` serializable with `serde`.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use num::{One, Zero};
use point::Point2D;
use rect::Rect;
use size::Size2D;
use std::ops::{Add, Mul, Sub};

#[derive(Clone, Copy, Deserialize, Serialize)]
pub struct Matrix2D<T> {
    m11: T, m12: T,
    m21: T, m22: T,
    m31: T, m32: T
}

impl<T:Add<T, Output=T> +
       Copy +
       Clone +
       Mul<T, Output=T> +
       One +
       PartialOrd +
       Sub<T, Output=T> +
       Zero> Matrix2D<T> {
    pub fn new(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Matrix2D<T> {
        Matrix2D {
            m11: m11, m12: m12,
            m21: m21, m22: m22,
            m31: m31, m32: m32
        }
    }

    pub fn mul(&self, m: &Matrix2D<T>) -> Matrix2D<T> {
        Matrix2D::new(m.m11*self.m11 + m.m12*self.m21,
                      m.m11*self.m12 + m.m12*self.m22,
                      m.m21*self.m11 + m.m22*self.m21,
                      m.m21*self.m12 + m.m22*self.m22,
                      m.m31*self.m11 + m.m32*self.m21 + self.m31,
                      m.m31*self.m12 + m.m32*self.m22 + self.m32)
    }

    pub fn translate(&self, x: T, y: T) -> Matrix2D<T> {
         let (_0, _1): (T, T) = (Zero::zero(), One::one());
         let matrix = Matrix2D::new(_1.clone(), _0.clone(),
                                    _0.clone(), _1.clone(),
                                    x, y);
        return self.mul(&matrix);
    }

    pub fn scale(&self, x: T, y: T) -> Matrix2D<T> {
        Matrix2D::new(self.m11 * x,     self.m12.clone(),
                      self.m21.clone(), self.m22 * y,
                      self.m31.clone(), self.m32.clone())
    }

    pub fn identity() -> Matrix2D<T> {
        let (_0, _1): (T, T) = (Zero::zero(), One::one());
        return Matrix2D::new(_1.clone(), _0.clone(),
                             _0.clone(), _1.clone(),
                             _0.clone(), _0.clone());
    }

    pub fn to_array(&self) -> [T; 6] {
        [
            self.m11.clone(), self.m12.clone(),
            self.m21.clone(), self.m22.clone(),
            self.m31.clone(), self.m32.clone()
        ]
    }

    /// Returns the given point transformed by this matrix.
    #[inline]
    pub fn transform_point(&self, point: &Point2D<T>) -> Point2D<T> {
        Point2D::new(point.x * self.m11 + point.y * self.m21 + self.m31,
                     point.x * self.m12 + point.y * self.m22 + self.m32)
    }

    /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
    /// matrix.
    #[inline]
    pub fn transform_rect(&self, rect: &Rect<T>) -> Rect<T> {
        let top_left = self.transform_point(&rect.origin);
        let top_right = self.transform_point(&rect.top_right());
        let bottom_left = self.transform_point(&rect.bottom_left());
        let bottom_right = self.transform_point(&rect.bottom_right());
        let (mut min_x, mut min_y) = (top_left.x.clone(), top_left.y.clone());
        let (mut max_x, mut max_y) = (min_x.clone(), min_y.clone());
        for point in [ top_right, bottom_left, bottom_right ].iter() {
            if point.x < min_x {
                min_x = point.x.clone()
            }
            if point.x > max_x {
                max_x = point.x.clone()
            }
            if point.y < min_y {
                min_y = point.y.clone()
            }
            if point.y > max_y {
                max_y = point.y.clone()
            }
        }
        Rect::new(Point2D::new(min_x.clone(), min_y.clone()),
                  Size2D::new(max_x - min_x, max_y - min_y))
    }
}
<|endoftext|>