<commit_before>// http://dev.w3.org/csswg/css3-syntax/#tokenization
//
// The output of the tokenization step is a series of zero or more
// of the following tokens:
// ident, function, at-keyword, hash, string, bad-string, url, bad-url,
// delim, number, percentage, dimension, unicode-range, whitespace, comment,
// cdo, cdc, colon, semicolon, [, ], (, ), {, }.
//
// ident, function, at-keyword, hash, string, and url tokens
// have a value composed of zero or more characters.
// Delim tokens have a value composed of a single character.
// Number, percentage, and dimension tokens have a representation
// composed of 1 or more character, a numeric value,
// and a type flag set to either "integer" or "number".
// The type flag defaults to "integer" if not otherwise set.
// Dimension tokens additionally have a unit
// composed of one or more characters.
// Unicode-range tokens have a range of characters.

use cssparser;

const MAX_UNICODE: uint = 0x10FFFF;

#[deriving_eq]
enum NumericValue {
    Integer(int),
    // The spec calls this "number".
    // Use "float" instead to reduce term overloading with "number token".
    Float(float),
}
// TODO: add a NumberValue.as_float() method.

#[deriving_eq]
enum Token {
    Ident(~str),
    Function(~str),
    AtKeyword(~str),
    Hash(~str),
    String(~str),
    BadString,
    URL(~str),
    BadURL,
    Delim(char),
    Number(NumericValue, ~str),  // value, representation
    Percentage(NumericValue, ~str),  // value, representation
    Dimension(NumericValue, ~str, ~str),  // value, representation, unit
    UnicodeRange(char, char),  // start, end. XXX what about empty ranges?
    WhiteSpace,
    Comment,
    CDO,  // <!--
    CDC,  // -->
    Colon,  // :
    Semicolon,  // ;
    OpenBraket, // [
    OpenParen, // (
    OpenBrace, // {
    CloseBraket, // ]
    CloseParen, // )
    CloseBrace, // }
}

struct State {
    input: ~str,
    length: uint,
    transform_function_whitespace: bool,
    quirks_mode: bool,
    mut position: uint,
    mut errors: ~[~str]
}

fn is_eof(state: &State) -> bool {
    state.position >= state.length
}

fn current_char(state: &State) -> char {
    str::char_at(state.input, state.position)
}

fn consume_char(state: &State) -> char {
    let range = str::char_range_at(state.input, state.position);
    state.position = range.next;
    range.ch
}

// http://dev.w3.org/csswg/css3-syntax/#tokenization
pub fn tokenize(input: &str, transform_function_whitespace: bool,
            quirks_mode: bool) -> {tokens: ~[Token], parse_errors: ~[~str]} {
    let input = cssparser::preprocess(input);
    let state = &State {
        input: input, length: input.len(), quirks_mode: quirks_mode,
        transform_function_whitespace: transform_function_whitespace,
        position: 0, errors: ~[] };
    let mut tokens: ~[Token] = ~[];

    while !is_eof(state) {
        tokens.push(consume_token(state))
    }

    // Work around `error: moving out of mutable field`
    // TODO: find a cleaner way.
    let mut errors: ~[~str] = ~[];
    errors <-> state.errors;
    {tokens: tokens, parse_errors: errors}
}

// 3.3.4. Data state
fn consume_token(state: &State) -> Token {
    let c = consume_char(state);
    match c {
        '\t' | '\n' | '\x0C' | ' ' => {
            while !is_eof(state) {
                match current_char(state) {
                    '\t' | '\n' | '\x0C' | ' ' => state.position += 1,
                    _ => break,
                }
            }
            WhiteSpace
        },
        '"' => consume_quoted_string(state, false),
        '\'' => consume_quoted_string(state, true),
        '(' => OpenParen,
        ')' => CloseParen,
        '-' => {
            if is_eof(state) { Delim('-') } else {
                // TODO: CDC, negative numbers
                match current_char(state) {
                    '\\' => {
                        state.position += 1;
                        if is_eof(state) { state.position -= 1; Delim('-') }
                        else {
                            let c = current_char(state);
                            state.position -= 1;
                            match c {
                                '\n' | '\x0C' => Delim('-'),
                                _ => consume_ident(state, '-')
                            }
                        }
                    },
                    'a'..'z' | 'A'..'Z' | '_' => consume_ident(state, c),
                    c if c >= '\xA0' => consume_ident(state, c),  // Non-ASCII
                    _ => Delim('-')
                }
            }
        }
        '/' if !is_eof(state) && current_char(state) == '*'
            => consume_comment(state),
        ':' => Colon,
        ';' => Semicolon,
        '[' => OpenBraket,
        '\\' => {
            if is_eof(state) {
                state.errors.push(~"Invalid escape");
                Delim('\\')
            } else {
                match current_char(state) {
                    '\n' | '\x0C' => {
                        state.errors.push(~"Invalid escape"); Delim('\\') },
                    _ => consume_ident(state, consume_escape(state))
                }
            }
        }
        ']' => CloseBraket,
        '{' => OpenBrace,
        '}' => CloseBrace,
        'a'..'z' | 'A'..'Z' | '_' => consume_ident(state, c),
        c if c >= '\xA0' => consume_ident(state, c),  // Non-ASCII
        _ => Delim(c),
    }
}

// 3.3.5. Double-quote-string state
// 3.3.6. Single-quote-string state
fn consume_quoted_string(state: &State, single_quote: bool) -> Token {
    let mut string: ~str = ~"";
    loop {
        if is_eof(state) {
            state.errors.push(~"EOF in quoted string");
            return String(string);
        }
        match consume_char(state) {
            '"' if !single_quote => return String(string),
            '\'' if single_quote => return String(string),
            '\n' | '\x0C' => {
                state.errors.push(~"Newline in quoted string");
                return BadString
            },
            '\\' => {
                if is_eof(state) {
                    state.errors.push(~"EOF in quoted string");
                    return BadString
                }
                match current_char(state) {
                    // Consume quoted newline
                    '\n' | '\x0C' => state.position += 1,
                    _ =>  str::push_char(&mut string, consume_escape(state))
                }
            }
            c => str::push_char(&mut string, c),
        }
    }
}

// 3.3.9. Comment state
fn consume_comment(state: &State) -> Token {
    state.position += 1;  // consume the * in /*
    match str::find_str_from(state.input, "*/", state.position) {
        Some(end_position) => state.position = end_position + 2,
        None => {
            state.errors.push(~"EOF in comment");
            state.position = state.input.len();
        }
    }
    Comment
}

// 3.3.12. Ident state
// 3.3.13. Ident-rest state
fn consume_ident(state: &State, initial_char: char) -> Token {
    let mut string = str::from_char(initial_char);
    while !is_eof(state) {
        let c = current_char(state);
        let cc = match c {
            'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '-'  => {
                state.position += 1; c },
            _ if c >= '\xA0' => consume_char(state),  // Non-ASCII
            '\\' => {
                state.position += 1;
                if is_eof(state) { state.position -= 1; break }
                match current_char(state) {
                    '\n' | '\x0C' => { state.position -= 1; break },
                    _ => consume_escape(state)
                }
            },
            '\t' | '\n' | '\x0C' | ' ' if state.transform_function_whitespace
            => {
                state.position += 1;
                return handle_transform_function_whitespace(state, string)
            }
            '(' => {
                state.position += 1;
                // TODO: URLs
                return Function(string)
            },
            _ => break
        };
        str::push_char(&mut string, cc)
    }
    Ident(string)
}

// 3.3.14. Transform-function-whitespace state
fn handle_transform_function_whitespace(state: &State, string: ~str) -> Token {
    while !is_eof(state) {
        match current_char(state) {
            '\t' | '\n' | '\x0C' | ' ' => state.position += 1,
            '(' => { state.position += 1; return Function(string) }
            _ => break,
        }
    }
    // XXX I think the spec is wrong here.
    // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0266.html
    // Go back for one whitespace character.
    state.position -= 1;
    return Ident(string)
}

// 3.3.27. Consume an escaped character
// Assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed
// and that the next input character has already been verified
// to not be a newline or EOF.
fn consume_escape(state: &State) -> char {
    let c = consume_char(state);
    match c {
        '0'..'9' | 'A'..'F' | 'a'..'f' => {
            let mut hex = ~[c];
            while hex.len() < 6 && !is_eof(state) {
                let c = current_char(state);
                match c {
                    '0'..'9' | 'A'..'F' | 'a'..'f' => {
                        hex.push(c); state.position += 1 },
                    _ => break
                }
            }
            if !is_eof(state) {
                match current_char(state) {
                    '\t' | '\n' | '\x0C' | ' ' => state.position += 1,
                    _ => ()
                }
            }
            char_from_hex(hex)
        },
        c => c
    }
}

