<commit_before>use radio::RadioStation;
use radio::song::{radio_1live, radio_ndr, radio_antenne};

pub const RADIOSTATIONS: &'static [RadioStation] = &[
    // TODO: Add other stations
    // Stations 1LIVE and WDR
    RadioStation {
        name: "1LIVE",
        shorthand: "1live",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_1live.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "1LIVE diGGi",
        shorthand: "diggi",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_1live_diggi.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR2",
        shorthand: "wdr2",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr2.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR3",
        shorthand: "wdr3",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr3.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR4",
        shorthand: "wdr4",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr4.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR5",
        shorthand: "wdr5",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr5.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "Funkhaus Europa",
        shorthand: "fhe",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_fhe.txt",
        get_song: radio_1live,
    },
    // RadioStation {
    //     name: "Kiraka",
    //     url: "http://www.wdr.de/radio/radiotext/streamtitle_kiraka.txt",
    //     get_song: radio_1live,
    // },
    RadioStation {
        name: "WDR-Event",
        shorthand: "wdre",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_event.txt",
        get_song: radio_1live,
    },
    // Stations NDR
    RadioStation {
        name: "NDR 1 Niedersachsen",
        shorthand: "ndr1n",
        url: "http://www.ndr.de/public/radio_playlists/ndr1niedersachsen.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR 1 Radio MV",
        shorthand: "ndr1rmv",
        url: "http://www.ndr.de/public/radio_playlists/ndr1radiomv.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Welle Nord",
        shorthand: "ndrwn",
        url: "http://www.ndr.de/public/radio_playlists/ndr1wellenord.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR 90,3",
        shorthand: "ndr903",
        url: "http://www.ndr.de/public/radio_playlists/ndr903.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR 2",
        shorthand: "ndr2",
        url: "http://www.ndr.de/public/radio_playlists/ndr2.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Info",
        shorthand: "ndri",
        url: "http://www.ndr.de/public/radio_playlists/ndrinfo.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Kultur",
        shorthand: "ndrk",
        url: "http://www.ndr.de/public/radio_playlists/ndrkultur.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NJOY",
        shorthand: "njoy",
        url: "http://www.ndr.de/public/radio_playlists/njoy.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Blue",
        shorthand: "ndrb",
        url: "http://www.ndr.de/public/radio_playlists/ndrblue.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Plus",
        shorthand: "ndrp",
        url: "http://www.ndr.de/public/radio_playlists/ndrplus.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "Antenne Niedersachsen On Air",
        shorthand: "antenneoa",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=29&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen 80er",
        shorthand: "antenne80",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=31&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen 90er",
        shorthand: "antenne90",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=422&nameSize=200&
                artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen Charts",
        shorthand: "antennec",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=30&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen Deutsch",
        shorthand: "antenned",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=565&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
];
<commit_msg>Add more Antenne stations<commit_after>use radio::RadioStation;
use radio::song::{radio_1live, radio_ndr, radio_antenne};

pub const RADIOSTATIONS: &'static [RadioStation] = &[
    // TODO: Add other stations
    // Stations 1LIVE and WDR
    RadioStation {
        name: "1LIVE",
        shorthand: "1live",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_1live.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "1LIVE diGGi",
        shorthand: "diggi",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_1live_diggi.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR2",
        shorthand: "wdr2",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr2.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR3",
        shorthand: "wdr3",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr3.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR4",
        shorthand: "wdr4",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr4.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "WDR5",
        shorthand: "wdr5",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_wdr5.txt",
        get_song: radio_1live,
    },
    RadioStation {
        name: "Funkhaus Europa",
        shorthand: "fhe",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_fhe.txt",
        get_song: radio_1live,
    },
    // RadioStation {
    //     name: "Kiraka",
    //     url: "http://www.wdr.de/radio/radiotext/streamtitle_kiraka.txt",
    //     get_song: radio_1live,
    // },
    RadioStation {
        name: "WDR-Event",
        shorthand: "wdre",
        url: "http://www.wdr.de/radio/radiotext/streamtitle_event.txt",
        get_song: radio_1live,
    },
    // Stations NDR
    RadioStation {
        name: "NDR 1 Niedersachsen",
        shorthand: "ndr1n",
        url: "http://www.ndr.de/public/radio_playlists/ndr1niedersachsen.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR 1 Radio MV",
        shorthand: "ndr1rmv",
        url: "http://www.ndr.de/public/radio_playlists/ndr1radiomv.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Welle Nord",
        shorthand: "ndrwn",
        url: "http://www.ndr.de/public/radio_playlists/ndr1wellenord.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR 90,3",
        shorthand: "ndr903",
        url: "http://www.ndr.de/public/radio_playlists/ndr903.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR 2",
        shorthand: "ndr2",
        url: "http://www.ndr.de/public/radio_playlists/ndr2.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Info",
        shorthand: "ndri",
        url: "http://www.ndr.de/public/radio_playlists/ndrinfo.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Kultur",
        shorthand: "ndrk",
        url: "http://www.ndr.de/public/radio_playlists/ndrkultur.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NJOY",
        shorthand: "njoy",
        url: "http://www.ndr.de/public/radio_playlists/njoy.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Blue",
        shorthand: "ndrb",
        url: "http://www.ndr.de/public/radio_playlists/ndrblue.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "NDR Plus",
        shorthand: "ndrp",
        url: "http://www.ndr.de/public/radio_playlists/ndrplus.json",
        get_song: radio_ndr,
    },
    RadioStation {
        name: "Antenne Niedersachsen On Air",
        shorthand: "antenneoa",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=29&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen 80er",
        shorthand: "antenne80",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=31&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen 90er",
        shorthand: "antenne90",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=422&nameSize=200&
                artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen Charts",
        shorthand: "antennec",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=30&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen Deutsch",
        shorthand: "antenned",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=565&nameSize=200
                &artistNameSize=200&descriptionSize=200&callback=radioplayer
                .playing.receive",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen X-Mas",
        shorthand: "antennexmas",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=110&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486056701107",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen Feel Good",
        shorthand: "antennefg",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=602&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486056790331",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Niedersachsen Love",
        shorthand: "antennelove",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=566&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486056946846",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Oldies",
        shorthand: "antenneold",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=32&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486057006247",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Relax",
        shorthand: "antennelax",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=454&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486057066325",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Rock",
        shorthand: "antennerock",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=33&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486057141342",
        get_song: radio_antenne,
    },
    RadioStation {
        name: "Antenne Schlager",
        shorthand: "antennesch",
        url: "http://np.radioplayer.de/qp/v3/onair?rpIds=601&nameSize=200
        &artistNameSize=200&descriptionSize=200&callback=radioplayer
        .playing.receive&_=1486057202504",
        get_song: radio_antenne,
    },
];
<|endoftext|>


<commit_before>//! Parser and syntax tree.

use std::char;

use charclass::CharClass;
use charclass::ascii;

/// A regular expression AST.
pub enum Expr {
    Empty,
    Range(char, char),
    Concatenate(~[Expr]),
    Alternate(~[Expr]),
    Repeat(~Expr, u32, Option<u32>, Greedy),
    Capture(~Expr)
}

/// Greediness flag.
pub enum Greedy {
    NonGreedy,
    Greedy
}

impl Not<Greedy> for Greedy {
    fn not(&self) -> Greedy {
        match *self {
            NonGreedy => Greedy,
            Greedy => NonGreedy
        }
    }
}

///
/// The maximum number of repetitions.  Any number larger than this will
/// cause a syntax error.  By honoring this limit, we prevent integer
/// overflow bugs in the library.
///
/// The value (100000) is taken from Ruby.
///
static REPEAT_MAX: u32 = 100000;

/// Parse a regular expression into an AST.  Fails on invalid syntax.
pub fn parse(input: &str) -> Expr {
    let mut s = State::new(input);
    let e = p_alternate(&mut s);
    if s.has_input() {
        // p_alternate() only terminates on an empty string or an extra
        // paren.  Since the string isn't empty, we infer the latter.
        fail!("unbalanced parenthesis")
    } else {
        e
    }
}

/// The parser state.  This tracks the position in the input string.
struct State<'a> {
    input: &'a str,
    prev: Option<&'a str>  // See `State::retreat`
}

impl<'a> State<'a> {
    fn new<'a>(input: &'a str) -> State<'a> {
        State {
            input: input,
            prev: None
        }
    }

    /// Consume and return the next character in the input, returning
    /// `None` if empty.
    fn advance(&mut self) -> Option<char> {
        self.prev = Some(self.input);
        if self.has_input() {
            let (c, input_) = self.input.slice_shift_char();
            self.input = input_;
            Some(c)
        } else {
            None
        }
    }

    /// Push the previously read character back onto the input.  This
    /// can only be called immediately after `advance`.
    fn retreat(&mut self) {
        self.input = self.prev.expect("nowhere to retreat");
        self.prev = None;
    }

    /// Return `true` if there is input remaining.
    fn has_input(&self) -> bool {
        self.input.len() > 0
    }
}

///
/// Parse alternation, e.g. `ducks|geese|swans`.
///
/// An alternation consists of zero or more concatenations, separated by
/// vertical bars `|`.
///
fn p_alternate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        items.push(p_concatenate(s));
        match s.advance() {
            Some(c) => {
                match c {
                    ')' => { s.retreat(); break },
                    '|' => continue,
                    _ => fail!("something bad happened; it's really bad")
                }
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Alternate(items)
    }
}

/// Parse concatenation, e.g. `abc`.
fn p_concatenate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        match s.advance() {
            Some(c) => match c {
                '|' | ')' => { s.retreat(); break },
                '(' => push_ignore_empty(&mut items, p_group(s)),
                '.' => items.push(Range('\0', char::MAX)),
                '\\' => items.push(cc_to_expr(p_escape(s))),
                '[' => items.push(cc_to_expr(p_charclass(s))),
                '?' => {
                    let e = pop_expr(&mut items);
                    items.push(match e {
                        Repeat(_, _, _, NonGreedy) => fail!("multiple repeat"),
                        Repeat(inner, min, max, Greedy) =>
                            Repeat(inner, min, max, NonGreedy),
                        _ => Repeat(~e, 0, Some(1), Greedy)
                    });
                },
                '+' => add_repeat(&mut items, 1, None),
                '*' => add_repeat(&mut items, 0, None),
                '{' => {
                    let (min, max) = p_repetition(s);
                    add_repeat(&mut items, min, max);
                },
                _ => items.push(Range(c, c))
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Concatenate(items)
    }
}