fn char_from_hex(hex: &[char]) -> char {
    let mut value = 0u;
    for hex.each |cc| {
        let c = *cc;
        value = value * 16 + c as uint - match c {
            '0'..'9' => '0' as uint,
            'A'..'F' => 'A' as uint - 10,
            'a'..'f' => 'a' as uint - 10,
            _ => fail
        }
    }
    if value == 0 || value > MAX_UNICODE {
        '\uFFFD'  // Replacement character
    } else {
        value as char
    }
}

#[test]
fn test_tokenizer() {

    fn assert_tokens(input: &str, expected_tokens: &[Token],
                     expected_errors: &[~str]) {
        assert_tokens_flags(
            input, false, false, expected_tokens, expected_errors)
    }

    fn assert_tokens_flags(
            input: &str,
            transform_function_whitespace: bool, quirks_mode: bool,
            expected_tokens: &[Token], expected_errors: &[~str]) {
        let result = tokenize(
            input, transform_function_whitespace, quirks_mode);
        let tokens: &[Token] = result.tokens;
        let parse_errors: &[~str] = result.parse_errors;
        if tokens != expected_tokens {
            fail fmt!("%? != %?", tokens, expected_tokens);
        }
        if parse_errors != expected_errors {
            fail fmt!("%? != %?", parse_errors, expected_errors);
        }
    }
    assert_tokens("", [], []);
    assert_tokens("?/", [Delim('?'), Delim('/')], []);
    assert_tokens("?/* Li/*psum… */", [Delim('?'), Comment], []);
    assert_tokens("?/* Li/*psum… *//", [Delim('?'), Comment, Delim('/')], []);
    assert_tokens("?/* Lipsum", [Delim('?'), Comment], [~"EOF in comment"]);
    assert_tokens("?/*", [Delim('?'), Comment], [~"EOF in comment"]);
    assert_tokens("[?}{)",
        [OpenBraket, Delim('?'), CloseBrace, OpenBrace, CloseParen], []);

    assert_tokens("(\n \t'Lore\\6d \"ipsu\\6D'",
        [OpenParen, WhiteSpace, String(~"Lorem\"ipsum")], []);
    assert_tokens("'\\''", [String(~"'")], []);
    assert_tokens("\"\\\"\"", [String(~"\"")], []);
    assert_tokens("\"\\\"", [String(~"\"")], [~"EOF in quoted string"]);
    assert_tokens("'\\", [BadString], [~"EOF in quoted string"]);
    assert_tokens("\"0\\0000000\"", [String(~"0\uFFFD0")], []);
    assert_tokens("\"0\\000000 0\"", [String(~"0\uFFFD0")], []);
    assert_tokens("'z\n'a", [BadString, String(~"a")],
        [~"Newline in quoted string", ~"EOF in quoted string"]);

    assert_tokens("Lorem\\ ipsu\\6D dolor \\sit",
        [Ident(~"Lorem ipsumdolor"), WhiteSpace, Ident(~"sit")], []);
    assert_tokens("foo\\", [Ident(~"foo"), Delim('\\')], [~"Invalid escape"]);
    assert_tokens("foo\\\nbar",
        [Ident(~"foo"), Delim('\\'), WhiteSpace, Ident(~"bar")],
        [~"Invalid escape"]);
    assert_tokens("-Lipsum", [Ident(~"-Lipsum")], []);
    assert_tokens("-\\Lipsum", [Ident(~"-Lipsum")], []);
    assert_tokens("func()", [Function(~"func"), CloseParen], []);
    assert_tokens("func ()",
        [Ident(~"func"), WhiteSpace, OpenParen, CloseParen], []);
    assert_tokens_flags("func ()", true, false,
        [Function(~"func"), CloseParen], []);
}
<commit_msg>Add CDO and CDC tokens.<commit_after>// http://dev.w3.org/csswg/css3-syntax/#tokenization
//
// The output of the tokenization step is a series of zero or more
// of the following tokens:
// ident, function, at-keyword, hash, string, bad-string, url, bad-url,
// delim, number, percentage, dimension, unicode-range, whitespace, comment,
// cdo, cdc, colon, semicolon, [, ], (, ), {, }.
//
// ident, function, at-keyword, hash, string, and url tokens
// have a value composed of zero or more characters.
// Delim tokens have a value composed of a single character.
// Number, percentage, and dimension tokens have a representation
// composed of 1 or more character, a numeric value,
// and a type flag set to either "integer" or "number".
// The type flag defaults to "integer" if not otherwise set.
// Dimension tokens additionally have a unit
// composed of one or more characters.
// Unicode-range tokens have a range of characters.

use cssparser;

const MAX_UNICODE: uint = 0x10FFFF;

#[deriving_eq]
enum NumericValue {
    Integer(int),
    // The spec calls this "number".
    // Use "float" instead to reduce term overloading with "number token".
    Float(float),
}
// TODO: add a NumberValue.as_float() method.

#[deriving_eq]
enum Token {
    Ident(~str),
    Function(~str),
    AtKeyword(~str),
    Hash(~str),
    String(~str),
    BadString,
    URL(~str),
    BadURL,
    Delim(char),
    Number(NumericValue, ~str),  // value, representation
    Percentage(NumericValue, ~str),  // value, representation
    Dimension(NumericValue, ~str, ~str),  // value, representation, unit
    UnicodeRange(char, char),  // start, end. XXX what about empty ranges?
    WhiteSpace,
    Comment,
    CDO,  // <!--
    CDC,  // -->
    Colon,  // :
    Semicolon,  // ;
    OpenBraket, // [
    OpenParen, // (
    OpenBrace, // {
    CloseBraket, // ]
    CloseParen, // )
    CloseBrace, // }
}

struct State {
    input: ~str,
    length: uint,
    transform_function_whitespace: bool,
    quirks_mode: bool,
    mut position: uint,
    mut errors: ~[~str]
}

#[inline(always)]
fn is_eof(state: &State) -> bool {
    state.position >= state.length
}

#[inline(always)]
fn current_char(state: &State) -> char {
    str::char_at(state.input, state.position)
}

// Return value may be smaller than n if we’re near the end of the input.
#[inline(always)]
fn next_n_bytes(state: &State, n: uint) -> ~str {
    str::slice(state.input, state.position,
               uint::min(state.position + n, state.length))
}

#[inline(always)]
fn consume_char(state: &State) -> char {
    let range = str::char_range_at(state.input, state.position);
    state.position = range.next;
    range.ch
}

// http://dev.w3.org/csswg/css3-syntax/#tokenization
pub fn tokenize(input: &str, transform_function_whitespace: bool,
            quirks_mode: bool) -> {tokens: ~[Token], parse_errors: ~[~str]} {
    let input = cssparser::preprocess(input);
    let state = &State {
        input: input, length: input.len(), quirks_mode: quirks_mode,
        transform_function_whitespace: transform_function_whitespace,
        position: 0, errors: ~[] };
    let mut tokens: ~[Token] = ~[];

    while !is_eof(state) {
        tokens.push(consume_token(state))
    }

    // Work around `error: moving out of mutable field`
    // TODO: find a cleaner way.
    let mut errors: ~[~str] = ~[];
    errors <-> state.errors;
    {tokens: tokens, parse_errors: errors}
}

// 3.3.4. Data state
fn consume_token(state: &State) -> Token {
    let c = consume_char(state);
    match c {
        '\t' | '\n' | '\x0C' | ' ' => {
            while !is_eof(state) {
                match current_char(state) {
                    '\t' | '\n' | '\x0C' | ' ' => state.position += 1,
                    _ => break,
                }
            }
            WhiteSpace
        },
        '"' => consume_quoted_string(state, false),
        '\'' => consume_quoted_string(state, true),
        '(' => OpenParen,
        ')' => CloseParen,
        '-' => {
            if is_eof(state) { Delim('-') } else {
                // TODO: CDC, negative numbers
                match current_char(state) {
                    '\\' => {
                        state.position += 1;
                        if is_eof(state) { state.position -= 1; Delim('-') }
                        else {
                            let c = current_char(state);
                            state.position -= 1;
                            match c {
                                '\n' | '\x0C' => Delim('-'),
                                _ => consume_ident(state, '-')
                            }
                        }
                    },
                    'a'..'z' | 'A'..'Z' | '_' => consume_ident(state, c),
                    c if c >= '\xA0' => consume_ident(state, c),  // Non-ASCII
                    _ => {
                        if next_n_bytes(state, 2) == ~"->"
                        { state.position += 2; CDC } else { Delim('-') }
                    }
                }
            }
        }
        '/' if !is_eof(state) && current_char(state) == '*'
            => consume_comment(state),
        ':' => Colon,
        ';' => Semicolon,
        '<' => {
            if next_n_bytes(state, 3) == ~"!--"
            { state.position += 3; CDO } else { Delim('<') }
        }
        '[' => OpenBraket,
        '\\' => {
            if is_eof(state) {
                state.errors.push(~"Invalid escape");
                Delim('\\')
            } else {
                match current_char(state) {
                    '\n' | '\x0C' => {
                        state.errors.push(~"Invalid escape"); Delim('\\') },
                    _ => consume_ident(state, consume_escape(state))
                }
            }
        }
        ']' => CloseBraket,
        '{' => OpenBrace,
        '}' => CloseBrace,
        'a'..'z' | 'A'..'Z' | '_' => consume_ident(state, c),
        c if c >= '\xA0' => consume_ident(state, c),  // Non-ASCII
        _ => Delim(c),
    }
}

// 3.3.5. Double-quote-string state
// 3.3.6. Single-quote-string state
fn consume_quoted_string(state: &State, single_quote: bool) -> Token {
    let mut string: ~str = ~"";
    loop {
        if is_eof(state) {
            state.errors.push(~"EOF in quoted string");
            return String(string);
        }
        match consume_char(state) {
            '"' if !single_quote => return String(string),
            '\'' if single_quote => return String(string),
            '\n' | '\x0C' => {
                state.errors.push(~"Newline in quoted string");
                return BadString
            },
            '\\' => {
                if is_eof(state) {
                    state.errors.push(~"EOF in quoted string");
                    return BadString
                }
                match current_char(state) {
                    // Consume quoted newline
                    '\n' | '\x0C' => state.position += 1,
                    _ =>  str::push_char(&mut string, consume_escape(state))
                }
            }
            c => str::push_char(&mut string, c),
        }
    }
}

// 3.3.9. Comment state
fn consume_comment(state: &State) -> Token {
    state.position += 1;  // consume the * in /*
    match str::find_str_from(state.input, "*/", state.position) {
        Some(end_position) => state.position = end_position + 2,
        None => {
            state.errors.push(~"EOF in comment");
            state.position = state.input.len();
        }
    }
    Comment
}

// 3.3.12. Ident state
// 3.3.13. Ident-rest state
fn consume_ident(state: &State, initial_char: char) -> Token {
    let mut string = str::from_char(initial_char);
    while !is_eof(state) {
        let c = current_char(state);
        let cc = match c {
            'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '-'  => {
                state.position += 1; c },
            _ if c >= '\xA0' => consume_char(state),  // Non-ASCII
            '\\' => {
                state.position += 1;
                if is_eof(state) { state.position -= 1; break }
                match current_char(state) {
                    '\n' | '\x0C' => { state.position -= 1; break },
                    _ => consume_escape(state)
                }
            },
            '\t' | '\n' | '\x0C' | ' ' if state.transform_function_whitespace
            => {
                state.position += 1;
                return handle_transform_function_whitespace(state, string)
            }
            '(' => {
                state.position += 1;
                // TODO: URLs
                return Function(string)
            },
            _ => break
        };
        str::push_char(&mut string, cc)
    }
    Ident(string)
}

// 3.3.14. Transform-function-whitespace state
fn handle_transform_function_whitespace(state: &State, string: ~str) -> Token {
    while !is_eof(state) {
        match current_char(state) {
            '\t' | '\n' | '\x0C' | ' ' => state.position += 1,
            '(' => { state.position += 1; return Function(string) }
            _ => break,
        }
    }
    // XXX I think the spec is wrong here.
    // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0266.html
    // Go back for one whitespace character.
    state.position -= 1;
    return Ident(string)
}

// 3.3.27. Consume an escaped character
// Assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed
// and that the next input character has already been verified
// to not be a newline or EOF.
fn consume_escape(state: &State) -> char {
    let c = consume_char(state);
    match c {
        '0'..'9' | 'A'..'F' | 'a'..'f' => {
            let mut hex = ~[c];
            while hex.len() < 6 && !is_eof(state) {
                let c = current_char(state);
                match c {
                    '0'..'9' | 'A'..'F' | 'a'..'f' => {
                        hex.push(c); state.position += 1 },
                    _ => break
                }
            }
            if !is_eof(state) {
                match current_char(state) {
                    '\t' | '\n' | '\x0C' | ' ' => state.position += 1,
                    _ => ()
                }
            }
            char_from_hex(hex)
        },
        c => c
    }
}

fn char_from_hex(hex: &[char]) -> char {
    let mut value = 0u;
    for hex.each |cc| {
        let c = *cc;
        value = value * 16 + c as uint - match c {
            '0'..'9' => '0' as uint,
            'A'..'F' => 'A' as uint - 10,
            'a'..'f' => 'a' as uint - 10,
            _ => fail
        }
    }
    if value == 0 || value > MAX_UNICODE {
        '\uFFFD'  // Replacement character
    } else {
        value as char
    }
}

#[test]
fn test_tokenizer() {

    fn assert_tokens(input: &str, expected_tokens: &[Token],
                     expected_errors: &[~str]) {
        assert_tokens_flags(
            input, false, false, expected_tokens, expected_errors)
    }

    fn assert_tokens_flags(
            input: &str,
            transform_function_whitespace: bool, quirks_mode: bool,
            expected_tokens: &[Token], expected_errors: &[~str]) {
        let result = tokenize(
            input, transform_function_whitespace, quirks_mode);
        let tokens: &[Token] = result.tokens;
        let parse_errors: &[~str] = result.parse_errors;
        if tokens != expected_tokens {
            fail fmt!("%? != %?", tokens, expected_tokens);
        }
        if parse_errors != expected_errors {
            fail fmt!("%? != %?", parse_errors, expected_errors);
        }
    }
    assert_tokens("", [], []);
    assert_tokens("?/", [Delim('?'), Delim('/')], []);
    assert_tokens("?/* Li/*psum… */", [Delim('?'), Comment], []);
    assert_tokens("?/* Li/*psum… *//", [Delim('?'), Comment, Delim('/')], []);
    assert_tokens("?/* Lipsum", [Delim('?'), Comment], [~"EOF in comment"]);
    assert_tokens("?/*", [Delim('?'), Comment], [~"EOF in comment"]);
    assert_tokens("[?}{)",
        [OpenBraket, Delim('?'), CloseBrace, OpenBrace, CloseParen], []);

    assert_tokens("(\n \t'Lore\\6d \"ipsu\\6D'",
        [OpenParen, WhiteSpace, String(~"Lorem\"ipsum")], []);
    assert_tokens("'\\''", [String(~"'")], []);
    assert_tokens("\"\\\"\"", [String(~"\"")], []);
    assert_tokens("\"\\\"", [String(~"\"")], [~"EOF in quoted string"]);
    assert_tokens("'\\", [BadString], [~"EOF in quoted string"]);
    assert_tokens("\"0\\0000000\"", [String(~"0\uFFFD0")], []);
    assert_tokens("\"0\\000000 0\"", [String(~"0\uFFFD0")], []);
    assert_tokens("'z\n'a", [BadString, String(~"a")],
        [~"Newline in quoted string", ~"EOF in quoted string"]);

    assert_tokens("Lorem\\ ipsu\\6D dolor \\sit",
        [Ident(~"Lorem ipsumdolor"), WhiteSpace, Ident(~"sit")], []);
    assert_tokens("foo\\", [Ident(~"foo"), Delim('\\')], [~"Invalid escape"]);
    assert_tokens("foo\\\nbar",
        [Ident(~"foo"), Delim('\\'), WhiteSpace, Ident(~"bar")],
        [~"Invalid escape"]);
    assert_tokens("-Lipsum", [Ident(~"-Lipsum")], []);
    assert_tokens("-\\Lipsum", [Ident(~"-Lipsum")], []);
    assert_tokens("func()", [Function(~"func"), CloseParen], []);
    assert_tokens("func ()",
        [Ident(~"func"), WhiteSpace, OpenParen, CloseParen], []);
    assert_tokens_flags("func ()", true, false,
        [Function(~"func"), CloseParen], []);

    assert_tokens("<!-<!-----><",
        [Delim('<'), Delim('!'), Delim('-'), CDO, Delim('-'), CDC, Delim('<')],
        []);
}
<|endoftext|>


<commit_before>
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::replace;

pub const BCSIZE: usize = 4;
pub const BCSIZEP4: usize = BCSIZE+4;

pub mod bc{
  pub const HALT: u8 = 0;
  pub const INT:  u8 = 1;
  pub const NEG:  u8 = 2;
  pub const ADD:  u8 = 3;
  pub const SUB:  u8 = 4;
  pub const MPY:  u8 = 5;
  pub const DIV:  u8 = 6;
  pub const IDIV: u8 = 7;
  pub const LIST: u8 = 8;
}