#[inline]
fn push_ignore_empty(items: &mut ~[Expr], e: Expr) {
    match e {
        Empty => (),
        _ => items.push(e)
    }
}

#[inline]
fn pop_expr(items: &mut ~[Expr]) -> Expr {
    items.pop_opt().expect("nothing to repeat")
}

#[inline]
fn add_repeat(items: &mut ~[Expr], min: u32, max: Option<u32>) {
    let e = pop_expr(items);
    items.push(match e {
        Repeat(..) => fail!("multiple repeat"),
        _ => Repeat(~e, min, max, Greedy)
    })
}

///
/// Parse a counted repetition (e.g. `a{2,3}`), sans the opening brace.
///
/// The following syntaxes are accepted:
///
/// * `{N}` – match exactly N repetitions;
/// * `{M,}` – at least M;
/// * `{,N}` – at most N;
/// * `{M,N}` – from M to N inclusive;
/// * `{,}` – zero or more (synonymous with `*`).
///
fn p_repetition(s: &mut State) -> (u32, Option<u32>) {
    let min = p_number(s);
    match s.advance() {
        Some(',') => {
            let max = p_number(s);
            match s.advance() {
                // {} or {M,} or {,N} or {M,N}
                Some('}') => {
                    let min_ = min.unwrap_or(0);
                    if check_repeat(min_, max) {
                        (min_, max)
                    } else {
                        fail!("bad repeat interval")
                    }
                },
                _ => fail!("invalid repeat")
            }
        },
        Some('}') => match min {
            // {N}
            Some(n) => (n, Some(n)),
            _ => fail!("invalid repeat")
        },
        _ => fail!("invalid repeat")
    }
}

#[inline]
fn check_repeat(min: u32, max: Option<u32>) -> bool {
    match max {
        Some(max_) => min <= max_,
        None => true
    }
}

///
/// Parse a non-negative integer, and return it as a `u32`.
///
/// This returns `None` if no number could be parsed, but fails directly
/// if the number is greater than `REPEAT_MAX`.
///
fn p_number(s: &mut State) -> Option<u32> {
    let mut acc = None;
    loop {
        match s.advance() {
            Some(c) if '0' <= c && c <= '9' => {
                let digit = c as u32 - '0' as u32;
                acc = Some(match acc {
                    Some(n) => {
                        let acc_ = 10 * n + digit;
                        if acc_ <= REPEAT_MAX {
                            acc_
                        } else {
                            fail!(format!("repeat must be <= {}", REPEAT_MAX))
                        }
                    },
                    None => digit
                });
            },
            _ => { s.retreat(); break }
        }
    }
    acc
}

/// Parse a group (e.g. `(hello)`), sans the opening parenthesis.
fn p_group(s: &mut State) -> Expr {
    let result = match s.advance() {
        Some('?') => match s.advance() {
            Some(c) => match c {
                ':' => p_alternate(s),
                '#' => p_comment(s),
                _ => fail!(format!("unknown extension: ?{}", c))
            },
            None => fail!("unexpected end of pattern")
        },
        _ => { s.retreat(); Capture(~p_alternate(s)) }
    };

    // Match the closing paren
    match s.advance() {
        Some(')') => result,
        _ => fail!("mismatched parenthesis")
    }
}

/// Consume all input up to the first closing parenthesis, and return
/// `Empty`.
fn p_comment(s: &mut State) -> Expr {
    loop {
        match s.advance() {
            Some(c) if c != ')' => continue,
            _ => { s.retreat(); break }
        }
    }
    Empty
}

/// Parse an escape sequence (e.g. `\d`), sans the leading backslash.
fn p_escape(s: &mut State) -> CharClass {
    match s.advance() {
        Some(c) => match c {
            'n' => CharClass::from_char('\n'),
            'r' => CharClass::from_char('\r'),
            't' => CharClass::from_char('\t'),

            'd' => ascii::digit,
            's' => ascii::space,
            'w' => ascii::word,

            'D' => ascii::digit.negate(),
            'S' => ascii::space.negate(),
            'W' => ascii::word.negate(),

            'x' => p_hex_escape(s, 2),
            'u' => p_hex_escape(s, 4),
            'U' => p_hex_escape(s, 8),

            _ if ascii::punct.includes(c) => CharClass::from_char(c),

            _ => fail!("invalid escape")
        },
        None => fail!("invalid escape")
    }
}

fn p_hex_escape(s: &mut State, n_digits: uint) -> CharClass {
    let mut acc = 0u32;
    for _ in range(0, n_digits) {
        acc = 16 * acc + match s.advance() {
            Some(c) => c.to_digit(16).expect("invalid escape") as u32,
            _ => fail!("invalid escape")
        };
    }
    let c = char::from_u32(acc).expect("character out of range");
    CharClass::from_char(c)
}

/// Parse a character class (e.g. `[a-z]`), sans the opening bracket.
fn p_charclass(s: &mut State) -> CharClass {
    let mut classes: ~[CharClass] = ~[];

    let negate = match s.advance() {
        Some('^') => true,
        _ => { s.retreat(); false }
    };

    loop {
        match s.advance() {
            Some(c) => match c {
                ']' => break,
                '-' => match p_charclass_token(s) {
                    Some(cc_hi) => match classes.pop_opt() {
                        Some(cc_lo) => {
                            // [a-z]
                            let lo = cc_lo.to_char().expect("bad character range");
                            let hi = cc_hi.to_char().expect("bad character range");
                            classes.push(CharClass::from_range(lo, hi));
                        },
                        None => classes.push(cc_hi)  // [-z]
                    },
                    None => classes.push(CharClass::from_char('-'))  // [a-]
                },
                _ => {
                    s.retreat();
                    classes.push(p_charclass_token(s).expect("invalid char class"));
                }
            },
            None => fail!("unexpected end of char class")
        }
    }

    let cc = CharClass::combine(classes);
    if negate {
        cc.negate()
    } else {
        cc
    }
}

fn p_charclass_token(s: &mut State) -> Option<CharClass> {
    match s.advance() {
        Some(c) => match c {
            ']' => { s.retreat(); None },
            '[' => Some(p_charclass(s)),
            '\\' => Some(p_escape(s)),
            _ => Some(CharClass::from_char(c))
        },
        None => None
    }
}

/// Reify a character class as an `Expr`.
fn cc_to_expr(cc: CharClass) -> Expr {
    Alternate(cc.ranges().iter().map(|&(lo, hi)| Range(lo, hi)).collect())
}
<commit_msg>Fix compile error<commit_after>//! Parser and syntax tree.

use std::char;

use charclass::CharClass;
use charclass::ascii;

/// A regular expression AST.
pub enum Expr {
    Empty,
    Range(char, char),
    Concatenate(~[Expr]),
    Alternate(~[Expr]),
    Repeat(~Expr, u32, Option<u32>, Greedy),
    Capture(~Expr)
}

/// Greediness flag.
pub enum Greedy {
    NonGreedy,
    Greedy
}

impl Not<Greedy> for Greedy {
    fn not(&self) -> Greedy {
        match *self {
            NonGreedy => Greedy,
            Greedy => NonGreedy
        }
    }
}

///
/// The maximum number of repetitions.  Any number larger than this will
/// cause a syntax error.  By honoring this limit, we prevent integer
/// overflow bugs in the library.
///
/// The value (100000) is taken from Ruby.
///
static REPEAT_MAX: u32 = 100000;

/// Parse a regular expression into an AST.  Fails on invalid syntax.
pub fn parse(input: &str) -> Expr {
    let mut s = State::new(input);
    let e = p_alternate(&mut s);
    if s.has_input() {
        // p_alternate() only terminates on an empty string or an extra
        // paren.  Since the string isn't empty, we infer the latter.
        fail!("unbalanced parenthesis")
    } else {
        e
    }
}

/// The parser state.  This tracks the position in the input string.
struct State<'a> {
    input: &'a str,
    prev: Option<&'a str>  // See `State::retreat`
}

impl<'a> State<'a> {
    fn new<'a>(input: &'a str) -> State<'a> {
        State {
            input: input,
            prev: None
        }
    }

    /// Consume and return the next character in the input, returning
    /// `None` if empty.
    fn advance(&mut self) -> Option<char> {
        self.prev = Some(self.input);
        if self.has_input() {
            let (c, input_) = self.input.slice_shift_char();
            self.input = input_;
            Some(c)
        } else {
            None
        }
    }

    /// Push the previously read character back onto the input.  This
    /// can only be called immediately after `advance`.
    fn retreat(&mut self) {
        self.input = self.prev.expect("nowhere to retreat");
        self.prev = None;
    }

    /// Return `true` if there is input remaining.
    fn has_input(&self) -> bool {
        self.input.len() > 0
    }
}

///
/// Parse alternation, e.g. `ducks|geese|swans`.
///
/// An alternation consists of zero or more concatenations, separated by
/// vertical bars `|`.
///
fn p_alternate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        items.push(p_concatenate(s));
        match s.advance() {
            Some(c) => {
                match c {
                    ')' => { s.retreat(); break },
                    '|' => continue,
                    _ => fail!("something bad happened; it's really bad")
                }
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Alternate(items)
    }
}