pub struct List{
  v: Vec<Object>
}

impl List{
  pub fn new_object(v: Vec<Object>) -> Object{
    return Object::List(Rc::new(RefCell::new(List{v: v})));
  }
}

pub enum Object{
  Null, Bool(bool), Int(i32), Float(f64),
  List(Rc<RefCell<List>>)
}

fn list_to_string(a: &[Object]) -> String{
  let mut s = String::from("[");
  for i in 0..a.len() {
    if i!=0 {s.push_str(", ");}
    s.push_str(&object_to_string(&a[i]));
  }
  s.push_str("]");
  return s;
}

fn object_to_string(x: &Object) -> String{
  match x {
    &Object::Null => String::from("null"),
    &Object::Bool(b) => String::from(if b {"true"} else {"false"}),
    &Object::Int(i) => format!("{}",i),
    &Object::List(ref a) => {
      list_to_string(&a.borrow().v)
    }
    _ => panic!()
  }
}

fn operator_plus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-1] = Object::Int(x+y);
          return sp;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_list(sp: usize, stack: &mut Vec<Object>, size: usize) -> usize{
  let mut sp = sp;
  let mut v: Vec<Object> = Vec::new();
  for i in 0..size {
    v.push(replace(&mut stack[sp-size+i],Object::Null));
  }
  sp-=size;
  stack[sp] = List::new_object(v);
  sp+=1;
  return sp;
}

fn compose_i32(b1: u8, b2: u8, b3: u8, b4: u8) -> i32{
  return (b4 as i32)<<24 | (b3 as i32)<<16 | (b2 as i32)<<8 | (b1 as i32);
}

pub fn eval(a: &[u8]){
  let mut ip=0;
  let mut stack: Vec<Object> = Vec::new();
  for _ in 0..100 {
    stack.push(Object::Null);
  }
  let mut sp=0;
  loop{
    match a[ip] {
      bc::INT => {
        ip+=BCSIZEP4;
        stack[sp] = Object::Int(compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]));
        sp+=1;
      },
      bc::ADD => {
        sp = operator_plus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::LIST => {
        ip+=BCSIZEP4;
        let size = compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]) as usize;
        sp = operator_list(sp,&mut stack,size);
      },
      bc::HALT => {
        break;
      },
      _ => {panic!()}
    }
  }
  if sp>0 {
    println!("{}",object_to_string(&stack[sp-1]));
  }
}
<commit_msg>update<commit_after>
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::replace;

pub const BCSIZE: usize = 4;
pub const BCSIZEP4: usize = BCSIZE+4;

pub mod bc{
  pub const HALT: u8 = 0;
  pub const INT:  u8 = 1;
  pub const NEG:  u8 = 2;
  pub const ADD:  u8 = 3;
  pub const SUB:  u8 = 4;
  pub const MPY:  u8 = 5;
  pub const DIV:  u8 = 6;
  pub const IDIV: u8 = 7;
  pub const LIST: u8 = 8;
}

pub struct List{
  v: Vec<Object>
}

impl List{
  pub fn new_object(v: Vec<Object>) -> Object{
    return Object::List(Rc::new(RefCell::new(List{v: v})));
  }
}

pub enum Object{
  Null, Bool(bool), Int(i32), Float(f64),
  List(Rc<RefCell<List>>)
}

fn list_to_string(a: &[Object]) -> String{
  let mut s = String::from("[");
  for i in 0..a.len() {
    if i!=0 {s.push_str(", ");}
    s.push_str(&object_to_string(&a[i]));
  }
  s.push_str("]");
  return s;
}

fn object_to_string(x: &Object) -> String{
  match x {
    &Object::Null => String::from("null"),
    &Object::Bool(b) => String::from(if b {"true"} else {"false"}),
    &Object::Int(i) => format!("{}",i),
    &Object::List(ref a) => {
      list_to_string(&a.borrow().v)
    }
    _ => panic!()
  }
}

fn operator_plus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-1] = Object::Int(x+y);
          return sp;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_minus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-1] = Object::Int(x-y);
          return sp;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_list(sp: usize, stack: &mut Vec<Object>, size: usize) -> usize{
  let mut sp = sp;
  let mut v: Vec<Object> = Vec::new();
  for i in 0..size {
    v.push(replace(&mut stack[sp-size+i],Object::Null));
  }
  sp-=size;
  stack[sp] = List::new_object(v);
  sp+=1;
  return sp;
}

fn compose_i32(b1: u8, b2: u8, b3: u8, b4: u8) -> i32{
  return (b4 as i32)<<24 | (b3 as i32)<<16 | (b2 as i32)<<8 | (b1 as i32);
}

pub fn eval(a: &[u8]){
  let mut ip=0;
  let mut stack: Vec<Object> = Vec::new();
  for _ in 0..100 {
    stack.push(Object::Null);
  }
  let mut sp=0;
  loop{
    match a[ip] {
      bc::INT => {
        ip+=BCSIZEP4;
        stack[sp] = Object::Int(compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]));
        sp+=1;
      },
      bc::ADD => {
        sp = operator_plus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::SUB => {
        sp = operator_minus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::LIST => {
        ip+=BCSIZEP4;
        let size = compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]) as usize;
        sp = operator_list(sp,&mut stack,size);
      },
      bc::HALT => {
        break;
      },
      _ => {panic!()}
    }
  }
  if sp>0 {
    println!("{}",object_to_string(&stack[sp-1]));
  }
}
<|endoftext|>


<commit_before>// The dictionary used for the lessons.

use rand::{Rng, thread_rng};
use serde_json;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fs::{File, rename};
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use stroke::{self, Stroke};
use ::Result;

/// The set of words we are working on.  This represents the current state.
#[derive(Debug, Deserialize, Serialize)]
pub struct Words {
    /// The unlearned words come directly from the json problem sets.
    pub unlearned: Vec<Lesson>,

    pub learning: Vec<LearnWord>,
}

impl Words {
    /// Construct a new word set from internal data.
    pub fn new() -> Words {
        Words {
            unlearned: get_lessons(),
            learning: vec![],
        }
    }

    /// Load a wordset from the given file.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Words> {
        let fd = File::open(path.as_ref())?;
        let result = serde_json::from_reader(&fd)?;
        Ok(result)
    }

    /// Save the wordset to a given file.
    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        let path = path.as_ref();
        let tmp = path.with_extension("tmp");
        {
            let mut fd = File::create(&tmp)?;
            // serde_json::to_writer_pretty(&mut fd, self)?;
            serde_json::to_writer(&mut fd, self)?;
            // serde_yaml::to_writer(&mut fd, self)?;
            // rmp_serde::encode::write(&mut fd, self)?;
        }
        rename(tmp, path)?;
        Ok(())
    }

    /// Extract a new word to learn.  Returns None if there are no more words.
    pub fn get_unlearned(&mut self) -> Option<LearnWord> {
        let mut lesson = match self.unlearned.pop() {
            None => return None,
            Some (l) => l,
        };

        let (strokes, english) = lesson.words.pop().expect("Words in list");

        let result = LearnWord {
            strokes: strokes,
            english: english,
            next: now() + 5.0,
            interval: 5.0,
        };

        // If there are more words in this lesson, push the lesson back.
        if !lesson.words.is_empty() {
            self.unlearned.push(lesson);
        }

        Some(result)
    }

    /// Extract a word to be learned, if were ready for it.
    pub fn get_learned(&mut self) -> Option<LearnWord> {
        match self.learning.pop() {
            None => None,
            Some(w) => {
                if now() >= w.next {
                    Some(w)
                } else {
                    self.learning.push(w);
                    None
                }
            }
        }
    }

    /// Push a word back into the unlearned word list.
    pub fn push_word(&mut self, word: LearnWord) {
        self.learning.push(word);
        self.learning.sort_by(word_cmp);
    }

    /// Return a count of the number of words that are pending.
    pub fn get_counts(&self) -> Counts {
        let n = now();

        // Divide all of the upcoming entries into buckets.
        let mut counts = vec![0; COUNT_BUCKETS.len()];

        for word in &self.learning {
            let mut v = word.interval;
            for (num, b) in COUNT_BUCKETS.iter().enumerate() {
                if v < b.limit {
                    counts[num] += 1;
                    break;
                }
                v /= b.limit;
            }
        }

        let buckets = COUNT_BUCKETS.iter().zip(counts).map(|(aa, bb)| Bucket {
            name: aa.name,
            count: bb,
        }).collect();

        Counts {
            active: self.learning.iter().filter(|x| x.next < n).count(),
            later: self.learning.iter().filter(|x| x.next >= n).count(),
            unlearned: self.unlearned.iter().map(|x| x.words.len()).sum(),

            buckets: buckets,
        }
    }
}

pub struct Counts {
    pub active: usize,
    pub later: usize,
    pub unlearned: usize,

    // Buckets for later.  The sum of all of these should match the `later+active` value above.
    pub buckets: Vec<Bucket>,
}

pub struct Bucket {
    pub name: &'static str,
    pub count: usize,
}

struct BucketBin {
    name: &'static str,
    limit: f64,
}

static COUNT_BUCKETS: &'static [BucketBin] = &[
    BucketBin{ name: "sec", limit: 60.0 },
    BucketBin{ name: "min", limit: 60.0 },
    BucketBin{ name: "hr", limit: 24.0 },
    BucketBin{ name: "day", limit: 30.0 },
    BucketBin{ name: "mon", limit: 1.0e30 },
];

#[derive(Debug, Serialize, Deserialize)]
pub struct LearnWord {
    pub strokes: Vec<Stroke>,
    pub english: String,
    pub next: f64,
    pub interval: f64,
}

impl LearnWord {
    pub fn correct(&mut self) {
        self.adjust(1.5)
    }

    pub fn incorrect(&mut self) {
        self.adjust(0.5)
    }

    fn adjust(&mut self, factor: f64) {
        let mut rng = thread_rng();
        self.interval *= factor * rng.gen_range(0.95, 1.05);
        self.next = now() + self.interval;
    }
}

// Comparison is reversed to make it easy to have the newest at the end.
fn word_cmp(a: &LearnWord, b: &LearnWord) -> Ordering {
    b.next.partial_cmp(&a.next).unwrap()
}

// Get the current time as ticks.
fn now() -> f64 {
    let stamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let sec = stamp.as_secs();
    let nsec = stamp.subsec_nanos();

    sec as f64 + (nsec as f64 / 1.0e9)
}

type Dict = BTreeMap<Vec<Stroke>, String>;

fn get_dict() -> Dict {
    let json = include_str!("dict-canonical.json");
    let main: BTreeMap<String, String> = serde_json::from_str(json).unwrap();
    let mut result = BTreeMap::new();
    for (k, v) in main {
        result.insert(Stroke::parse_strokes(&k).unwrap(), v);
    }
    result
}

#[derive(Debug, Deserialize, Serialize)]
pub struct LessonInfo {
    pub title: String,
    pub include: Stroke,
    pub require: Stroke,
    pub tags: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Lesson {
    pub info: LessonInfo,
    pub words: Vec<(Vec<Stroke>, String)>,
}

fn get_lessons() -> Vec<Lesson> {
    let json = include_str!("lessons.json");
    let mut dict: Vec<(Vec<Stroke>, String)> = get_dict().into_iter().collect();
    let infos: Vec<LessonInfo> = serde_json::from_str(json).unwrap();

    let mut result = vec![];
    // Work through the lessons in order, assigning the problems to the first lesson that makes
    // sense.
    for info in infos {
        let (mut with, without): (Vec<_>, Vec<_>) = dict.into_iter().partition(|item| {
            let value = item.0[0].0;
            (value & !info.include.0 == 0) && (value & info.require.0 != 0)
        });
        with.reverse();
        if !with.is_empty() {
            result.push(Lesson {
                info: info,
                words: with,
            });
        }
        dict = without;
    }

    // Put the remaining words in a separate lesson.  The website will never ask for these, but we
    // should still learn them.
    // The 'require' can't ever be correct here, but we'll include something so that the saved data
    // will parse.
    result.push(Lesson {
        info: LessonInfo {
            title: "Uncategorized".to_string(),
            include: Stroke(stroke::NUM - 1),
            require: Stroke(1),
            tags: "Rest".to_string(),
        },
        words: dict,
    });

    result.reverse();

    result
}

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

    #[test]
    fn load_words() {
        let words = Words::new();
        println!("{} lessons", words.unlearned.len());
        for les in &words.unlearned {
            println!("  lesson {} words: {}", les.words.len(), les.info.title);
        }

        let tmp = TempDir::new("words-test").expect("create temp dir");
        let json_path = tmp.path().join("sample.json");
        words.save(&json_path).unwrap();

        let w2 = Words::load(&json_path).unwrap();
        assert_eq!(words.unlearned.len(), w2.unlearned.len());
    }
}
<commit_msg>More aggressive scaling of the interval<commit_after>// The dictionary used for the lessons.

use rand::{Rng, thread_rng};
use serde_json;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fs::{File, rename};
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use stroke::{self, Stroke};
use ::Result;

/// The set of words we are working on.  This represents the current state.
#[derive(Debug, Deserialize, Serialize)]
pub struct Words {
    /// The unlearned words come directly from the json problem sets.
    pub unlearned: Vec<Lesson>,

    pub learning: Vec<LearnWord>,
}

impl Words {
    /// Construct a new word set from internal data.
    pub fn new() -> Words {
        Words {
            unlearned: get_lessons(),
            learning: vec![],
        }
    }

    /// Load a wordset from the given file.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Words> {
        let fd = File::open(path.as_ref())?;
        let result = serde_json::from_reader(&fd)?;
        Ok(result)
    }

    /// Save the wordset to a given file.
    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        let path = path.as_ref();
        let tmp = path.with_extension("tmp");
        {
            let mut fd = File::create(&tmp)?;
            // serde_json::to_writer_pretty(&mut fd, self)?;
            serde_json::to_writer(&mut fd, self)?;
            // serde_yaml::to_writer(&mut fd, self)?;
            // rmp_serde::encode::write(&mut fd, self)?;
        }
        rename(tmp, path)?;
        Ok(())
    }

    /// Extract a new word to learn.  Returns None if there are no more words.
    pub fn get_unlearned(&mut self) -> Option<LearnWord> {
        let mut lesson = match self.unlearned.pop() {
            None => return None,
            Some (l) => l,
        };

        let (strokes, english) = lesson.words.pop().expect("Words in list");

        let result = LearnWord {
            strokes: strokes,
            english: english,
            next: now() + 5.0,
            interval: 5.0,
        };

        // If there are more words in this lesson, push the lesson back.
        if !lesson.words.is_empty() {
            self.unlearned.push(lesson);
        }

        Some(result)
    }

    /// Extract a word to be learned, if were ready for it.
    pub fn get_learned(&mut self) -> Option<LearnWord> {
        match self.learning.pop() {
            None => None,
            Some(w) => {
                if now() >= w.next {
                    Some(w)
                } else {
                    self.learning.push(w);
                    None
                }
            }
        }
    }

    /// Push a word back into the unlearned word list.
    pub fn push_word(&mut self, word: LearnWord) {
        self.learning.push(word);
        self.learning.sort_by(word_cmp);
    }

    /// Return a count of the number of words that are pending.
    pub fn get_counts(&self) -> Counts {
        let n = now();

        // Divide all of the upcoming entries into buckets.
        let mut counts = vec![0; COUNT_BUCKETS.len()];

        for word in &self.learning {
            let mut v = word.interval;
            for (num, b) in COUNT_BUCKETS.iter().enumerate() {
                if v < b.limit {
                    counts[num] += 1;
                    break;
                }
                v /= b.limit;
            }
        }

        let buckets = COUNT_BUCKETS.iter().zip(counts).map(|(aa, bb)| Bucket {
            name: aa.name,
            count: bb,
        }).collect();

        Counts {
            active: self.learning.iter().filter(|x| x.next < n).count(),
            later: self.learning.iter().filter(|x| x.next >= n).count(),
            unlearned: self.unlearned.iter().map(|x| x.words.len()).sum(),

            buckets: buckets,
        }
    }
}

pub struct Counts {
    pub active: usize,
    pub later: usize,
    pub unlearned: usize,

    // Buckets for later.  The sum of all of these should match the `later+active` value above.
    pub buckets: Vec<Bucket>,
}

pub struct Bucket {
    pub name: &'static str,
    pub count: usize,
}

struct BucketBin {
    name: &'static str,
    limit: f64,
}

static COUNT_BUCKETS: &'static [BucketBin] = &[
    BucketBin{ name: "sec", limit: 60.0 },
    BucketBin{ name: "min", limit: 60.0 },
    BucketBin{ name: "hr", limit: 24.0 },
    BucketBin{ name: "day", limit: 30.0 },
    BucketBin{ name: "mon", limit: 1.0e30 },
];

#[derive(Debug, Serialize, Deserialize)]
pub struct LearnWord {
    pub strokes: Vec<Stroke>,
    pub english: String,
    pub next: f64,
    pub interval: f64,
}

impl LearnWord {
    pub fn correct(&mut self) {
        self.adjust(2.2)
    }

    pub fn incorrect(&mut self) {
        self.adjust(0.25)
    }