/// Parse concatenation, e.g. `abc`.
fn p_concatenate(s: &mut State) -> Expr {
    let mut items: ~[Expr] = ~[];

    loop {
        match s.advance() {
            Some(c) => match c {
                '|' | ')' => { s.retreat(); break },
                '(' => push_ignore_empty(&mut items, p_group(s)),
                '.' => items.push(Range('\0', char::MAX)),
                '\\' => items.push(cc_to_expr(p_escape(s))),
                '[' => items.push(cc_to_expr(p_charclass(s))),
                '?' => {
                    let e = pop_expr(&mut items);
                    items.push(match e {
                        Repeat(_, _, _, NonGreedy) => fail!("multiple repeat"),
                        Repeat(inner, min, max, Greedy) =>
                            Repeat(inner, min, max, NonGreedy),
                        _ => Repeat(~e, 0, Some(1), Greedy)
                    });
                },
                '+' => add_repeat(&mut items, 1, None),
                '*' => add_repeat(&mut items, 0, None),
                '{' => {
                    let (min, max) = p_repetition(s);
                    add_repeat(&mut items, min, max);
                },
                _ => items.push(Range(c, c))
            },
            None => break
        }
    }

    match items {
        [] => Empty,
        [e] => e,
        _ => Concatenate(items)
    }
}

#[inline]
fn push_ignore_empty(items: &mut ~[Expr], e: Expr) {
    match e {
        Empty => (),
        _ => items.push(e)
    }
}

#[inline]
fn pop_expr(items: &mut ~[Expr]) -> Expr {
    items.pop().expect("nothing to repeat")
}

#[inline]
fn add_repeat(items: &mut ~[Expr], min: u32, max: Option<u32>) {
    let e = pop_expr(items);
    items.push(match e {
        Repeat(..) => fail!("multiple repeat"),
        _ => Repeat(~e, min, max, Greedy)
    })
}

///
/// Parse a counted repetition (e.g. `a{2,3}`), sans the opening brace.
///
/// The following syntaxes are accepted:
///
/// * `{N}` – match exactly N repetitions;
/// * `{M,}` – at least M;
/// * `{,N}` – at most N;
/// * `{M,N}` – from M to N inclusive;
/// * `{,}` – zero or more (synonymous with `*`).
///
fn p_repetition(s: &mut State) -> (u32, Option<u32>) {
    let min = p_number(s);
    match s.advance() {
        Some(',') => {
            let max = p_number(s);
            match s.advance() {
                // {} or {M,} or {,N} or {M,N}
                Some('}') => {
                    let min_ = min.unwrap_or(0);
                    if check_repeat(min_, max) {
                        (min_, max)
                    } else {
                        fail!("bad repeat interval")
                    }
                },
                _ => fail!("invalid repeat")
            }
        },
        Some('}') => match min {
            // {N}
            Some(n) => (n, Some(n)),
            _ => fail!("invalid repeat")
        },
        _ => fail!("invalid repeat")
    }
}

#[inline]
fn check_repeat(min: u32, max: Option<u32>) -> bool {
    match max {
        Some(max_) => min <= max_,
        None => true
    }
}

///
/// Parse a non-negative integer, and return it as a `u32`.
///
/// This returns `None` if no number could be parsed, but fails directly
/// if the number is greater than `REPEAT_MAX`.
///
fn p_number(s: &mut State) -> Option<u32> {
    let mut acc = None;
    loop {
        match s.advance() {
            Some(c) if '0' <= c && c <= '9' => {
                let digit = c as u32 - '0' as u32;
                acc = Some(match acc {
                    Some(n) => {
                        let acc_ = 10 * n + digit;
                        if acc_ <= REPEAT_MAX {
                            acc_
                        } else {
                            fail!(format!("repeat must be <= {}", REPEAT_MAX))
                        }
                    },
                    None => digit
                });
            },
            _ => { s.retreat(); break }
        }
    }
    acc
}

/// Parse a group (e.g. `(hello)`), sans the opening parenthesis.
fn p_group(s: &mut State) -> Expr {
    let result = match s.advance() {
        Some('?') => match s.advance() {
            Some(c) => match c {
                ':' => p_alternate(s),
                '#' => p_comment(s),
                _ => fail!(format!("unknown extension: ?{}", c))
            },
            None => fail!("unexpected end of pattern")
        },
        _ => { s.retreat(); Capture(~p_alternate(s)) }
    };

    // Match the closing paren
    match s.advance() {
        Some(')') => result,
        _ => fail!("mismatched parenthesis")
    }
}

/// Consume all input up to the first closing parenthesis, and return
/// `Empty`.
fn p_comment(s: &mut State) -> Expr {
    loop {
        match s.advance() {
            Some(c) if c != ')' => continue,
            _ => { s.retreat(); break }
        }
    }
    Empty
}

/// Parse an escape sequence (e.g. `\d`), sans the leading backslash.
fn p_escape(s: &mut State) -> CharClass {
    match s.advance() {
        Some(c) => match c {
            'n' => CharClass::from_char('\n'),
            'r' => CharClass::from_char('\r'),
            't' => CharClass::from_char('\t'),

            'd' => ascii::digit,
            's' => ascii::space,
            'w' => ascii::word,

            'D' => ascii::digit.negate(),
            'S' => ascii::space.negate(),
            'W' => ascii::word.negate(),

            'x' => p_hex_escape(s, 2),
            'u' => p_hex_escape(s, 4),
            'U' => p_hex_escape(s, 8),

            _ if ascii::punct.includes(c) => CharClass::from_char(c),

            _ => fail!("invalid escape")
        },
        None => fail!("invalid escape")
    }
}

fn p_hex_escape(s: &mut State, n_digits: uint) -> CharClass {
    let mut acc = 0u32;
    for _ in range(0, n_digits) {
        acc = 16 * acc + match s.advance() {
            Some(c) => c.to_digit(16).expect("invalid escape") as u32,
            _ => fail!("invalid escape")
        };
    }
    let c = char::from_u32(acc).expect("character out of range");
    CharClass::from_char(c)
}

/// Parse a character class (e.g. `[a-z]`), sans the opening bracket.
fn p_charclass(s: &mut State) -> CharClass {
    let mut classes: ~[CharClass] = ~[];

    let negate = match s.advance() {
        Some('^') => true,
        _ => { s.retreat(); false }
    };

    loop {
        match s.advance() {
            Some(c) => match c {
                ']' => break,
                '-' => match p_charclass_token(s) {
                    Some(cc_hi) => match classes.pop() {
                        Some(cc_lo) => {
                            // [a-z]
                            let lo = cc_lo.to_char().expect("bad character range");
                            let hi = cc_hi.to_char().expect("bad character range");
                            classes.push(CharClass::from_range(lo, hi));
                        },
                        None => classes.push(cc_hi)  // [-z]
                    },
                    None => classes.push(CharClass::from_char('-'))  // [a-]
                },
                _ => {
                    s.retreat();
                    classes.push(p_charclass_token(s).expect("invalid char class"));
                }
            },
            None => fail!("unexpected end of char class")
        }
    }

    let cc = CharClass::combine(classes);
    if negate {
        cc.negate()
    } else {
        cc
    }
}

fn p_charclass_token(s: &mut State) -> Option<CharClass> {
    match s.advance() {
        Some(c) => match c {
            ']' => { s.retreat(); None },
            '[' => Some(p_charclass(s)),
            '\\' => Some(p_escape(s)),
            _ => Some(CharClass::from_char(c))
        },
        None => None
    }
}

/// Reify a character class as an `Expr`.
fn cc_to_expr(cc: CharClass) -> Expr {
    Alternate(cc.ranges().iter().map(|&(lo, hi)| Range(lo, hi)).collect())
}
<|endoftext|>


<commit_before>use liquid;
use liquid::Token::{self, Identifier};
use liquid::lexer::Element::{self, Expression, Tag, Raw};

use pulldown_cmark as cmark;

use error;

pub fn has_syntax_theme(_name: &str) -> error::Result<bool> {
    bail!("Themes are unsupported in this build.");
}

pub fn list_syntax_themes<'a>() -> Vec<&'a String> {
    vec![]
}

pub fn list_syntaxes<'a>() -> Vec<String> {
    vec![]
}

// The code is taken from Liquid which was adapted from
// https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/escape.rs
// Retrieved 2016-11-19.
fn html_escape(input: &str) -> String {
    let mut result = String::new();
    let mut last = 0;
    let mut skip = 0;
    for (i, c) in input.chars().enumerate() {
        if skip > 0 {
            skip -= 1;
            continue;
        }
        match c as char {
            '<' | '>' | '\'' | '"' | '&' => {
                result.push_str(&input[last..i]);
                last = i + 1;
                let escaped = match c as char {
                    '<' => "<",
                    '>' => ">",
                    '\'' => "'",
                    '"' => """,
                    '&' => "&",
                    _ => unreachable!(),
                };
                result.push_str(escaped);
            }
            _ => {}
        }
    }
    if last < input.len() {
        result.push_str(&input[last..]);
    }
    result
}

struct CodeBlock {
    lang: Option<String>,
    code: String,
}

impl liquid::Renderable for CodeBlock {
    fn render(&self, _: &mut liquid::Context) -> Result<Option<String>, liquid::Error> {
        if let Some(ref lang) = self.lang {
            Ok(Some(format!("
{}
",
                            lang,
                            self.code)))
        } else {
            Ok(Some(format!("
{}
", self.code)))
        }
    }
}

pub fn initialize_codeblock(arguments: &[Token],
                            tokens: &[Element],
                            _theme_name: &str)
                            -> Result<Box<liquid::Renderable>, liquid::Error> {

    let content = tokens
        .iter()
        .fold("".to_owned(), |a, b| {
            match *b {
                    Expression(_, ref text) |
                    Tag(_, ref text) |
                    Raw(ref text) => text,
                }
                .to_owned() + &a
        });

    let lang = match arguments.iter().next() {
        Some(&Identifier(ref x)) => Some(x.clone()),
        _ => None,
    };

    let content = html_escape(&content);

    Ok(Box::new(CodeBlock {
                    lang: lang,
                    code: content,
                }))
}

pub type DecoratedParser<'a> = cmark::Parser<'a>;

pub fn decorate_markdown<'a>(parser: cmark::Parser<'a>, _theme_name: &str) -> DecoratedParser<'a> {
    parser
}

#[cfg(test)]
mod test {

    use std::default::Default;
    use liquid::{self, Renderable, LiquidOptions, Context};

    use super::*;

    const CODE_BLOCK: &'static str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
";

    const CODEBLOCK_RENDERED: &'static str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn codeblock_renders_rust() {
        let mut options: LiquidOptions = Default::default();
        options
            .blocks
            .insert("codeblock".to_string(),
                    Box::new(|_, args, tokens, _| {
                                 initialize_codeblock(args, tokens, "base16-ocean.dark")
                             }));
        let template = liquid::parse(&format!("{{% codeblock rust %}}{}{{% endcodeblock %}}",
                                              CODE_BLOCK),
                                     options)
                .unwrap();
        let mut data = Context::new();
        let output = template.render(&mut data);
        assert_eq!(output.unwrap(), Some(CODEBLOCK_RENDERED.to_string()));
    }

    const MARKDOWN_RENDERED: &'static str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn decorate_markdown_renders_rust() {
        let html = format!("```rust
{}
```",
                           CODE_BLOCK);

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(&mut buf, decorate_markdown(parser, "base16-ocean.dark"));
        assert_eq!(buf, MARKDOWN_RENDERED);
    }
}
<commit_msg>chore: Fix clippy<commit_after>use liquid;
use liquid::Token::{self, Identifier};
use liquid::lexer::Element::{self, Expression, Tag, Raw};

use pulldown_cmark as cmark;

use error;

pub fn has_syntax_theme(_name: &str) -> error::Result<bool> {
    bail!("Themes are unsupported in this build.");
}

pub fn list_syntax_themes<'a>() -> Vec<&'a String> {
    vec![]
}

pub fn list_syntaxes() -> Vec<String> {
    vec![]
}

// The code is taken from Liquid which was adapted from
// https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/escape.rs
// Retrieved 2016-11-19.
fn html_escape(input: &str) -> String {
    let mut result = String::new();
    let mut last = 0;
    let mut skip = 0;
    for (i, c) in input.chars().enumerate() {
        if skip > 0 {
            skip -= 1;
            continue;
        }
        match c as char {
            '<' | '>' | '\'' | '"' | '&' => {
                result.push_str(&input[last..i]);
                last = i + 1;
                let escaped = match c as char {
                    '<' => "<",
                    '>' => ">",
                    '\'' => "'",
                    '"' => """,
                    '&' => "&",
                    _ => unreachable!(),
                };
                result.push_str(escaped);
            }
            _ => {}
        }
    }
    if last < input.len() {
        result.push_str(&input[last..]);
    }
    result
}

struct CodeBlock {
    lang: Option<String>,
    code: String,
}

impl liquid::Renderable for CodeBlock {
    fn render(&self, _: &mut liquid::Context) -> Result<Option<String>, liquid::Error> {
        if let Some(ref lang) = self.lang {
            Ok(Some(format!("
{}
",
                            lang,
                            self.code)))
        } else {
            Ok(Some(format!("
{}
", self.code)))
        }
    }
}

pub fn initialize_codeblock(arguments: &[Token],
                            tokens: &[Element],
                            _theme_name: &str)
                            -> Result<Box<liquid::Renderable>, liquid::Error> {

    let content = tokens
        .iter()
        .fold("".to_owned(), |a, b| {
            match *b {
                    Expression(_, ref text) |
                    Tag(_, ref text) |
                    Raw(ref text) => text,
                }
                .to_owned() + &a
        });

    let lang = match arguments.iter().next() {
        Some(&Identifier(ref x)) => Some(x.clone()),
        _ => None,
    };

    let content = html_escape(&content);

    Ok(Box::new(CodeBlock {
                    lang: lang,
                    code: content,
                }))
}

pub type DecoratedParser<'a> = cmark::Parser<'a>;

pub fn decorate_markdown<'a>(parser: cmark::Parser<'a>, _theme_name: &str) -> DecoratedParser<'a> {
    parser
}

#[cfg(test)]
mod test {

    use std::default::Default;
    use liquid::{self, Renderable, LiquidOptions, Context};

    use super::*;

    const CODE_BLOCK: &'static str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
";

    const CODEBLOCK_RENDERED: &'static str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn codeblock_renders_rust() {
        let mut options: LiquidOptions = Default::default();
        options
            .blocks
            .insert("codeblock".to_string(),
                    Box::new(|_, args, tokens, _| {
                                 initialize_codeblock(args, tokens, "base16-ocean.dark")
                             }));
        let template = liquid::parse(&format!("{{% codeblock rust %}}{}{{% endcodeblock %}}",
                                              CODE_BLOCK),
                                     options)
                .unwrap();
        let mut data = Context::new();
        let output = template.render(&mut data);
        assert_eq!(output.unwrap(), Some(CODEBLOCK_RENDERED.to_string()));
    }