    fn adjust(&mut self, factor: f64) {
        let mut rng = thread_rng();
        let n = now();
        // If we've gone past the deadline, add this time to the interval.
        let interval = if factor > 1.0 {
            if n > self.next {
                self.interval + (n - self.next)
            } else {
                self.interval
            }
        } else {
            self.interval
        };
        // Compute the interval, capping with a minimum of 5 seconds.
        self.interval = (interval * factor * rng.gen_range(0.75, 1.25)).max(5.0);
        self.next = now() + self.interval;
    }
}

// Comparison is reversed to make it easy to have the newest at the end.
fn word_cmp(a: &LearnWord, b: &LearnWord) -> Ordering {
    b.next.partial_cmp(&a.next).unwrap()
}

// Get the current time as ticks.
fn now() -> f64 {
    let stamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let sec = stamp.as_secs();
    let nsec = stamp.subsec_nanos();

    sec as f64 + (nsec as f64 / 1.0e9)
}

type Dict = BTreeMap<Vec<Stroke>, String>;

fn get_dict() -> Dict {
    let json = include_str!("dict-canonical.json");
    let main: BTreeMap<String, String> = serde_json::from_str(json).unwrap();
    let mut result = BTreeMap::new();
    for (k, v) in main {
        result.insert(Stroke::parse_strokes(&k).unwrap(), v);
    }
    result
}

#[derive(Debug, Deserialize, Serialize)]
pub struct LessonInfo {
    pub title: String,
    pub include: Stroke,
    pub require: Stroke,
    pub tags: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Lesson {
    pub info: LessonInfo,
    pub words: Vec<(Vec<Stroke>, String)>,
}

fn get_lessons() -> Vec<Lesson> {
    let json = include_str!("lessons.json");
    let mut dict: Vec<(Vec<Stroke>, String)> = get_dict().into_iter().collect();
    let infos: Vec<LessonInfo> = serde_json::from_str(json).unwrap();

    let mut result = vec![];
    // Work through the lessons in order, assigning the problems to the first lesson that makes
    // sense.
    for info in infos {
        let (mut with, without): (Vec<_>, Vec<_>) = dict.into_iter().partition(|item| {
            let value = item.0[0].0;
            (value & !info.include.0 == 0) && (value & info.require.0 != 0)
        });
        with.reverse();
        if !with.is_empty() {
            result.push(Lesson {
                info: info,
                words: with,
            });
        }
        dict = without;
    }

    // Put the remaining words in a separate lesson.  The website will never ask for these, but we
    // should still learn them.
    // The 'require' can't ever be correct here, but we'll include something so that the saved data
    // will parse.
    result.push(Lesson {
        info: LessonInfo {
            title: "Uncategorized".to_string(),
            include: Stroke(stroke::NUM - 1),
            require: Stroke(1),
            tags: "Rest".to_string(),
        },
        words: dict,
    });

    result.reverse();

    result
}

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

    #[test]
    fn load_words() {
        let words = Words::new();
        println!("{} lessons", words.unlearned.len());
        for les in &words.unlearned {
            println!("  lesson {} words: {}", les.words.len(), les.info.title);
        }

        let tmp = TempDir::new("words-test").expect("create temp dir");
        let json_path = tmp.path().join("sample.json");
        words.save(&json_path).unwrap();

        let w2 = Words::load(&json_path).unwrap();
        assert_eq!(words.unlearned.len(), w2.unlearned.len());
    }
}
<|endoftext|>


<commit_before>use super::{
    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
};
use crate::infer::InferCtxt;
use crate::ty::subst::Subst;
use crate::ty::{self, GenericParamDefKind};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::sym;

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
    fn impl_similar_to(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> Option<DefId> {
        let tcx = self.tcx;
        let param_env = obligation.param_env;
        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
        let trait_self_ty = trait_ref.self_ty();

        let mut self_match_impls = vec![];
        let mut fuzzy_match_impls = vec![];

        self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
            let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);

            let impl_self_ty = impl_trait_ref.self_ty();

            if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
                self_match_impls.push(def_id);

                if trait_ref
                    .substs
                    .types()
                    .skip(1)
                    .zip(impl_trait_ref.substs.types().skip(1))
                    .all(|(u, v)| self.fuzzy_match_tys(u, v))
                {
                    fuzzy_match_impls.push(def_id);
                }
            }
        });

        let impl_def_id = if self_match_impls.len() == 1 {
            self_match_impls[0]
        } else if fuzzy_match_impls.len() == 1 {
            fuzzy_match_impls[0]
        } else {
            return None;
        };

        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
    }

    /// Used to set on_unimplemented's `ItemContext`
    /// to be the enclosing (async) block/function/closure
    fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
        let hir = &self.tcx.hir();
        let node = hir.find(hir_id)?;
        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
            self.describe_generator(*body_id).or_else(|| {
                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                    "an async function"
                } else {
                    "a function"
                })
            })
        } else if let hir::Node::TraitItem(hir::TraitItem {
            kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| Some("a trait method"))
        } else if let hir::Node::ImplItem(hir::ImplItem {
            kind: hir::ImplItemKind::Method(sig, body_id),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| {
                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                    "an async method"
                } else {
                    "a method"
                })
            })
        } else if let hir::Node::Expr(hir::Expr {
            kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| {
                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
            })
        } else if let hir::Node::Expr(hir::Expr { .. }) = &node {
            let parent_hid = hir.get_parent_node(hir_id);
            if parent_hid != hir_id {
                return self.describe_enclosure(parent_hid);
            } else {
                None
            }
        } else {
            None
        }
    }

    crate fn on_unimplemented_note(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> OnUnimplementedNote {
        let def_id =
            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
        let trait_ref = *trait_ref.skip_binder();

        let mut flags = vec![];
        flags.push((
            sym::item_context,
            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
        ));

        match obligation.cause.code {
            ObligationCauseCode::BuiltinDerivedObligation(..)
            | ObligationCauseCode::ImplDerivedObligation(..) => {}
            _ => {
                // this is a "direct", user-specified, rather than derived,
                // obligation.
                flags.push((sym::direct, None));
            }
        }

        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
            // FIXME: maybe also have some way of handling methods
            // from other traits? That would require name resolution,
            // which we might want to be some sort of hygienic.
            //
            // Currently I'm leaving it for what I need for `try`.
            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
                let method = self.tcx.item_name(item);
                flags.push((sym::from_method, None));
                flags.push((sym::from_method, Some(method.to_string())));
            }
        }
        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
            flags.push((sym::parent_trait, Some(t)));
        }

        if let Some(k) = obligation.cause.span.desugaring_kind() {
            flags.push((sym::from_desugaring, None));
            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
        }
        let generics = self.tcx.generics_of(def_id);
        let self_ty = trait_ref.self_ty();
        // This is also included through the generics list as `Self`,
        // but the parser won't allow you to use it
        flags.push((sym::_Self, Some(self_ty.to_string())));
        if let Some(def) = self_ty.ty_adt_def() {
            // We also want to be able to select self's original
            // signature with no type arguments resolved
            flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
        }

        for param in generics.params.iter() {
            let value = match param.kind {
                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
                    trait_ref.substs[param.index as usize].to_string()
                }
                GenericParamDefKind::Lifetime => continue,
            };
            let name = param.name;
            flags.push((name, Some(value)));
        }

        if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
            flags.push((sym::crate_local, None));
        }

        // Allow targeting all integers using `{integral}`, even if the exact type was resolved
        if self_ty.is_integral() {
            flags.push((sym::_Self, Some("{integral}".to_owned())));
        }

        if let ty::Array(aty, len) = self_ty.kind {
            flags.push((sym::_Self, Some("[]".to_owned())));
            flags.push((sym::_Self, Some(format!("[{}]", aty))));
            if let Some(def) = aty.ty_adt_def() {
                // We also want to be able to select the array's type's original
                // signature with no type arguments resolved
                flags.push((
                    sym::_Self,
                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
                ));
                let tcx = self.tcx;
                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
                    ));
                } else {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
                    ));
                }
            }
        }

        if let Ok(Some(command)) =
            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
        {
            command.evaluate(self.tcx, trait_ref, &flags[..])
        } else {
            OnUnimplementedNote::default()
        }
    }
}
<commit_msg>Cleanup: rewrite conditional as match<commit_after>use super::{
    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
};
use crate::infer::InferCtxt;
use crate::ty::subst::Subst;
use crate::ty::{self, GenericParamDefKind};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::sym;

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
    fn impl_similar_to(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> Option<DefId> {
        let tcx = self.tcx;
        let param_env = obligation.param_env;
        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
        let trait_self_ty = trait_ref.self_ty();

        let mut self_match_impls = vec![];
        let mut fuzzy_match_impls = vec![];

        self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
            let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);

            let impl_self_ty = impl_trait_ref.self_ty();

            if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
                self_match_impls.push(def_id);

                if trait_ref
                    .substs
                    .types()
                    .skip(1)
                    .zip(impl_trait_ref.substs.types().skip(1))
                    .all(|(u, v)| self.fuzzy_match_tys(u, v))
                {
                    fuzzy_match_impls.push(def_id);
                }
            }
        });

        let impl_def_id = if self_match_impls.len() == 1 {
            self_match_impls[0]
        } else if fuzzy_match_impls.len() == 1 {
            fuzzy_match_impls[0]
        } else {
            return None;
        };

        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
    }

    /// Used to set on_unimplemented's `ItemContext`
    /// to be the enclosing (async) block/function/closure
    fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
        let hir = &self.tcx.hir();
        let node = hir.find(hir_id)?;
        match &node {
            hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
                self.describe_generator(*body_id).or_else(|| {
                    Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                        "an async function"
                    } else {
                        "a function"
                    })
                })
            }
            hir::Node::TraitItem(hir::TraitItem {
                kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)),
                ..
            }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")),
            hir::Node::ImplItem(hir::ImplItem {
                kind: hir::ImplItemKind::Method(sig, body_id),
                ..
            }) => self.describe_generator(*body_id).or_else(|| {
                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                    "an async method"
                } else {
                    "a method"
                })
            }),
            hir::Node::Expr(hir::Expr {
                kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
                ..
            }) => self.describe_generator(*body_id).or_else(|| {
                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
            }),
            hir::Node::Expr(hir::Expr { .. }) => {
                let parent_hid = hir.get_parent_node(hir_id);
                if parent_hid != hir_id {
                    return self.describe_enclosure(parent_hid);
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    crate fn on_unimplemented_note(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> OnUnimplementedNote {
        let def_id =
            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
        let trait_ref = *trait_ref.skip_binder();

        let mut flags = vec![];
        flags.push((
            sym::item_context,
            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
        ));

        match obligation.cause.code {
            ObligationCauseCode::BuiltinDerivedObligation(..)
            | ObligationCauseCode::ImplDerivedObligation(..) => {}
            _ => {
                // this is a "direct", user-specified, rather than derived,
                // obligation.
                flags.push((sym::direct, None));
            }
        }

        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
            // FIXME: maybe also have some way of handling methods
            // from other traits? That would require name resolution,
            // which we might want to be some sort of hygienic.
            //
            // Currently I'm leaving it for what I need for `try`.
            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
                let method = self.tcx.item_name(item);
                flags.push((sym::from_method, None));
                flags.push((sym::from_method, Some(method.to_string())));
            }
        }
        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
            flags.push((sym::parent_trait, Some(t)));
        }

        if let Some(k) = obligation.cause.span.desugaring_kind() {
            flags.push((sym::from_desugaring, None));
            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
        }
        let generics = self.tcx.generics_of(def_id);
        let self_ty = trait_ref.self_ty();
        // This is also included through the generics list as `Self`,
        // but the parser won't allow you to use it
        flags.push((sym::_Self, Some(self_ty.to_string())));
        if let Some(def) = self_ty.ty_adt_def() {
            // We also want to be able to select self's original
            // signature with no type arguments resolved
            flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
        }

        for param in generics.params.iter() {
            let value = match param.kind {
                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
                    trait_ref.substs[param.index as usize].to_string()
                }
                GenericParamDefKind::Lifetime => continue,
            };
            let name = param.name;
            flags.push((name, Some(value)));
        }

        if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
            flags.push((sym::crate_local, None));
        }

        // Allow targeting all integers using `{integral}`, even if the exact type was resolved
        if self_ty.is_integral() {
            flags.push((sym::_Self, Some("{integral}".to_owned())));
        }

        if let ty::Array(aty, len) = self_ty.kind {
            flags.push((sym::_Self, Some("[]".to_owned())));
            flags.push((sym::_Self, Some(format!("[{}]", aty))));
            if let Some(def) = aty.ty_adt_def() {
                // We also want to be able to select the array's type's original
                // signature with no type arguments resolved
                flags.push((
                    sym::_Self,
                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
                ));
                let tcx = self.tcx;
                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
                    ));
                } else {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
                    ));
                }
            }
        }

        if let Ok(Some(command)) =
            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
        {
            command.evaluate(self.tcx, trait_ref, &flags[..])
        } else {
            OnUnimplementedNote::default()
        }
    }
}
<|endoftext|>