    const MARKDOWN_RENDERED: &'static str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn decorate_markdown_renders_rust() {
        let html = format!("```rust
{}
```",
                           CODE_BLOCK);

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(&mut buf, decorate_markdown(parser, "base16-ocean.dark"));
        assert_eq!(buf, MARKDOWN_RENDERED);
    }
}
<|endoftext|>


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

const PRIME_NUMBER: &[u64] = &[
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
    101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
    197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
    311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
    431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
    557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
    661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
    809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
    937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009,
];

type Record = Vec<(u64, Vec<u64>)>;

fn max_product<'a>(n: u64, table: &'a mut HashMap<u64, Record>) -> Option<&'a Record> {
    match n {
        2 | 3 => &Some(vec![(n, vec![n])]),
        1 => None,
        _ => {
            for pn in PRIME_NUMBER[0..prime_nums_below(n)] {
                let records = record_of_this_number((n - i), table);
            }
        }
    };
}

fn prime_nums_below(n: u64) -> usize {
    PRIME_NUMBER.iter().rposition(|i| *i < n).unwrap_or(0)
}

fn record_of_this_number(n: u64, table: &HashMap<u64, Record>) -> Option<&Record> {
    let a = table.get(&n);
    if a.is_none() {
        max_product(n, table);
    } else {
        a
    }
}

fn update_table(n: u64, i: u64, re: &(u64, Vec<u64>), table: &HashMap<u64, Record>) {
    let a = (i * re.0, {
        let b = re.1.clone();
        b.push(i);
        b
    });
    let b = table.entry(n).or_insert(vec![]);
    b.push(a);
    b.sort_by(|x, y| y.partial_cmp(x).unwrap());
}

//fn check_if_already_in(n:u64, res:&R)

//fn main() {}
<commit_msg>finish rust version<commit_after>use std::collections::HashMap;

const PRIME_NUMBER: &[u64] = &[
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
    101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
    197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
    311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
    431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
    557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
    661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
    809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
    937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009,
];

#[derive(Clone, Debug)]
struct Record {
    inner: (u128, Vec<u64>),
}

type Records = Vec<Record>;

impl Record {
    fn new(n: u64, v: Vec<u64>) -> Self {
        Self {
            inner: (n as u128, v),
        }
    }

    fn update_record(i: u64, other: &Self) -> Self {
        Self {
            inner: (i as u128 * other.inner.0, {
                let mut a = other.inner.1.clone();
                a.push(i);
                a
            }),
        }
    }
}

fn max_product<'a>(
    n: u64,
    table: &'a mut HashMap<u64, Records>,
    prime_n: &[u64],
) -> Option<&'a Records> {
    let empty_trick = vec![];
    match n {
        1 => None,
        _ => {
            for pn in prime_n {
                if *pn < n {
                    let records = match table.get(&(n - *pn)) {
                        Some(records) => records,
                        None => max_product(n - *pn, table, prime_n).unwrap_or(&empty_trick),
                    };

                    if let Some(record) = records.iter().find(|r| !r.inner.1.contains(pn)) {
                        let new_re = Record::update_record(*pn, record);
                        let update_re = table.entry(n).or_insert(vec![]);
                        update_re.push(new_re);
                        update_re.sort_by(|x, y| y.inner.0.partial_cmp(&x.inner.0).unwrap());
                    }
                }
            }

            table.get(&n)
        }
    }
}

fn main() {
    let mut table: HashMap<u64, Records> = HashMap::new();
    table.insert(2, vec![Record::new(2, vec![2])]);
    table.insert(3, vec![Record::new(3, vec![3])]);

    let reverse_prime_vec: Vec<u64> = PRIME_NUMBER.to_vec().into_iter().rev().collect();

    println!(
        "{:?}",
        max_product(35, &mut table, &reverse_prime_vec).unwrap()[0]
    );

    println!(
        "{:?}",
        max_product(500, &mut table, &reverse_prime_vec).unwrap()[0]
    );

    println!(
        "{:?}",
        max_product(1000, &mut table, &reverse_prime_vec).unwrap()[0]
    );
}
<|endoftext|>


<commit_before>#[feature(globs)];
#[feature(struct_variant)];
#[feature(macro_rules)];
extern mod std;
extern mod extra;
use extra::getopts;
use basics::*;
use std::io::File;

mod basics;
mod policies;
mod raft;
mod sim;

/* features to support selectmatch */

/* SelectBox is a wrapper to allow calling select() on pointers */
struct SelectBox<'self> {
    inner: &'self mut std::select::Select,
}

impl<'self> std::rt::shouldnt_be_public::SelectInner for SelectBox<'self> {
    fn optimistic_check(&mut self) -> bool {
        self.inner.optimistic_check()
    }
    fn block_on(&mut self, sched: &mut std::rt::sched::Scheduler, task: std::rt::BlockedTask) -> bool {
        self.inner.block_on(sched, task)
    }
    fn unblock_from(&mut self) -> bool {
        self.inner.unblock_from()
    }
}

impl<'self> std::select::Select for SelectBox<'self> {
}

/* recursive helper for selectmatch macro */
macro_rules! selectmatch_rec(
    ($index:expr,
     $port:expr => $action:expr,
     $( $port_rest:expr => $action_rest:expr ),+) => (
        if $index == 0 {
            $action
        } else {
            $index -= 1;
            selectmatch_rec!($index, $( $port_rest => $action_rest ),*)
        }
    );
    ($index:expr, $port:expr => $action:expr) => (
        if $index == 0 {
            $action
        } else {
            fail!("Bogus return value from select()");
        }
    );
)

/* bearable syntax for calling select with SelectBox */
macro_rules! selectmatch(
     ($( $port:expr => $action:expr ),+) => (
        {
            let mut selectmatch_i : uint = std::select::select([$( SelectBox{ inner: &mut $port as &mut std::select::Select } ),+]);
            selectmatch_rec!(selectmatch_i, $( $port => $action ),+)
        }
    );
)

/* end selectmatch */

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("algorithm"),
        getopts::optopt("cluster"),
        getopts::optopt("logs"),
        getopts::optopt("maxticks"),
        getopts::optopt("samples"),
        getopts::optopt("tasks"),
        getopts::optopt("terms"),
        getopts::optopt("timeout"),
        getopts::optopt("timing"),
        getopts::optopt("trace"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println!("--algorithm=ALGO Algorithm variant (default submission)");
        println!("--cluster=POLICY Type/size of cluster (default 5)");
        println!("-h, --help       Print this help message");
        println!("--logs=POLICY    Log length policy (default same)");
        println!("--maxticks=N     Number of simulation ticks after which ");
        println!("                 to stop a sample (default 5,000,000)");
        println!("--samples=N      Number of simulations (default 10,000)");
        println!("--tasks=N        Number of parallel jobs (default {})",
                 std::rt::default_sched_threads() - 1);
        println!("--terms=POLICY   Initial terms policy (default same)");
        println!("--timeout=MS     Milliseconds after which to stop");
        println!("                 (default 0 meaning infinity)");
        println!("--timing=POLICY  Network timing policy (default LAN)");
        println!("--trace=N         Dump N simulation traces to files (default 0)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let algorithm : ~str = match matches.opt_str("algorithm") {
        Some(s) => { s },
        None => { ~"submission" },
    };
    let cluster : ~str = match matches.opt_str("cluster") {
        Some(s) => { s },
        None => { ~"5" },
    };
    let log_length : ~str = match matches.opt_str("logs") {
        Some(s) => { s },
        None => { ~"same" },
    };
    let max_ticks : Time = match matches.opt_str("maxticks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { Time(i) },
            None => {
                usage();
                fail!(format!("Couldn't parse max number of ticks from '{}'", s));
            },
        }},
        None => { Time(5000000) },
    };
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 10000 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { std::rt::default_sched_threads() - 1 },
    };
    let terms : ~str = match matches.opt_str("terms") {
        Some(s) => { s },
        None => { ~"same" },
    };
    let timeout : uint = match matches.opt_str("timeout") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse timeout from '{}'", s));
            },
        }},
        None => { 0 },
    };
    let timeout = if timeout == 0 {
        !0
    } else {
        timeout
    };
    let timing : ~str = match matches.opt_str("timing") {
        Some(s) => { s },
        None => { ~"LAN" },
    };
    let trace : uint = match matches.opt_str("trace") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of traces from '{}'", s));
            },
        }},
        None => { 0 },
    };

    let mut meta : ~[(~str, ~str)] = ~[];
    meta.push((~"algorithm",  algorithm.clone()));
    meta.push((~"log_length", log_length.clone()));
    meta.push((~"cluster",    cluster.clone()));
    meta.push((~"maxticks",   format!("{}", max_ticks)));
    meta.push((~"tasks",      format!("{}", num_tasks)));
    meta.push((~"terms",      terms.clone()));
    meta.push((~"timing",     timing.clone()));
    meta.push((~"trials_req", format!("{}", num_samples)));
    meta.push((~"timeout",    format!("{}", timeout)));

    println!("Algorithm:  {}", algorithm)
    println!("Cluster:    {}", cluster)
    println!("Log length: {}", log_length)
    println!("Max ticks:  {}", max_ticks)
    println!("Tasks:      {}", num_tasks)
    println!("Terms:      {}", terms)
    println!("Timing:     {}", timing)
    println!("Req. trials:{}", num_samples)
    println!("Timeout:    {} ms", timeout)

    let start_ns = extra::time::precise_time_ns();

    let mut signals = std::io::signal::Listener::new();
    signals.register(std::io::signal::Interrupt);

    let sim_opts = sim::SimOpts {
       cluster: cluster,
       timing: timing,
       log_length: log_length,
       algorithm: algorithm,
       terms: terms,
       max_ticks: max_ticks,
       trace: trace,
    };
    let samples = if num_tasks <= 1 {
        run_task(range(0, num_samples), &sim_opts, &signals.port)
    } else {
        let (mut port, chan): (std::comm::Port<~[Sample]>, std::comm::Chan<~[Sample]>) = stream();
        let chan = std::comm::SharedChan::new(chan);
        let mut exit_chans : ~[std::comm::Chan<()>] = ~[];
        let exit = || {
            for c in exit_chans.iter() {
                c.send(());
            }
        };
        for tid in range(0, num_tasks) {
            let (exit_port, exit_chan): (std::comm::Port<()>, std::comm::Chan<()>) = stream();
            exit_chans.push(exit_chan);
            let child_chan = chan.clone();
            let child_opts = sim_opts.clone();
            do spawn {
                let runs = range(num_samples / num_tasks * tid,
                                 if tid == num_tasks - 1 {
                                     num_samples // get odd tasks left over
                                 } else {
                                     num_samples / num_tasks * (tid + 1)
                                 });
                child_chan.send(run_task(runs, &child_opts, &exit_port));
            }
        }

        let mut samples = ~[];
        samples.reserve(num_samples);
        let mut tasks_outstanding = num_tasks;
        let mut timeout_timer = std::io::timer::Timer::new().unwrap();
        // simulate a one_shot timer with a periodic timer and a boolean, since
        // I can't get the types to work otherwise
        let mut timeout_port = timeout_timer.periodic(timeout as u64);
        let mut timed_out = false;
        while tasks_outstanding > 0 {
            selectmatch!(
                signals.port.x => {
                    match signals.port.recv() {
                        std::io::signal::Interrupt => {
                            println!("\nCtrl-C: exiting");
                        },
                        _ => fail!("Unexpected signal"),
                    }
                },
                timeout_port.x => {
                    timeout_port.recv();
                    if !timed_out {
                        println!("Timeout");
                        timed_out = true;
                        exit();
                    }
                },
                port.x => {
                    tasks_outstanding -= 1;
                    samples.push_all(port.recv());
                }
            )
        }
        sort_samples(samples);
        samples
    };

    let end_ns = extra::time::precise_time_ns();
    let elapsed_ns = end_ns - start_ns;
    meta.push((~"wall",   format!("{}", elapsed_ns as f64 / 1e9)));
    meta.push((~"trials", format!("{}", samples.len())));
    meta.push((~"min",    format!("{}", samples[0].ticks)));
    meta.push((~"median", format!("{}", samples[samples.len()/2].ticks)));
    meta.push((~"max",    format!("{}", samples[samples.len()-1].ticks)));

    println!("Trials:     {}",       samples.len());
    println!("Min:        {} ticks", samples[0].ticks);
    println!("Median:     {} ticks", samples[samples.len()/2].ticks);
    println!("Max:        {} ticks", samples[samples.len()-1].ticks);
    println!("Wall:       {:.2f} s", elapsed_ns as f64 / 1e9);

    let metaf = &mut File::create(&Path::new("meta.csv")).unwrap() as &mut Writer;
    for &(ref k, ref _v) in meta.iter() {
        write!(metaf, "{}, ", *k);
    }
    write!(metaf, "\n");
    for &(ref _k, ref v) in meta.iter() {
        write!(metaf, "{}, ", *v);
    }
    write!(metaf, "\n");

    let runf = &mut File::create(&Path::new("samples.csv")).unwrap() as &mut Writer;
    writeln!(runf, "election_time,run");
    for sample in samples.iter() {
        writeln!(runf, "{},{}", sample.ticks, sample.run);
    }
}

#[deriving(Clone)]
struct Sample {
    run: uint,
    ticks: Time,
}

fn sort_samples(samples: &mut [Sample]) {
    extra::sort::quick_sort(samples, |x,y| x.ticks <= y.ticks);
}

fn run_task<T: Send>(mut runs: std::iter::Range<uint>, opts: &sim::SimOpts, exit_port: &Port<T>) -> ~[Sample] {
    let mut samples = ~[];
    samples.reserve(runs.size_hint().first());
    for run in runs {
        if exit_port.peek() {
            return samples;
        }
        let sample = Sample {
            run: run,
            ticks: sim::simulate(run, opts),
        };
        samples.push(sample);
    }
    sort_samples(samples);
    return samples;
}
<commit_msg>Round-robin runs per thread so the tracing threads don't straggle<commit_after>#[feature(globs)];
#[feature(struct_variant)];
#[feature(macro_rules)];
extern mod std;
extern mod extra;
use extra::getopts;
use basics::*;
use std::io::File;

mod basics;
mod policies;
mod raft;
mod sim;

/* features to support selectmatch */

/* SelectBox is a wrapper to allow calling select() on pointers */
struct SelectBox<'self> {
    inner: &'self mut std::select::Select,
}

impl<'self> std::rt::shouldnt_be_public::SelectInner for SelectBox<'self> {
    fn optimistic_check(&mut self) -> bool {
        self.inner.optimistic_check()
    }
    fn block_on(&mut self, sched: &mut std::rt::sched::Scheduler, task: std::rt::BlockedTask) -> bool {
        self.inner.block_on(sched, task)
    }
    fn unblock_from(&mut self) -> bool {
        self.inner.unblock_from()
    }
}

impl<'self> std::select::Select for SelectBox<'self> {
}

/* recursive helper for selectmatch macro */
macro_rules! selectmatch_rec(
    ($index:expr,
     $port:expr => $action:expr,
     $( $port_rest:expr => $action_rest:expr ),+) => (
        if $index == 0 {
            $action
        } else {
            $index -= 1;
            selectmatch_rec!($index, $( $port_rest => $action_rest ),*)
        }
    );
    ($index:expr, $port:expr => $action:expr) => (
        if $index == 0 {
            $action
        } else {
            fail!("Bogus return value from select()");
        }
    );
)

/* bearable syntax for calling select with SelectBox */
macro_rules! selectmatch(
     ($( $port:expr => $action:expr ),+) => (
        {
            let mut selectmatch_i : uint = std::select::select([$( SelectBox{ inner: &mut $port as &mut std::select::Select } ),+]);
            selectmatch_rec!(selectmatch_i, $( $port => $action ),+)
        }
    );
)

/* end selectmatch */

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("algorithm"),
        getopts::optopt("cluster"),
        getopts::optopt("logs"),
        getopts::optopt("maxticks"),
        getopts::optopt("samples"),
        getopts::optopt("tasks"),
        getopts::optopt("terms"),
        getopts::optopt("timeout"),
        getopts::optopt("timing"),
        getopts::optopt("trace"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println!("--algorithm=ALGO Algorithm variant (default submission)");
        println!("--cluster=POLICY Type/size of cluster (default 5)");
        println!("-h, --help       Print this help message");
        println!("--logs=POLICY    Log length policy (default same)");
        println!("--maxticks=N     Number of simulation ticks after which ");
        println!("                 to stop a sample (default 5,000,000)");
        println!("--samples=N      Number of simulations (default 10,000)");
        println!("--tasks=N        Number of parallel jobs (default {})",
                 std::rt::default_sched_threads() - 1);
        println!("--terms=POLICY   Initial terms policy (default same)");
        println!("--timeout=MS     Milliseconds after which to stop");
        println!("                 (default 0 meaning infinity)");
        println!("--timing=POLICY  Network timing policy (default LAN)");
        println!("--trace=N         Dump N simulation traces to files (default 0)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let algorithm : ~str = match matches.opt_str("algorithm") {
        Some(s) => { s },
        None => { ~"submission" },
    };
    let cluster : ~str = match matches.opt_str("cluster") {
        Some(s) => { s },
        None => { ~"5" },
    };
    let log_length : ~str = match matches.opt_str("logs") {
        Some(s) => { s },
        None => { ~"same" },
    };
    let max_ticks : Time = match matches.opt_str("maxticks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { Time(i) },
            None => {
                usage();
                fail!(format!("Couldn't parse max number of ticks from '{}'", s));
            },
        }},
        None => { Time(5000000) },
    };
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 10000 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { std::rt::default_sched_threads() - 1 },
    };
    let terms : ~str = match matches.opt_str("terms") {
        Some(s) => { s },
        None => { ~"same" },
    };
    let timeout : uint = match matches.opt_str("timeout") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse timeout from '{}'", s));
            },
        }},
        None => { 0 },
    };
    let timeout = if timeout == 0 {
        !0
    } else {
        timeout
    };
    let timing : ~str = match matches.opt_str("timing") {
        Some(s) => { s },
        None => { ~"LAN" },
    };
    let trace : uint = match matches.opt_str("trace") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of traces from '{}'", s));
            },
        }},
        None => { 0 },
    };

    let mut meta : ~[(~str, ~str)] = ~[];
    meta.push((~"algorithm",  algorithm.clone()));
    meta.push((~"log_length", log_length.clone()));
    meta.push((~"cluster",    cluster.clone()));
    meta.push((~"maxticks",   format!("{}", max_ticks)));
    meta.push((~"tasks",      format!("{}", num_tasks)));
    meta.push((~"terms",      terms.clone()));
    meta.push((~"timing",     timing.clone()));
    meta.push((~"trials_req", format!("{}", num_samples)));
    meta.push((~"timeout",    format!("{}", timeout)));

    println!("Algorithm:  {}", algorithm)
    println!("Cluster:    {}", cluster)
    println!("Log length: {}", log_length)
    println!("Max ticks:  {}", max_ticks)
    println!("Tasks:      {}", num_tasks)
    println!("Terms:      {}", terms)
    println!("Timing:     {}", timing)
    println!("Req. trials:{}", num_samples)
    println!("Timeout:    {} ms", timeout)

    let start_ns = extra::time::precise_time_ns();

    let mut signals = std::io::signal::Listener::new();
    signals.register(std::io::signal::Interrupt);

    let sim_opts = sim::SimOpts {
       cluster: cluster,
       timing: timing,
       log_length: log_length,
       algorithm: algorithm,
       terms: terms,
       max_ticks: max_ticks,
       trace: trace,
    };
    let samples = if num_tasks <= 1 {
        run_task(std::iter::range_step(0, num_samples, 1), &sim_opts, &signals.port)
    } else {
        let (mut port, chan): (std::comm::Port<~[Sample]>, std::comm::Chan<~[Sample]>) = stream();
        let chan = std::comm::SharedChan::new(chan);
        let mut exit_chans : ~[std::comm::Chan<()>] = ~[];
        let exit = || {
            for c in exit_chans.iter() {
                c.send(());
            }
        };
        for tid in range(0, num_tasks) {
            let (exit_port, exit_chan): (std::comm::Port<()>, std::comm::Chan<()>) = stream();
            exit_chans.push(exit_chan);
            let child_chan = chan.clone();
            let child_opts = sim_opts.clone();
            do spawn {
                let runs = std::iter::range_step(tid, num_samples, num_tasks);
                child_chan.send(run_task(runs, &child_opts, &exit_port));
            }
        }

        let mut samples = ~[];
        samples.reserve(num_samples);
        let mut tasks_outstanding = num_tasks;
        let mut timeout_timer = std::io::timer::Timer::new().unwrap();
        // simulate a one_shot timer with a periodic timer and a boolean, since
        // I can't get the types to work otherwise
        let mut timeout_port = timeout_timer.periodic(timeout as u64);
        let mut timed_out = false;
        while tasks_outstanding > 0 {
            selectmatch!(
                signals.port.x => {
                    match signals.port.recv() {
                        std::io::signal::Interrupt => {
                            println!("\nCtrl-C: exiting");
                        },
                        _ => fail!("Unexpected signal"),
                    }
                },
                timeout_port.x => {
                    timeout_port.recv();
                    if !timed_out {
                        println!("Timeout");
                        timed_out = true;
                        exit();
                    }
                },
                port.x => {
                    tasks_outstanding -= 1;
                    samples.push_all(port.recv());
                }
            )
        }
        sort_samples(samples);
        samples
    };

    let end_ns = extra::time::precise_time_ns();
    let elapsed_ns = end_ns - start_ns;
    meta.push((~"wall",   format!("{}", elapsed_ns as f64 / 1e9)));
    meta.push((~"trials", format!("{}", samples.len())));
    meta.push((~"min",    format!("{}", samples[0].ticks)));
    meta.push((~"median", format!("{}", samples[samples.len()/2].ticks)));
    meta.push((~"max",    format!("{}", samples[samples.len()-1].ticks)));

    println!("Trials:     {}",       samples.len());
    println!("Min:        {} ticks", samples[0].ticks);
    println!("Median:     {} ticks", samples[samples.len()/2].ticks);
    println!("Max:        {} ticks", samples[samples.len()-1].ticks);
    println!("Wall:       {:.2f} s", elapsed_ns as f64 / 1e9);

    let metaf = &mut File::create(&Path::new("meta.csv")).unwrap() as &mut Writer;
    for &(ref k, ref _v) in meta.iter() {
        write!(metaf, "{}, ", *k);
    }
    write!(metaf, "\n");
    for &(ref _k, ref v) in meta.iter() {
        write!(metaf, "{}, ", *v);
    }
    write!(metaf, "\n");

    let runf = &mut File::create(&Path::new("samples.csv")).unwrap() as &mut Writer;
    writeln!(runf, "election_time,run");
    for sample in samples.iter() {
        writeln!(runf, "{},{}", sample.ticks, sample.run);
    }
}

#[deriving(Clone)]
struct Sample {
    run: uint,
    ticks: Time,
}

fn sort_samples(samples: &mut [Sample]) {
    extra::sort::quick_sort(samples, |x,y| x.ticks <= y.ticks);
}

fn run_task<T: Send>(mut runs: std::iter::RangeStep<uint>, opts: &sim::SimOpts, exit_port: &Port<T>) -> ~[Sample] {
    let mut samples = ~[];
    samples.reserve(runs.size_hint().first());
    for run in runs {
        if exit_port.peek() {
            return samples;
        }
        let sample = Sample {
            run: run,
            ticks: sim::simulate(run, opts),
        };
        samples.push(sample);
    }
    sort_samples(samples);
    return samples;
}
<|endoftext|>


<commit_before>#![allow(ctypes)]
#![no_std]
#![no_main]
#![feature(globs)]
#![feature(asm)]

extern crate core;

use core::container::Container;
use start32::MultiBootInfo;

mod mboot;
mod start32;

static kernel_base : uint = - (1 << 30);

extern "rust-intrinsic" {
    fn offset<T>(dst: *T, offset: int) -> *T;
}
unsafe fn mut_offset<T>(dst: *mut T, off: int) -> *mut T {
	offset(dst as *T, off) as *mut T
}

fn range(lo: uint, hi: uint, it: |uint| -> ()) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

trait Writer {
	fn write(&mut self, string : &str);
}

fn writeUInt<T : Writer>(out : &mut T, x : uint) {
	out.write("<num>");
}

struct Console {
	buffer : *mut u16,
	position : uint,
	width : uint,
	height : uint,
	color : u16
}

impl Console {
	fn new(buffer : *mut u16, width : uint, height : uint) -> Console {
		Console {
			buffer : buffer,
			position : 0,
			width : width,
			height : height,
			color : 0x0f00,
		}
	}

	fn putchar(&mut self, position : uint, c : u16) {
	}

	fn clear(&mut self) {
		range(0, 80*25, |i| { unsafe {
			*mut_offset(self.buffer, i as int) = 0;
		}});
		self.position = 0;
	}
}

impl Writer for Console {
	fn write(&mut self, string : &str) {
		range(0, string.len(), |i| {
			let c = string[i] as u16;
			unsafe {
				*mut_offset(self.buffer, self.position as int) = self.color | c;
			}
			self.position += 1;
			if self.position > self.width * self.height {
				// TODO scroll
				self.position = 0;
			}
		});
	}
}

#[no_mangle]
pub unsafe fn start64() {
	let mut con = Console::new((kernel_base + 0xb8000) as *mut u16, 80, 25);
	con.clear();
	con.write("Hello World! ");
	writeUInt(&mut con, (*MultiBootInfo()).mem_upper as uint);
	loop {}
}

#[no_mangle]
pub unsafe fn abort() {
	let mut con = Console::new((kernel_base + 0xb8000) as *mut u16, 80, 25);
	con.write("aborted.");
	loop{} // asm!("cli; hlt")
}

#[no_mangle]
pub unsafe fn breakpoint() {
	asm!("int3")
}
<commit_msg>Actual number formatting<commit_after>#![allow(ctypes)]
#![no_std]
#![no_main]
#![feature(globs)]
#![feature(asm)]

extern crate core;

use core::cmp::min;
use core::container::Container;
use start32::MultiBootInfo;

mod mboot;
mod start32;

static kernel_base : uint = - (1 << 30);

extern "rust-intrinsic" {
    fn offset<T>(dst: *T, offset: int) -> *T;
}
unsafe fn mut_offset<T>(dst: *mut T, off: int) -> *mut T {
	offset(dst as *T, off) as *mut T
}

fn range(lo: uint, hi: uint, it: |uint| -> ()) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

trait Writer {
	fn putc(&mut self, c : char);

	fn write(&mut self, string : &str) {
		range(0, string.len(), |i| {
			self.putc(string[i] as char);
		});
	}

	fn writeUInt(&mut self, x : uint) {
		self.writeNumber(0, false, 10, false, x);
	}

	fn writeNumber(&mut self, width : uint, leading_zero : bool, base : uint, show_base : bool, num : uint)
	{
		if show_base && base == 16 {
			self.write("0x");
		}
		let mut buf : [u8, ..32] = [0, ..32];
		let mut len = 0;
		let mut num_ = num;
		loop {
			let i = num_ % base;
			buf[len] = "0123456789abcdef"[i];
			len += 1;
			num_ /= base;
			if num_ == 0 { break; }
		}
		if width > 0 {
			let c = if leading_zero { '0' } else { ' ' };
			range(0, min(len, width), |_| {
				self.putc(c);
			});
		}
		while len > 0 {
			len -= 1;
			self.putc(buf[len] as char);
		}
	}

	fn writeSNumber(&mut self, width : uint, leading_zero : bool, num : int) {
		let abs = if num < 0 {
			self.putc('-');
			-num
		} else {
			num
		} as uint;
		self.writeNumber(width, leading_zero, 10, false, abs);
	}

}

struct Console {
	buffer : *mut u16,
	position : uint,
	width : uint,
	height : uint,
	color : u16
}

impl Console {
	fn new(buffer : *mut u16, width : uint, height : uint) -> Console {
		Console {
			buffer : buffer,
			position : 0,
			width : width,
			height : height,
			color : 0x0f00,
		}
	}

	fn putchar(&mut self, position : uint, c : u16) {
		unsafe {
			*mut_offset(self.buffer, position as int) = c;
		}
	}

	fn clear(&mut self) {
		range(0, 80*25, |i| { unsafe {
			*mut_offset(self.buffer, i as int) = 0;
		}});
		self.position = 0;
	}

	fn clear_eol(&mut self) {
		range(0, self.width - (self.position % self.width), |i| {
			self.putchar(self.position + i, 0);
		});
	}

	fn copy_back(&mut self, to : uint, from : uint, n : uint) {
		range(0, n, |i| {
			unsafe {
				*mut_offset(self.buffer, (to + i) as int) =
					*mut_offset(self.buffer, (from + i) as int);
			}
		});
	}

	fn scroll(&mut self, lines : uint) {
		if lines >= self.height {
			self.clear();
			return;
		}
		let dist = self.width * lines;
		self.copy_back(0, dist, self.width * self.height - dist);
		self.position -= dist;
	}

	fn newline(&mut self) {
		if self.position > self.width * (self.height - 1) {
			self.scroll(1);
		}
		self.position += self.width - (self.position % self.width);
		self.clear_eol();
	}
}

impl Writer for Console {
	fn putc(&mut self, c : char) {
		if c == '\n' {
			self.newline();
			return;
		}
		let value = (c as u8) as u16 | self.color;
		self.putchar(self.position, value);
		self.position += 1;
		if self.position == self.width * self.height {
			self.scroll(1);
		}
	}
}

#[no_mangle]
pub unsafe fn start64() {
	let mut con = Console::new((kernel_base + 0xb8000) as *mut u16, 80, 25);
	con.clear();
	con.write("Hello World!\n");
	con.writeUInt((*MultiBootInfo()).mem_upper as uint);
	let mut i = 0;
	loop {
		con.writeUInt(i);
		con.putc('\n');
		i += 1;
	}
}

#[no_mangle]
pub unsafe fn abort() {
	let mut con = Console::new((kernel_base + 0xb8000) as *mut u16, 80, 25);
	con.write("aborted.");
	loop{} // asm!("cli; hlt")
}

#[no_mangle]
pub unsafe fn breakpoint() {
	asm!("int3")
}
<|endoftext|>


<commit_before>use crate::{api::prelude::*, proc_macros::*, themes::theme_orbtk::*, Stack};

/// The `ItemsWidgetState` handles the state for items drawer objects.
#[derive(Default, AsAny)]
pub struct ItemsWidgetState {
    builder: WidgetBuildContext,
    count: usize,
}

impl ItemsWidgetState {
    fn generate_items(&mut self, ctx: &mut Context) {
        let count: usize = ctx.widget().clone_or_default("count");
        let request_update: bool = *ctx.widget().get("request_update");

        if count != self.count || request_update {
            if let Some(builder) = &self.builder {
                if let Some(items_panel) = ctx.entity_of_child("items_panel") {
                    ctx.clear_children_of(items_panel);

                    for i in 0..count {
                        let bctx = &mut ctx.build_context();

                        let child = builder(bctx, i);
                        bctx.append_child(items_panel, child);
                    }
                }
            }

            self.count = count;
            ctx.widget().set("request_update", false);
        }
    }
}

impl State for ItemsWidgetState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.generate_items(ctx);
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.generate_items(ctx);
    }
}

widget!(
    /// The `ItemsWidget` is a simple no interactive items drawer widget.
    ///
    /// **style:** `items-widget`
    ItemsWidget<ItemsWidgetState> {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the orientation property.
        orientation: Orientation,

        /// Sets or shared the count.
        count: usize,

        /// Use this flag to force the redrawing of the items.
        request_update: bool
    }
);

impl ItemsWidget {
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Box::new(builder));
        self
    }
}

impl Template for ItemsWidget {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("ItemsWidget")
            .style("items_widget")
            .background(colors::LYNCH_COLOR)
            .border_radius(2.0)
            .border_width(1.0)
            .border_brush(colors::BOMBAY_COLOR)
            .padding(2.0)
            .orientation("vertical")
            .child(Stack::new().id("items_panel").orientation(id).build(ctx))
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        RectangleRenderObject.into()
    }

    fn layout(&self) -> Box<dyn Layout> {
        PaddingLayout::new().into()
    }
}
<commit_msg>orbtk_widgets: fix typo bug in `items_widget`<commit_after>use crate::{api::prelude::*, proc_macros::*, themes::theme_orbtk::*, Stack};

/// The `ItemsWidgetState` handles the state for items drawer objects.
#[derive(Default, AsAny)]
pub struct ItemsWidgetState {
    builder: WidgetBuildContext,
    count: usize,
}

impl ItemsWidgetState {
    fn generate_items(&mut self, ctx: &mut Context) {
        let count: usize = ctx.widget().clone_or_default("count");
        let request_update: bool = *ctx.widget().get("request_update");

        if count != self.count || request_update {
            if let Some(builder) = &self.builder {
                if let Some(items_panel) = ctx.entity_of_child("items_panel") {
                    ctx.clear_children_of(items_panel);

                    for i in 0..count {
                        let bctx = &mut ctx.build_context();

                        let child = builder(bctx, i);
                        bctx.append_child(items_panel, child);
                    }
                }
            }

            self.count = count;
            ctx.widget().set("request_update", false);
        }
    }
}

impl State for ItemsWidgetState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.generate_items(ctx);
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.generate_items(ctx);
    }
}

widget!(
    /// The `ItemsWidget` is a simple no interactive items drawer widget.
    ///
    /// **style:** `items_widget`
    ItemsWidget<ItemsWidgetState> {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the orientation property.
        orientation: Orientation,

        /// Sets or shared the count.
        count: usize,

        /// Use this flag to force the redrawing of the items.
        request_update: bool
    }
);

impl ItemsWidget {
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Box::new(builder));
        self
    }
}

impl Template for ItemsWidget {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("ItemsWidget")
            .style("items_widget")
            .background(colors::LYNCH_COLOR)
            .border_radius(2.0)
            .border_width(1.0)
            .border_brush(colors::BOMBAY_COLOR)
            .padding(2.0)
            .orientation("vertical")
            .child(Stack::new().id("items_panel").orientation(id).build(ctx))
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        RectangleRenderObject.into()
    }

    fn layout(&self) -> Box<dyn Layout> {
        PaddingLayout::new().into()
    }
}
<|endoftext|>


<commit_before>use idna::domain_to_ascii;
use lazy_static::lazy_static;
use regex::Regex;
use std::borrow::Cow;

use crate::validation::ip::validate_ip;

lazy_static! {
    // Regex from the specs
    // https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
    // It will mark esoteric email addresses like quoted string as invalid
    static ref EMAIL_USER_RE: Regex = Regex::new(r"^(?i)[a-z0-9.!#$%&'*+/=?^_`{|}~-]+\z").unwrap();
    static ref EMAIL_DOMAIN_RE: Regex = Regex::new(
        r"(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$"
    ).unwrap();
    // literal form, ipv4 or ipv6 address (SMTP 4.1.3)
    static ref EMAIL_LITERAL_RE: Regex = Regex::new(r"(?i)\[([A-f0-9:\.]+)\]\z").unwrap();
}

/// Validates whether the given string is an email based on the [HTML5 spec](https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address).
/// [RFC 5322](https://tools.ietf.org/html/rfc5322) is not practical in most circumstances and allows email addresses
/// that are unfamiliar to most users.
#[must_use]
pub fn validate_email<'a, T>(val: T) -> bool
where
    T: Into<Cow<'a, str>>,
{
    let val = val.into();
    if val.is_empty() || !val.contains('@') {
        return false;
    }
    let parts: Vec<&str> = val.rsplitn(2, '@').collect();
    let user_part = parts[1];
    let domain_part = parts[0];

    if !EMAIL_USER_RE.is_match(user_part) {
        return false;
    }

    if !validate_domain_part(domain_part) {
        // Still the possibility of an [IDN](https://en.wikipedia.org/wiki/Internationalized_domain_name)
        return match domain_to_ascii(domain_part) {
            Ok(d) => validate_domain_part(&d),
            Err(_) => false,
        };
    }

    true
}

/// Checks if the domain is a valid domain and if not, check whether it's an IP
#[must_use]
fn validate_domain_part(domain_part: &str) -> bool {
    if EMAIL_DOMAIN_RE.is_match(domain_part) {
        return true;
    }

    // maybe we have an ip as a domain?
    match EMAIL_LITERAL_RE.captures(domain_part) {
        Some(caps) => match caps.get(1) {
            Some(c) => validate_ip(c.as_str()),
            None => false,
        },
        None => false,
    }
}

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

    use super::validate_email;

    #[test]
    fn test_validate_email() {
        // Test cases taken from Django
        // https://github.com/django/django/blob/master/tests/validators/tests.py#L48
        let tests = vec![
            ("email@here.com", true),
            ("weirder-email@here.and.there.com", true),
            (r#"!def!xyz%abc@example.com"#, true),
            ("email@[127.0.0.1]", true),
            ("email@[2001:dB8::1]", true),
            ("email@[2001:dB8:0:0:0:0:0:1]", true),
            ("email@[::fffF:127.0.0.1]", true),
            ("example@valid-----hyphens.com", true),
            ("example@valid-with-hyphens.com", true),
            ("test@domain.with.idn.tld.उदाहरण.परीक्षा", true),
            (r#""test@test"@example.com"#, false),
            // max length for domain name labels is 63 characters per RFC 1034
            ("a@atm.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true),
            ("a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.atm", true),
            (
                "a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbb.atm",
                true,
            ),
            // 64 * a
            ("a@atm.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false),
            ("", false),
            ("abc", false),
            ("abc@", false),
            ("abc@bar", true),
            ("a @x.cz", false),
            ("abc@.com", false),
            ("something@@somewhere.com", false),
            ("email@127.0.0.1", true),
            ("email@[127.0.0.256]", false),
            ("email@[2001:db8::12345]", false),
            ("email@[2001:db8:0:0:0:0:1]", false),
            ("email@[::ffff:127.0.0.256]", false),
            ("example@invalid-.com", false),
            ("example@-invalid.com", false),
            ("example@invalid.com-", false),
            ("example@inv-.alid-.com", false),
            ("example@inv-.-alid.com", false),
            (r#"test@example.com\n\n<script src="x.js">"#, false),
            (r#""\\\011"@here.com"#, false),
            (r#""\\\012"@here.com"#, false),
            ("trailingdot@shouldfail.com.", false),
            // Trailing newlines in username or domain not allowed
            ("a@b.com\n", false),
            ("a\n@b.com", false),
            (r#""test@test"\n@example.com"#, false),
            ("a@[127.0.0.1]\n", false),
            // underscores are not allowed
            ("John.Doe@exam_ple.com", false),
        ];

        for (input, expected) in tests {
            // println!("{} - {}", input, expected);
            assert_eq!(
                validate_email(input),
                expected,
                "Email `{}` was not classified correctly",
                input
            );
        }
    }

    #[test]
    fn test_validate_email_cow() {
        let test: Cow<'static, str> = "email@here.com".into();
        assert!(validate_email(test));
        let test: Cow<'static, str> = String::from("email@here.com").into();
        assert!(validate_email(test));
        let test: Cow<'static, str> = "a@[127.0.0.1]\n".into();
        assert!(!validate_email(test));
        let test: Cow<'static, str> = String::from("a@[127.0.0.1]\n").into();
        assert!(!validate_email(test));
    }
}
<commit_msg>Email length validation before regex (#211)<commit_after>use idna::domain_to_ascii;
use lazy_static::lazy_static;
use regex::Regex;
use std::borrow::Cow;

use crate::{validation::ip::validate_ip, HasLen};

lazy_static! {
    // Regex from the specs
    // https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
    // It will mark esoteric email addresses like quoted string as invalid
    static ref EMAIL_USER_RE: Regex = Regex::new(r"^(?i)[a-z0-9.!#$%&'*+/=?^_`{|}~-]+\z").unwrap();
    static ref EMAIL_DOMAIN_RE: Regex = Regex::new(
        r"(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$"
    ).unwrap();
    // literal form, ipv4 or ipv6 address (SMTP 4.1.3)
    static ref EMAIL_LITERAL_RE: Regex = Regex::new(r"(?i)\[([A-f0-9:\.]+)\]\z").unwrap();
}

/// Validates whether the given string is an email based on the [HTML5 spec](https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address).
/// [RFC 5322](https://tools.ietf.org/html/rfc5322) is not practical in most circumstances and allows email addresses
/// that are unfamiliar to most users.
#[must_use]
pub fn validate_email<'a, T>(val: T) -> bool
where
    T: Into<Cow<'a, str>>,
{
    let val = val.into();
    if val.is_empty() || !val.contains('@') {
        return false;
    }
    let parts: Vec<&str> = val.rsplitn(2, '@').collect();
    let user_part = parts[1];
    let domain_part = parts[0];

    // validate the length of each part of the email, BEFORE doing the regex
    // according to RFC5321 the max length of the local part is 64 characters
    // and the max length of the domain part is 255 characters
    // https://datatracker.ietf.org/doc/html/rfc5321#section-4.5.3.1.1
    if user_part.length() > 64 || domain_part.length() > 255 {
        return false;
    }

    if !EMAIL_USER_RE.is_match(user_part) {
        return false;
    }

    if !validate_domain_part(domain_part) {
        // Still the possibility of an [IDN](https://en.wikipedia.org/wiki/Internationalized_domain_name)
        return match domain_to_ascii(domain_part) {
            Ok(d) => validate_domain_part(&d),
            Err(_) => false,
        };
    }

    true
}

/// Checks if the domain is a valid domain and if not, check whether it's an IP
#[must_use]
fn validate_domain_part(domain_part: &str) -> bool {
    if EMAIL_DOMAIN_RE.is_match(domain_part) {
        return true;
    }

    // maybe we have an ip as a domain?
    match EMAIL_LITERAL_RE.captures(domain_part) {
        Some(caps) => match caps.get(1) {
            Some(c) => validate_ip(c.as_str()),
            None => false,
        },
        None => false,
    }
}

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

    use super::validate_email;

    #[test]
    fn test_validate_email() {
        // Test cases taken from Django
        // https://github.com/django/django/blob/master/tests/validators/tests.py#L48
        let tests = vec![
            ("email@here.com", true),
            ("weirder-email@here.and.there.com", true),
            (r#"!def!xyz%abc@example.com"#, true),
            ("email@[127.0.0.1]", true),
            ("email@[2001:dB8::1]", true),
            ("email@[2001:dB8:0:0:0:0:0:1]", true),
            ("email@[::fffF:127.0.0.1]", true),
            ("example@valid-----hyphens.com", true),
            ("example@valid-with-hyphens.com", true),
            ("test@domain.with.idn.tld.उदाहरण.परीक्षा", true),
            (r#""test@test"@example.com"#, false),
            // max length for domain name labels is 63 characters per RFC 1034
            ("a@atm.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true),
            ("a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.atm", true),
            (
                "a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbb.atm",
                true,
            ),
            // 64 * a
            ("a@atm.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false),
            ("", false),
            ("abc", false),
            ("abc@", false),
            ("abc@bar", true),
            ("a @x.cz", false),
            ("abc@.com", false),
            ("something@@somewhere.com", false),
            ("email@127.0.0.1", true),
            ("email@[127.0.0.256]", false),
            ("email@[2001:db8::12345]", false),
            ("email@[2001:db8:0:0:0:0:1]", false),
            ("email@[::ffff:127.0.0.256]", false),
            ("example@invalid-.com", false),
            ("example@-invalid.com", false),
            ("example@invalid.com-", false),
            ("example@inv-.alid-.com", false),
            ("example@inv-.-alid.com", false),
            (r#"test@example.com\n\n<script src="x.js">"#, false),
            (r#""\\\011"@here.com"#, false),
            (r#""\\\012"@here.com"#, false),
            ("trailingdot@shouldfail.com.", false),
            // Trailing newlines in username or domain not allowed
            ("a@b.com\n", false),
            ("a\n@b.com", false),
            (r#""test@test"\n@example.com"#, false),
            ("a@[127.0.0.1]\n", false),
            // underscores are not allowed
            ("John.Doe@exam_ple.com", false),
        ];

        for (input, expected) in tests {
            // println!("{} - {}", input, expected);
            assert_eq!(
                validate_email(input),
                expected,
                "Email `{}` was not classified correctly",
                input
            );
        }
    }

    #[test]
    fn test_validate_email_cow() {
        let test: Cow<'static, str> = "email@here.com".into();
        assert!(validate_email(test));
        let test: Cow<'static, str> = String::from("email@here.com").into();
        assert!(validate_email(test));
        let test: Cow<'static, str> = "a@[127.0.0.1]\n".into();
        assert!(!validate_email(test));
        let test: Cow<'static, str> = String::from("a@[127.0.0.1]\n").into();
        assert!(!validate_email(test));
    }

    #[test]
    fn test_validate_email_rfc5321() {
        // 65 character local part
        let test = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@mail.com";
        assert_eq!(validate_email(test), false);
        // 256 character domain part
        let test = "a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com";
        assert_eq!(validate_email(test), false);
    }
}
<|endoftext|>