<commit_before>/**
 * Count the Population of an unsigned integer. Returns how many bits are
 * set to 1.
 *
 * Currently designed for a 32-bit unsigned integer.
 *
 * Many chips have a CTPOP instruction available and would be an order
 * of magnitude speed improvement.
 */
pure fn ctpop32(map : u32) -> u32 {
  // Code smell: these constants should not be defined in the function.
  let SK5  : u32 = 0x55555555;
  let SK3  : u32 = 0x33333333;
  let SKF0 : u32 = 0xF0F0F0F;
  let SKFF : u32 = 0xFF00FF;
  let mut Map = copy map;

  Map-=((Map>>1)&SK5);
  Map=(Map&SK3)+((Map>>2)&SK3);
  Map=(Map&SKF0)+((Map>>4)&SKF0);
  Map+=Map>>8;

  return (Map+(Map>>16))&0x3F;
}

#[test]
fn test_ctpop32() {
  assert(ctpop32(0x0) == 0);
  assert(ctpop32(0x1) == 1);
  assert(ctpop32(0x3) == 2);
  assert(ctpop32(0x7) == 3);
  assert(ctpop32(0xF) == 4);
  assert(ctpop32(0x10) == 1);
  assert(ctpop32(0xFF) == 8);
  assert(ctpop32(0xAD) == 5);
  assert(ctpop32(0x2FADBFF) == 21);
  assert(ctpop32(0x82FFFFFF) == 26);
  assert(ctpop32(0x8FFFFFFF) == 29);
  assert(ctpop32(0xFFFFFFFF) == 32);
}<commit_msg>turned inner lets into consts<commit_after>const SK5  : u32 = 0x55555555;
const SK3  : u32 = 0x33333333;
const SKF0 : u32 = 0xF0F0F0F;
const SKFF : u32 = 0xFF00FF;

/**
 * Count the Population of an unsigned integer. Returns how many bits are
 * set to 1.
 *
 * Currently designed for a 32-bit unsigned integer.
 *
 * Many chips have a CTPOP instruction available and would be an order
 * of magnitude speed improvement.
 */
pure fn ctpop32(map : u32) -> u32 {
  let mut Map = copy map;

  Map-=((Map>>1)&SK5);
  Map=(Map&SK3)+((Map>>2)&SK3);
  Map=(Map&SKF0)+((Map>>4)&SKF0);
  Map+=Map>>8;

  return (Map+(Map>>16))&0x3F;
}

#[test]
fn test_ctpop32() {
  assert(ctpop32(0x0) == 0);
  assert(ctpop32(0x1) == 1);
  assert(ctpop32(0x3) == 2);
  assert(ctpop32(0x7) == 3);
  assert(ctpop32(0xF) == 4);
  assert(ctpop32(0x10) == 1);
  assert(ctpop32(0xFF) == 8);
  assert(ctpop32(0xAD) == 5);
  assert(ctpop32(0x2FADBFF) == 21);
  assert(ctpop32(0x82FFFFFF) == 26);
  assert(ctpop32(0x8FFFFFFF) == 29);
  assert(ctpop32(0xFFFFFFFF) == 32);
}<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId, Throughput};

use image_decoder_benchmarks::{
    IMAGES,
    load_image_to_memory,
    decode_jpeg_decoder,
    decode_turbojpeg,
};

use std::time::Duration;

fn bench_fibs(c: &mut Criterion) {
    let mut group = c.benchmark_group("Images");
    group.measurement_time(Duration::from_secs(15));

    for image in IMAGES.iter() {
        let contents = load_image_to_memory(image);

        let size = contents.len();
        group.throughput(Throughput::Bytes(size as u64));

        group.bench_with_input(BenchmarkId::new("turbo", image), &size,
            |b, _i| b.iter(|| decode_turbojpeg(black_box(&contents)))
        );
        group.bench_with_input(BenchmarkId::new("jpeg_decoder", image), &size,
            |b, _i| b.iter(|| decode_jpeg_decoder(black_box(&contents)))
        );
    }

    group.finish();
}

criterion_group!(benches, bench_fibs);
criterion_main!(benches);
<commit_msg>Update jpeg_benchmark.rs<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId, Throughput};

use image_decoder_benchmarks::{
    IMAGES,
    load_image_to_memory,
    decode_jpeg_decoder,
    decode_turbojpeg,
};

use std::time::Duration;

fn bench_jpegs(c: &mut Criterion) {
    let mut group = c.benchmark_group("Images");
    group.measurement_time(Duration::from_secs(15));

    for image in IMAGES.iter() {
        let contents = load_image_to_memory(image);

        let size = contents.len();
        group.throughput(Throughput::Bytes(size as u64));

        group.bench_with_input(BenchmarkId::new("turbo", image), &size,
            |b, _i| b.iter(|| decode_turbojpeg(black_box(&contents)))
        );
        group.bench_with_input(BenchmarkId::new("jpeg_decoder", image), &size,
            |b, _i| b.iter(|| decode_jpeg_decoder(black_box(&contents)))
        );
    }

    group.finish();
}

criterion_group!(benches, bench_jpegs);
criterion_main!(benches);
<|endoftext|>


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

/*!
An attempt to move all intrinsic declarations to a single place,
as mentioned in #3369
The intrinsics are defined in librustc/middle/trans/foreign.rs.
*/

#[abi = "rust-intrinsic"]
pub extern "rust-intrinsic" {
    pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
    pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
    pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;

    pub fn atomic_xchg(dst: &mut int, src: int) -> int;
    pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
    pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int;

    pub fn atomic_xadd(dst: &mut int, src: int) -> int;
    pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
    pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int;

    pub fn atomic_xsub(dst: &mut int, src: int) -> int;
    pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
    pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int;

    pub fn size_of<T>() -> uint;

    pub fn move_val<T>(dst: &mut T, src: T);
    pub fn move_val_init<T>(dst: &mut T, src: T);

    pub fn min_align_of<T>() -> uint;
    pub fn pref_align_of<T>() -> uint;

    pub fn get_tydesc<T>() -> *();

    pub fn init<T>() -> T;

    #[cfg(not(stage0))]
    pub unsafe fn uninit<T>() -> T;

    pub fn forget<T>(_: T) -> ();

    pub fn needs_drop<T>() -> bool;

    // XXX: intrinsic uses legacy modes and has reference to TyDesc
    // and TyVisitor which are in librustc
    //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> ();
    // XXX: intrinsic uses legacy modes
    //fn frame_address(f: &once fn(*u8));

    pub fn morestack_addr() -> *();

    pub fn memmove32(dst: *mut u8, src: *u8, size: u32);
    pub fn memmove64(dst: *mut u8, src: *u8, size: u64);

    pub fn sqrtf32(x: f32) -> f32;
    pub fn sqrtf64(x: f64) -> f64;

    pub fn powif32(a: f32, x: i32) -> f32;
    pub fn powif64(a: f64, x: i32) -> f64;

    // the following kill the stack canary without
    // `fixed_stack_segment`. This possibly only affects the f64
    // variants, but it's hard to be sure since it seems to only
    // occur with fairly specific arguments.
    #[fixed_stack_segment]
    pub fn sinf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn sinf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn cosf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn cosf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn powf32(a: f32, x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn powf64(a: f64, x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn expf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn expf64(x: f64) -> f64;

    pub fn exp2f32(x: f32) -> f32;
    pub fn exp2f64(x: f64) -> f64;

    pub fn logf32(x: f32) -> f32;
    pub fn logf64(x: f64) -> f64;

    pub fn log10f32(x: f32) -> f32;
    pub fn log10f64(x: f64) -> f64;

    pub fn log2f32(x: f32) -> f32;
    pub fn log2f64(x: f64) -> f64;

    pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
    pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;

    pub fn fabsf32(x: f32) -> f32;
    pub fn fabsf64(x: f64) -> f64;

    pub fn floorf32(x: f32) -> f32;
    pub fn floorf64(x: f64) -> f64;

    pub fn ceilf32(x: f32) -> f32;
    pub fn ceilf64(x: f64) -> f64;

    pub fn truncf32(x: f32) -> f32;
    pub fn truncf64(x: f64) -> f64;

    pub fn ctpop8(x: i8) -> i8;
    pub fn ctpop16(x: i16) -> i16;
    pub fn ctpop32(x: i32) -> i32;
    pub fn ctpop64(x: i64) -> i64;

    pub fn ctlz8(x: i8) -> i8;
    pub fn ctlz16(x: i16) -> i16;
    pub fn ctlz32(x: i32) -> i32;
    pub fn ctlz64(x: i64) -> i64;

    pub fn cttz8(x: i8) -> i8;
    pub fn cttz16(x: i16) -> i16;
    pub fn cttz32(x: i32) -> i32;
    pub fn cttz64(x: i64) -> i64;

    pub fn bswap16(x: i16) -> i16;
    pub fn bswap32(x: i32) -> i32;
    pub fn bswap64(x: i64) -> i64;
}
<commit_msg>core: Make intrinsics::init unsafe<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
An attempt to move all intrinsic declarations to a single place,
as mentioned in #3369
The intrinsics are defined in librustc/middle/trans/foreign.rs.
*/

#[abi = "rust-intrinsic"]
pub extern "rust-intrinsic" {
    pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
    pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
    pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;

    pub fn atomic_xchg(dst: &mut int, src: int) -> int;
    pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
    pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int;

    pub fn atomic_xadd(dst: &mut int, src: int) -> int;
    pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
    pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int;

    pub fn atomic_xsub(dst: &mut int, src: int) -> int;
    pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
    pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int;

    pub fn size_of<T>() -> uint;

    pub fn move_val<T>(dst: &mut T, src: T);
    pub fn move_val_init<T>(dst: &mut T, src: T);

    pub fn min_align_of<T>() -> uint;
    pub fn pref_align_of<T>() -> uint;

    pub fn get_tydesc<T>() -> *();

    /// init is unsafe because it returns a zeroed-out datum,
    /// which is unsafe unless T is POD. We don't have a POD
    /// kind yet. (See #4074)
    pub unsafe fn init<T>() -> T;

    #[cfg(not(stage0))]
    pub unsafe fn uninit<T>() -> T;

    pub fn forget<T>(_: T) -> ();

    pub fn needs_drop<T>() -> bool;

    // XXX: intrinsic uses legacy modes and has reference to TyDesc
    // and TyVisitor which are in librustc
    //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> ();
    // XXX: intrinsic uses legacy modes
    //fn frame_address(f: &once fn(*u8));

    pub fn morestack_addr() -> *();

    pub fn memmove32(dst: *mut u8, src: *u8, size: u32);
    pub fn memmove64(dst: *mut u8, src: *u8, size: u64);

    pub fn sqrtf32(x: f32) -> f32;
    pub fn sqrtf64(x: f64) -> f64;

    pub fn powif32(a: f32, x: i32) -> f32;
    pub fn powif64(a: f64, x: i32) -> f64;

    // the following kill the stack canary without
    // `fixed_stack_segment`. This possibly only affects the f64
    // variants, but it's hard to be sure since it seems to only
    // occur with fairly specific arguments.
    #[fixed_stack_segment]
    pub fn sinf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn sinf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn cosf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn cosf64(x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn powf32(a: f32, x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn powf64(a: f64, x: f64) -> f64;

    #[fixed_stack_segment]
    pub fn expf32(x: f32) -> f32;
    #[fixed_stack_segment]
    pub fn expf64(x: f64) -> f64;

    pub fn exp2f32(x: f32) -> f32;
    pub fn exp2f64(x: f64) -> f64;

    pub fn logf32(x: f32) -> f32;
    pub fn logf64(x: f64) -> f64;

    pub fn log10f32(x: f32) -> f32;
    pub fn log10f64(x: f64) -> f64;

    pub fn log2f32(x: f32) -> f32;
    pub fn log2f64(x: f64) -> f64;

    pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
    pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;

    pub fn fabsf32(x: f32) -> f32;
    pub fn fabsf64(x: f64) -> f64;

    pub fn floorf32(x: f32) -> f32;
    pub fn floorf64(x: f64) -> f64;

    pub fn ceilf32(x: f32) -> f32;
    pub fn ceilf64(x: f64) -> f64;

    pub fn truncf32(x: f32) -> f32;
    pub fn truncf64(x: f64) -> f64;

    pub fn ctpop8(x: i8) -> i8;
    pub fn ctpop16(x: i16) -> i16;
    pub fn ctpop32(x: i32) -> i32;
    pub fn ctpop64(x: i64) -> i64;

    pub fn ctlz8(x: i8) -> i8;
    pub fn ctlz16(x: i16) -> i16;
    pub fn ctlz32(x: i32) -> i32;
    pub fn ctlz64(x: i64) -> i64;

    pub fn cttz8(x: i8) -> i8;
    pub fn cttz16(x: i16) -> i16;
    pub fn cttz32(x: i32) -> i32;
    pub fn cttz64(x: i64) -> i64;

    pub fn bswap16(x: i16) -> i16;
    pub fn bswap32(x: i32) -> i32;
    pub fn bswap64(x: i64) -> i64;
}
<|endoftext|>