<commit_before>
use std::error::Error;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use reader::{self, Form, InputStream};
use analyzer::{self, Analysis, AstNode};
use symbol_table::*;
use vm::*;

// TODO: return type
pub fn interpret<T: Into<String>>(input: T) -> String {
    let input = input.into();
    let form = read(input).unwrap();
    let analysis = analyze(form).unwrap();
    let program = compile(analysis).unwrap();

    exec(program)

    //    read(input)
    //        .and_then(analyze)
    //        .and_then(typecheck)
    //        .and_then(compile)
    //        .and_then(exec)
    //        .unwrap()
    //        .to_string()
}

fn read(input: String) -> Result<Vec<Form>, Box<Error>> {
    let mut reader = reader::ReaderEnv::new_default(InputStream::new(input));
    reader.read_all().map_err(|_| reader.last_error().into())

}
fn analyze(input: Vec<Form>) -> Result<Analysis, Box<Error>> {
    analyzer::analyze_from_root(input).map_err(Into::into)
}

fn compile(input: Analysis) -> Result<Program, Box<Error>> {
    fn emit_const(p: &mut ProgramBuilder, val: i64) -> Result<bool, Box<Error>> {
        p.load_i64(val);
        Ok(true)
    }

    fn emit_var(p: &mut ProgramBuilder,
                var_id: u32,
                env: &SymbolTable)
                -> Result<bool, Box<Error>> {
        let var_record = env.lookup_id(var_id).unwrap();

        match *var_record.kind() {
            VarKind::Var => {
                p.load_var(var_id);
                Ok(true)
            }
            _ => unimplemented!(),
        }
    }

    fn emit_do(p: &mut ProgramBuilder,
               env: &SymbolTable,
               args: &[AstNode])
               -> Result<bool, Box<Error>> {
        let (last, others) = args.split_last().expect("emit_do");

        for arg in others {
            // if something was left on the stack, clean it up
            if try!(emit(arg, env, p)) {
                p.pop();
            }
        }

        emit(last, env, p)
    }

    fn emit_def(p: &mut ProgramBuilder,
                env: &SymbolTable,
                args: &[AstNode])
                -> Result<bool, Box<Error>> {
        assert_eq!(args.len(), 2);

        let var = &args[0];
        let val = &args[1];

        match *var {
            AstNode::Var(var_id) => {
                match *val {
                    AstNode::Const(val) => {
                        p.in_prologue();
                        p.load_i64(val);
                        p.def_var(var_id);
                        p.store_var(var_id);
                        p.out_prologue();
                    }
                    AstNode::Var(val_id) => {
                        p.in_prologue();
                        p.load_var(val_id);
                        p.def_var(var_id);
                        p.store_var(var_id);
                        p.out_prologue();
                    }
                    AstNode::Inv(ref callee, ref args) => {
                        emit_inv(p, callee, args, env).unwrap();
                        p.in_prologue();
                        p.def_var(var_id);
                        p.store_var(var_id);
                        p.out_prologue();
                    }
                }
            }
            _ => return Err("1st arg of `def` must be a var".into()),
        }

        Ok(false) // def never puts anything on the stack (TODO: nil?)
    }

    fn emit_fn(p: &mut ProgramBuilder,
               env: &SymbolTable,
               args: &[AstNode])
               -> Result<bool, Box<Error>> {

        fn next_fn_id() -> u32 {
            static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

            COUNTER.fetch_add(1, Ordering::SeqCst) as u32
        }

        assert!(args.len() > 1);
        let (arg_list, body) = args.split_first().unwrap();

        match *arg_list {
            AstNode::Inv(..) => {}
            _ => return Err("Malformed argument list".into()),
        }

        // return ref to function? (addr?)
        let id = next_fn_id();
        p.begin_fn_def(id);

        // emit param marshalling header
        if let AstNode::Inv(ref callee, ref args) = *arg_list {
            for arg in ::std::iter::once(&**callee).chain(args.iter()) {
                match *arg {
                    AstNode::Var(arg_id) => {
                        p.def_var(arg_id);
                        p.store_var(arg_id);
                    }
                    _ => return Err("Argument lists may only contain vars".into()),
                }
            }
        }

        // emit body, wrapped in `do` form
        try!(emit_do(p, env, body));
        p.ret();

        p.end_fn_def();
        Ok(true)
    }

    fn emit_inv(p: &mut ProgramBuilder,
                callee: &AstNode,
                args: &[AstNode],
                env: &SymbolTable)
                -> Result<bool, Box<Error>> {

        match *callee {
            AstNode::Var(id) => {
                let var_record = env.lookup_id(id).unwrap();
                match *var_record.kind() {
                    VarKind::Var => {
                        for arg in args {
                            try!(emit(arg, env, p));
                        }

                        p.load_var(id);
                        p.call();
                        Ok(true) // TODO: not all fns return a value
                    }
                    VarKind::NormalFn => {
                        unimplemented!();
                        // for arg in args {
                        //     try!(emit(arg, env, p));
                        // }
                        // emit(callee, env, p)
                    }
                    VarKind::SpecialFn => {
                        match var_record.ident() {
                            "def" => emit_def(p, env, args),
                            "fn" => emit_fn(p, env, args),
                            "do" => emit_do(p, env, args),
                            "+" => {
                                assert!(args.len() < 256);

                                for arg in args {
                                    try!(emit(arg, env, p));
                                }

                                p.add(args.len() as u8);
                                Ok(true)
                            }
                            _ => unimplemented!(),
                        }
                    }
                    VarKind::Constant => Err("cannot invoke constant".into()),
                }
            }
            _ => {
                for arg in args {
                    try!(emit(arg, env, p));
                }
                emit(callee, env, p)
            }
        }
    }

    // TODO: lift defs to top-level
    fn emit(node: &AstNode, env: &SymbolTable, p: &mut ProgramBuilder) -> Result<bool, Box<Error>> {
        match *node {
            AstNode::Const(val) => emit_const(p, val),
            AstNode::Var(id) => emit_var(p, id, env),
            AstNode::Inv(ref callee, ref args) => emit_inv(p, callee, args, env),
        }
    }

    let mut program = new_program();
    assert!(try!(emit(input.ast(), input.env(), &mut program)),
            "nothing will be on the stack");
    program.exit();

    let program = program.finish(input.env());

    println!("Program: {:?}", program);
    Ok(program)
}

fn exec(input: Program) -> String {
    format!("{}", exec_program(input))
}

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

    #[test]
    fn add_int_constants() {
        assert_eq!(interpret("(+ 1 2 3)"), "6");
    }

    #[test]
    fn nested_add_int_constants() {
        assert_eq!(interpret("(+ (+) (+ 1 (+ 1 1)) (+ 1 2))"), "6");
    }

    #[test]
    fn def_const_var() {
        assert_eq!(interpret("(def x 7) x"), "7");
    }

    #[test]
    fn add_const_vars() {
        assert_eq!(interpret("(def x 3) (def y 4) (+ x 7 y)"), "14");
    }

    #[test]
    fn copy_var() {
        assert_eq!(interpret("(def x 3) (def y x) y"), "3");
    }

    #[test]
    fn def_fn() {
        assert_eq!(interpret("(def f (fn (x) (+ 1 x x))) (f 7)"), "15");
    }

    #[test]
    fn nested_def_fn() {
        assert_eq!(interpret("(def quadruple (fn (x) \
                                               (def double (fn (y) \
                                                             (+ y y))) \
                                               (+ (double x) (double x)))) \
                              (quadruple 7)"),
                   "28");
    }
}
<commit_msg>Tear out compiler<commit_after>
use std::error::Error;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use reader::{self, Form, InputStream};
use analyzer::{self, Analysis, AstNode};
use symbol_table::*;
use vm::*;

// TODO: return type
pub fn interpret<T: Into<String>>(input: T) -> String {
    let input = input.into();
    let form = read(input).unwrap();
    let analysis = analyze(form).unwrap();
    let program = compile(analysis).unwrap();

    exec(program)

    //    read(input)
    //        .and_then(analyze)
    //        .and_then(typecheck)
    //        .and_then(compile)
    //        .and_then(exec)
    //        .unwrap()
    //        .to_string()
}

fn read(input: String) -> Result<Vec<Form>, Box<Error>> {
    let mut reader = reader::ReaderEnv::new_default(InputStream::new(input));
    reader.read_all().map_err(|_| reader.last_error().into())

}
fn analyze(input: Vec<Form>) -> Result<Analysis, Box<Error>> {
    analyzer::analyze_from_root(input).map_err(Into::into)
}

fn compile(input: Analysis) -> Result<Program, Box<Error>> {
    // use scopes!
    // no special 'top-level' anonymous scope
    // walk tree and visit nodes:
    // - fn nodes: emit function in text section, 'value' of the node is... the addr? a special NormalFn kind?
    //
    //

    // some things are not known until post-assembly/linking, primarily fn addresses

    unimplemented!()
    // let mut program = new_program();
    // assert!(try!(emit(input.ast(), input.env(), &mut program)),
    //         "nothing will be on the stack");
    // program.exit();

    // let program = program.finish(input.env());

    // println!("Program: {:?}", program);
    // Ok(program)
}

fn exec(input: Program) -> String {
    format!("{}", exec_program(input))
}

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

    #[test]
    fn add_int_constants() {
        assert_eq!(interpret("(+ 1 2 3)"), "6");
    }

    #[test]
    fn nested_add_int_constants() {
        assert_eq!(interpret("(+ (+) (+ 1 (+ 1 1)) (+ 1 2))"), "6");
    }

    #[test]
    fn def_const_var() {
        assert_eq!(interpret("(def x 7) x"), "7");
    }

    #[test]
    fn add_const_vars() {
        assert_eq!(interpret("(def x 3) (def y 4) (+ x 7 y)"), "14");
    }

    #[test]
    fn copy_var() {
        assert_eq!(interpret("(def x 3) (def y x) y"), "3");
    }

    #[test]
    fn def_fn() {
        assert_eq!(interpret("(def f (fn (x) (+ 1 x x))) (f 7)"), "15");
    }

    #[test]
    fn nested_def_fn() {
        assert_eq!(interpret("(def quadruple (fn (x) \
                                               (def double (fn (y) \
                                                             (+ y y))) \
                                               (+ (double x) (double x)))) \
                              (quadruple 7)"),
                   "28");
    }
}
<|endoftext|>


<commit_before>use lazy_static::lazy_static;
use regex::{Captures, Regex};
use std::{borrow::Borrow, cmp::Ordering};

use crate::colors::Color;
use crate::game_object::{GameObject, GameObjectRef};
use crate::number_utils::written_number;
use crate::objects::{ItemFlags, Realm};

const COLOR_MAP: [&str; 16] = [
    "37;1", "37", "30;1", "30", "31;1", "31", "33;1", "33", "32;1", "32", "36;1", "36", "34;1",
    "34", "35;1", "35",
];

pub fn capitalize(string: &str) -> String {
    let mut chars: Vec<char> = string.chars().collect();
    if let Some(c) = chars.get(0) {
        chars[0] = c.to_ascii_uppercase();
    }
    chars.into_iter().collect()
}

pub fn colorize(string: &str, color: Color) -> String {
    format!("\x1B[{}m{}\x1B[0m", COLOR_MAP[color as usize], string)
}

fn count_objects<'a>(
    realm: &'a Realm,
    object_refs: &[GameObjectRef],
) -> Vec<(&'a dyn GameObject, u16)> {
    let mut objects_with_counts = Vec::<(&dyn GameObject, u16)>::new();
    for object in object_refs
        .iter()
        .filter_map(|object_ref| realm.object(*object_ref))
    {
        if let Some(object_with_count) = objects_with_counts
            .iter_mut()
            .find(|(other, _)| other.name() == object.name())
        {
            object_with_count.1 += 1;
        } else {
            objects_with_counts.push((object, 1));
        }
    }
    objects_with_counts
}

pub fn definite_article_from_noun(noun: String) -> &'static str {
    if noun.chars().next().map(is_vowel).unwrap_or(false) {
        "an"
    } else {
        "a"
    }
}

pub fn describe_items(realm: &Realm, item_refs: &[GameObjectRef]) -> Vec<String> {
    count_objects(realm, item_refs)
        .iter()
        .map(|(item, count)| {
            if *count > 1 {
                format!("{} {}", written_number(*count), item.plural_form())
            } else {
                item.indefinite_name()
            }
        })
        .collect()
}

pub fn describe_objects_from_room(
    realm: &Realm,
    object_refs: &[GameObjectRef],
    room_ref: GameObjectRef,
) -> Vec<String> {
    count_objects(realm, object_refs)
        .iter()
        .map(|(object, count)| {
            if *count > 1 {
                format!("{} {}", written_number(*count), object.plural_form())
            } else if let Some(portal) = object.as_portal() {
                portal.name_with_destination_from_room(room_ref)
            } else {
                object.indefinite_name()
            }
        })
        .collect()
}

pub fn describe_objects_with_definite_articles(
    realm: &Realm,
    object_refs: &[GameObjectRef],
) -> Vec<String> {
    count_objects(realm, object_refs)
        .iter()
        .map(|(object, count)| {
            if *count > 1 {
                format!("{} {}", written_number(*count), object.plural_form())
            } else {
                format!("the {}", object.name())
            }
        })
        .collect()
}

pub fn first_item_is_plural(realm: &Realm, item_refs: &[GameObjectRef]) -> bool {
    match item_refs.first().and_then(|item_ref| realm.item(*item_ref)) {
        Some(item) => {
            if item.has_flags(ItemFlags::ImpliedPlural) {
                true
            } else if item.has_flags(ItemFlags::AlwaysUseDefiniteArticle) {
                item_refs.len() > 1
            } else {
                item_refs
                    .iter()
                    .skip(1)
                    .filter_map(|item_ref| realm.item(*item_ref))
                    .any(|other| other.name() == item.name())
            }
        }
        None => false,
    }
}

pub fn format_columns<T>(items: Vec<T>) -> String
where
    T: Borrow<str>,
{
    let mut result = String::new();
    let len = items.len();
    let half_len = len / 2 + len % 2;
    for i in 0..half_len {
        let first = items[i].borrow();
        let second = if i < len - half_len {
            items[i + half_len].borrow()
        } else {
            ""
        };

        result.push_str(&format!("  {:30}  {}\n", first, second));
    }
    result
}

pub fn format_weight(weight: f32) -> String {
    format!("{}kg", weight.round())
}

pub fn highlight(string: &str) -> String {
    colorize(string, Color::White)
}

pub fn is_letter(character: char) -> bool {
    ('a'..='z').contains(&character) || ('A'..='Z').contains(&character)
}

pub fn is_vowel(character: char) -> bool {
    character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u'
}

pub fn join_fancy<T>(list: Vec<T>, separator: &str, last: &str) -> String
where
    T: Borrow<str>,
{
    let mut string = String::new();
    let len = list.len();
    for (i, item) in list.iter().enumerate() {
        string += item.borrow();
        match (i + 2).cmp(&len) {
            Ordering::Less => string += separator,
            Ordering::Equal => string += last,
            Ordering::Greater => {}
        }
    }
    string
}

pub fn join_sentence<T>(list: Vec<T>) -> String
where
    T: Borrow<str>,
{
    join_fancy(list, ", ", " and ")
}

pub fn plural_from_noun(noun: &str) -> String {
    if noun.ends_with('y') && !noun.chars().nth_back(1).map(is_vowel).unwrap_or(true) {
        format!("{}ies", substring(noun, 0, -1))
    } else if noun.ends_with('f') {
        format!("{}ves", substring(noun, 0, -1))
    } else if noun.ends_with("fe") {
        format!("{}ves", substring(noun, 0, -2))
    } else if noun.ends_with('s')
        || noun.ends_with('x')
        || noun.ends_with("sh")
        || noun.ends_with("ch")
    {
        format!("{}es", noun)
    } else if noun.ends_with("ese") {
        noun.to_owned()
    } else {
        format!("{}s", noun)
    }
}

pub fn process_highlights(string: &str) -> String {
    lazy_static! {
        static ref HIGHLIGHT_REGEX: Regex = Regex::new(r"\*([^*]+)\*").unwrap();
    }

    (*HIGHLIGHT_REGEX.replace_all(string, |captures: &Captures| {
        highlight(captures.get(1).unwrap().as_str())
    }))
    .to_owned()
}

pub fn split_lines(string: &str, max_line_len: usize) -> Vec<String> {
    let mut lines = Vec::new();
    let mut current_line = String::new();
    let mut current_line_len = 0;

    for mut word in string.split(' ') {
        while let Some(index) = word.find('\n') {
            let left = &word[0..index];
            if !left.is_empty() {
                if current_line_len + left.len() + 1 > max_line_len {
                    lines.push(current_line);
                    current_line = left.to_owned();
                    current_line_len = left.len();
                } else {
                    if !current_line.is_empty() {
                        current_line += " ";
                        current_line_len += 1;
                    }
                    current_line += left;
                    current_line_len += left.len();
                }
            }
            lines.push(current_line);
            current_line = String::new();
            word = &word[index + 1..];
        }
        if word.is_empty() {
            continue;
        }

        let word_len = word.len() - 4 * word.matches("\x1B[").count();
        if current_line_len + word_len + 1 > max_line_len {
            lines.push(current_line);
            current_line = word.to_owned();
            current_line_len = word_len;
        } else {
            if !current_line.is_empty() {
                current_line += " ";
                current_line_len += 1;
            }
            current_line += word;
            current_line_len += word_len;
        }
    }
    if !current_line.is_empty() {
        lines.push(current_line);
    }

    lines
}

fn substring(string: &str, start: i32, end: i32) -> &str {
    &string[(start as usize)..if end > 0 {
        (end - start) as usize
    } else {
        ((string.len() as i32) - end - start) as usize
    }]
}
<commit_msg>Display players before other characters<commit_after>use lazy_static::lazy_static;
use regex::{Captures, Regex};
use std::{borrow::Borrow, cmp::Ordering};

use crate::colors::Color;
use crate::game_object::{GameObject, GameObjectRef, GameObjectType};
use crate::number_utils::written_number;
use crate::objects::{ItemFlags, Realm};

const COLOR_MAP: [&str; 16] = [
    "37;1", "37", "30;1", "30", "31;1", "31", "33;1", "33", "32;1", "32", "36;1", "36", "34;1",
    "34", "35;1", "35",
];

pub fn capitalize(string: &str) -> String {
    let mut chars: Vec<char> = string.chars().collect();
    if let Some(c) = chars.get(0) {
        chars[0] = c.to_ascii_uppercase();
    }
    chars.into_iter().collect()
}

pub fn colorize(string: &str, color: Color) -> String {
    format!("\x1B[{}m{}\x1B[0m", COLOR_MAP[color as usize], string)
}

fn count_objects<'a>(
    realm: &'a Realm,
    object_refs: &[GameObjectRef],
) -> Vec<(&'a dyn GameObject, u16)> {
    let mut objects_with_counts = Vec::<(&dyn GameObject, u16)>::new();
    for object in object_refs
        .iter()
        .filter_map(|object_ref| realm.object(*object_ref))
    {
        if let Some(object_with_count) = objects_with_counts
            .iter_mut()
            .find(|(other, _)| other.name() == object.name())
        {
            object_with_count.1 += 1;
        } else {
            objects_with_counts.push((object, 1));
        }
    }

    objects_with_counts
}

fn count_and_sort_objects<'a>(
    realm: &'a Realm,
    object_refs: &[GameObjectRef],
) -> Vec<(&'a dyn GameObject, u16)> {
    let mut objects_with_counts = count_objects(realm, object_refs);

    // Players go before everything else, but after that we sort by count:
    objects_with_counts.sort_by(|(object1, count1), (object2, count2)| {
        if object1.object_type() == GameObjectType::Player {
            if object2.object_type() == GameObjectType::Player {
                count1.cmp(count2)
            } else {
                Ordering::Less
            }
        } else if object2.object_type() == GameObjectType::Player {
            Ordering::Greater
        } else {
            count1.cmp(count2)
        }
    });

    objects_with_counts
}

pub fn definite_article_from_noun(noun: String) -> &'static str {
    if noun.chars().next().map(is_vowel).unwrap_or(false) {
        "an"
    } else {
        "a"
    }
}

pub fn describe_items(realm: &Realm, item_refs: &[GameObjectRef]) -> Vec<String> {
    count_and_sort_objects(realm, item_refs)
        .iter()
        .map(|(item, count)| {
            if *count > 1 {
                format!("{} {}", written_number(*count), item.plural_form())
            } else {
                item.indefinite_name()
            }
        })
        .collect()
}

pub fn describe_objects_from_room(
    realm: &Realm,
    object_refs: &[GameObjectRef],
    room_ref: GameObjectRef,
) -> Vec<String> {
    count_and_sort_objects(realm, object_refs)
        .iter()
        .map(|(object, count)| {
            if *count > 1 {
                format!("{} {}", written_number(*count), object.plural_form())
            } else if let Some(portal) = object.as_portal() {
                portal.name_with_destination_from_room(room_ref)
            } else {
                object.indefinite_name()
            }
        })
        .collect()
}

pub fn describe_objects_with_definite_articles(
    realm: &Realm,
    object_refs: &[GameObjectRef],
) -> Vec<String> {
    count_and_sort_objects(realm, object_refs)
        .iter()
        .map(|(object, count)| {
            if *count > 1 {
                format!("{} {}", written_number(*count), object.plural_form())
            } else {
                format!("the {}", object.name())
            }
        })
        .collect()
}

pub fn first_item_is_plural(realm: &Realm, item_refs: &[GameObjectRef]) -> bool {
    match item_refs.first().and_then(|item_ref| realm.item(*item_ref)) {
        Some(item) => {
            if item.has_flags(ItemFlags::ImpliedPlural) {
                true
            } else if item.has_flags(ItemFlags::AlwaysUseDefiniteArticle) {
                item_refs.len() > 1
            } else {
                item_refs
                    .iter()
                    .skip(1)
                    .filter_map(|item_ref| realm.item(*item_ref))
                    .any(|other| other.name() == item.name())
            }
        }
        None => false,
    }
}

pub fn format_columns<T>(items: Vec<T>) -> String
where
    T: Borrow<str>,
{
    let mut result = String::new();
    let len = items.len();
    let half_len = len / 2 + len % 2;
    for i in 0..half_len {
        let first = items[i].borrow();
        let second = if i < len - half_len {
            items[i + half_len].borrow()
        } else {
            ""
        };

        result.push_str(&format!("  {:30}  {}\n", first, second));
    }
    result
}

pub fn format_weight(weight: f32) -> String {
    format!("{}kg", weight.round())
}

pub fn highlight(string: &str) -> String {
    colorize(string, Color::White)
}

pub fn is_letter(character: char) -> bool {
    ('a'..='z').contains(&character) || ('A'..='Z').contains(&character)
}

pub fn is_vowel(character: char) -> bool {
    character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u'
}

pub fn join_fancy<T>(list: Vec<T>, separator: &str, last: &str) -> String
where
    T: Borrow<str>,
{
    let mut string = String::new();
    let len = list.len();
    for (i, item) in list.iter().enumerate() {
        string += item.borrow();
        match (i + 2).cmp(&len) {
            Ordering::Less => string += separator,
            Ordering::Equal => string += last,
            Ordering::Greater => {}
        }
    }
    string
}

pub fn join_sentence<T>(list: Vec<T>) -> String
where
    T: Borrow<str>,
{
    join_fancy(list, ", ", " and ")
}

pub fn plural_from_noun(noun: &str) -> String {
    if noun.ends_with('y') && !noun.chars().nth_back(1).map(is_vowel).unwrap_or(true) {
        format!("{}ies", substring(noun, 0, -1))
    } else if noun.ends_with('f') {
        format!("{}ves", substring(noun, 0, -1))
    } else if noun.ends_with("fe") {
        format!("{}ves", substring(noun, 0, -2))
    } else if noun.ends_with('s')
        || noun.ends_with('x')
        || noun.ends_with("sh")
        || noun.ends_with("ch")
    {
        format!("{}es", noun)
    } else if noun.ends_with("ese") {
        noun.to_owned()
    } else {
        format!("{}s", noun)
    }
}

pub fn process_highlights(string: &str) -> String {
    lazy_static! {
        static ref HIGHLIGHT_REGEX: Regex = Regex::new(r"\*([^*]+)\*").unwrap();
    }

    (*HIGHLIGHT_REGEX.replace_all(string, |captures: &Captures| {
        highlight(captures.get(1).unwrap().as_str())
    }))
    .to_owned()
}

pub fn split_lines(string: &str, max_line_len: usize) -> Vec<String> {
    let mut lines = Vec::new();
    let mut current_line = String::new();
    let mut current_line_len = 0;

    for mut word in string.split(' ') {
        while let Some(index) = word.find('\n') {
            let left = &word[0..index];
            if !left.is_empty() {
                if current_line_len + left.len() + 1 > max_line_len {
                    lines.push(current_line);
                    current_line = left.to_owned();
                    current_line_len = left.len();
                } else {
                    if !current_line.is_empty() {
                        current_line += " ";
                        current_line_len += 1;
                    }
                    current_line += left;
                    current_line_len += left.len();
                }
            }
            lines.push(current_line);
            current_line = String::new();
            word = &word[index + 1..];
        }
        if word.is_empty() {
            continue;
        }

        let word_len = word.len() - 4 * word.matches("\x1B[").count();
        if current_line_len + word_len + 1 > max_line_len {
            lines.push(current_line);
            current_line = word.to_owned();
            current_line_len = word_len;
        } else {
            if !current_line.is_empty() {
                current_line += " ";
                current_line_len += 1;
            }
            current_line += word;
            current_line_len += word_len;
        }
    }
    if !current_line.is_empty() {
        lines.push(current_line);
    }

    lines
}

fn substring(string: &str, start: i32, end: i32) -> &str {
    &string[(start as usize)..if end > 0 {
        (end - start) as usize
    } else {
        ((string.len() as i32) - end - start) as usize
    }]
}
<|endoftext|>


<commit_before>//! X509 certificate parsing

use chrono::*;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use num::bigint::BigUint;
use std::fmt::Write as FmtWrite;

use timmy::asn1::*;
use timmy::tup::*;

#[derive(Debug)]
pub enum X509Error {
    InvalidType(String),
    InvalidSequence(String),
    InvalidTimestamp(String),
    InvalidPublicKey(String),
    InvalidASN1(ASN1Error),
}

pub type X509Result<T> = Result<T, X509Error>;

fn x509_oid_to_str(oid: &ASN1Type) -> String {
    let ret = match oid {
        &ASN1Type::Object(Tup::T4(2, 5, 4, 6)) => "C",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 8)) => "ST",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 7)) => "L",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 10)) => "O",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 3)) => "CN",
        _ => "unknown"
    };

    ret.to_string()
}

pub fn x509_subject_to_string(subject: &ASN1Type) -> X509Result<String> {
    let mut result_string = "".to_string();

    match subject {
        &ASN1Type::Sequence(ref parts) => {
            for ent in &*parts {
                if let &ASN1Type::Set(ref seq) = ent {
                    //println!("{:?}", seq[0]);

                    let ref seq0 = seq[0];
                    if let ASN1Type::Sequence(ref obj_str) = *seq0 {

                        let oid_str = x509_oid_to_str(&obj_str[0]);
                        if let Some(value) = asn1_to_raw_string(&obj_str[1]) {
                            write!(&mut result_string, "{}={}/", oid_str, value).unwrap();
                        }
                    }
                }
            }
        }
        _ => {
            return Err(X509Error::InvalidType("failed to construct subject".to_string()));
        }
    }

    Ok(result_string)
}

pub fn x509_validity_to_datetime(validity: &ASN1Type) -> X509Result<(DateTime<UTC>, DateTime<UTC>)> {
    if let &ASN1Type::Sequence(ref two_dates) = validity {
        if two_dates.len() != 2 {
            return Err(X509Error::InvalidSequence(
                "TBSCertificate.validity should contain 2 items".to_string()));
        }

        let ref first = two_dates[0];
        let ref last = two_dates[1];

        match (first, last) {
            (&ASN1Type::UTCTime(ref dt1_str), &ASN1Type::UTCTime(ref dt2_str)) => {
                let dt1 = UTC.datetime_from_str(&dt1_str, "%y%m%d%H%M%SZ");
                let dt2 = UTC.datetime_from_str(&dt2_str, "%y%m%d%H%M%SZ");

                match (dt1, dt2) {
                    (Ok(a), Ok(b)) => Ok((a, b)),
                    _ => Err(X509Error::InvalidTimestamp(
                        format!("TBSCertificate.validity are on the wrong format: {:?} {:?}",
                                dt1_str, dt2_str)))
                }
            }
            _ => { Err(X509Error::InvalidSequence(
                format!("TBSCertificate.validity has invalid types: {:?} {:?}",
                        first, last))) }
        }

    } else {
        Err(X509Error::InvalidType(
            "TBSCertificate.validity should be a sequence".to_string()))
    }
}

#[derive(Debug)]
pub enum AlgorithmIdentifier {
    Unsupported,
    RSA
}

fn x509_parse_algorithm_identifier(ai: &ASN1Type) -> X509Result<AlgorithmIdentifier> {
    match ai {
        &ASN1Type::Sequence(ref seq) => {
            if seq.len() < 2 {
                return Err(X509Error::InvalidSequence(
                    "AlgorithmIdentifier should contain 2 items".to_string()));
            }

            let ref algo = seq[0];

            Ok(match *algo {
                ASN1Type::Object(Tup::T7(1, 2, 840, 113549, 1, 1, 1)) => AlgorithmIdentifier::RSA,
                _ => AlgorithmIdentifier::Unsupported
            })
        }
        _ => Err(X509Error::InvalidType(
            "AlgorithmIdentifier should be a sequence".to_string()))
    }
}

#[derive(Debug)]
pub enum PublicKey {
    RSA(BigUint, BigUint) // n, e
}

pub fn x509_parse_public_key_info(info: &ASN1Type) -> X509Result<PublicKey> {
    if let &ASN1Type::Sequence(ref algo_pubkey) = info {
        let ref algo_seq = algo_pubkey[0];
        let ref pubkey = algo_pubkey[1];

        let ai = try!(x509_parse_algorithm_identifier(algo_seq));

        if let &ASN1Type::BitString(ref bitstring) = pubkey {
            // TODO (bjorn): Fix this parsing, not super reliable.
            let mut derparser = DerParser::new(&bitstring[1..].iter().cloned().collect());
            let bs_tree = derparser.parse_entry();

            //println!("bitstring: {:?}", bs_tree)
            if let Ok(ASN1Type::Sequence(ref pk_seq)) = bs_tree {
                match ai {
                    AlgorithmIdentifier::RSA => {
                        let rsa_n = asn1_to_raw_integer(&pk_seq[0]).expect("TODO");
                        let rsa_e = asn1_to_raw_integer(&pk_seq[1]).expect("TODO");

                        Ok(PublicKey::RSA(rsa_n.to_biguint().expect("TODO"),
                                          rsa_e.to_biguint().expect("TODO")))
                    },
                    _ => Err(X509Error::InvalidPublicKey(
                        "Only RSA is supported".to_string()))
                }
            } else {
                Err(X509Error::InvalidType(
                    "public key material should be a sequence".to_string()))
            }
        } else {
            Err(X509Error::InvalidType(
                "SubjectPublicKeyInfo.subjectPublicKey should be a BitString".to_string()))
        }
    } else {
        Err(X509Error::InvalidType(
            "SubjectPublicKeyInfo should be a sequence".to_string()))
    }
}

#[derive(Debug)]
pub struct ParsedX509Certificate {
    pub key: PublicKey,
    pub validity: (DateTime<UTC>, DateTime<UTC>),
    pub subject: String,
}

pub struct X509Certificate {
    pub buf: Vec<u8>,
}

impl X509Certificate {
    pub fn new(der: Vec<u8>) -> X509Certificate {
        X509Certificate {
            buf: der,
        }
    }

    pub fn sha1_fingerprint(&self) -> X509Result<Vec<u8>> {
        let mut hash_sha1 = Sha1::new();
        hash_sha1.input(&self.buf);
        let mut hash_result: [u8; 20] = [0; 20];
        hash_sha1.result(&mut hash_result[0..20]);
        Ok(hash_result.iter().cloned().collect())
    }

    pub fn parse(&self) -> X509Result<ParsedX509Certificate> {
        let mut derparser = DerParser::new(&self.buf);

        let asn1tree = derparser.parse_entry();
        if asn1tree.is_err() {
            return Err(X509Error::InvalidASN1(asn1tree.unwrap_err()));
        }
        let tree = asn1tree.unwrap();

        // Slice patterns are experimental right now, so lets do this
        // awkwardly.
        match tree {
            ASN1Type::Sequence(body) => {
                match body[0] {
                    ASN1Type::Sequence(ref part0) => {
                        //for ent in &*part0 {
                        //    println!("seq {:?}", ent);
                        //}

                        let ref tbs = *part0;

                        //let ref version = tbs[0];
                        //let ref serialNumber = tbs[1];
                        //let ref signature = tbs[2];
                        //let ref issuer = tbs[3];
                        let ref validity = tbs[4];
                        let ref subject = tbs[5];
                        let ref subject_public_key_info = tbs[6];

                        let field_subject = try!(x509_subject_to_string(subject));
                        let field_validity = try!(x509_validity_to_datetime(validity));
                        let field_public_key = try!(x509_parse_public_key_info(subject_public_key_info));

                        let fields = ParsedX509Certificate {
                            key: field_public_key,
                            validity: field_validity,
                            subject: field_subject,
                        };

                        Ok(fields)
                    }
                    _ => {
                        Err(X509Error::InvalidType(
                            "certificate should be a sequence".to_string()))
                    }
                }
            }
            _ => {
                Err(X509Error::InvalidType(
                    "certificate should be a sequence".to_string()))
            }
        }
    }
}
<commit_msg>Add OID for organizational unit.<commit_after>//! X509 certificate parsing

use chrono::*;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use num::bigint::BigUint;
use std::fmt::Write as FmtWrite;

use timmy::asn1::*;
use timmy::tup::*;

#[derive(Debug)]
pub enum X509Error {
    InvalidType(String),
    InvalidSequence(String),
    InvalidTimestamp(String),
    InvalidPublicKey(String),
    InvalidASN1(ASN1Error),
}

pub type X509Result<T> = Result<T, X509Error>;

fn x509_oid_to_str(oid: &ASN1Type) -> String {
    let ret = match oid {
        &ASN1Type::Object(Tup::T4(2, 5, 4, 6)) => "C",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 8)) => "ST",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 7)) => "L",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 10)) => "O",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 3)) => "CN",
        &ASN1Type::Object(Tup::T4(2, 5, 4, 11)) => "OU",
        &ASN1Type::Object(ref t) => {
            println!("unknown({:?})", t);
            "unknown"
        },
        _ => "unknown"
    };

    ret.to_string()
}

pub fn x509_subject_to_string(subject: &ASN1Type) -> X509Result<String> {
    let mut result_string = "".to_string();

    match subject {
        &ASN1Type::Sequence(ref parts) => {
            for ent in &*parts {
                if let &ASN1Type::Set(ref seq) = ent {
                    //println!("{:?}", seq[0]);

                    let ref seq0 = seq[0];
                    if let ASN1Type::Sequence(ref obj_str) = *seq0 {

                        let oid_str = x509_oid_to_str(&obj_str[0]);
                        if let Some(value) = asn1_to_raw_string(&obj_str[1]) {
                            write!(&mut result_string, "{}={}/", oid_str, value).unwrap();
                        }
                    }
                }
            }
        }
        _ => {
            return Err(X509Error::InvalidType("failed to construct subject".to_string()));
        }
    }

    Ok(result_string)
}

pub fn x509_validity_to_datetime(validity: &ASN1Type) -> X509Result<(DateTime<UTC>, DateTime<UTC>)> {
    if let &ASN1Type::Sequence(ref two_dates) = validity {
        if two_dates.len() != 2 {
            return Err(X509Error::InvalidSequence(
                "TBSCertificate.validity should contain 2 items".to_string()));
        }

        let ref first = two_dates[0];
        let ref last = two_dates[1];

        match (first, last) {
            (&ASN1Type::UTCTime(ref dt1_str), &ASN1Type::UTCTime(ref dt2_str)) => {
                let dt1 = UTC.datetime_from_str(&dt1_str, "%y%m%d%H%M%SZ");
                let dt2 = UTC.datetime_from_str(&dt2_str, "%y%m%d%H%M%SZ");

                match (dt1, dt2) {
                    (Ok(a), Ok(b)) => Ok((a, b)),
                    _ => Err(X509Error::InvalidTimestamp(
                        format!("TBSCertificate.validity are on the wrong format: {:?} {:?}",
                                dt1_str, dt2_str)))
                }
            }
            _ => { Err(X509Error::InvalidSequence(
                format!("TBSCertificate.validity has invalid types: {:?} {:?}",
                        first, last))) }
        }

    } else {
        Err(X509Error::InvalidType(
            "TBSCertificate.validity should be a sequence".to_string()))
    }
}

#[derive(Debug)]
pub enum AlgorithmIdentifier {
    Unsupported,
    RSA
}

fn x509_parse_algorithm_identifier(ai: &ASN1Type) -> X509Result<AlgorithmIdentifier> {
    match ai {
        &ASN1Type::Sequence(ref seq) => {
            if seq.len() < 2 {
                return Err(X509Error::InvalidSequence(
                    "AlgorithmIdentifier should contain 2 items".to_string()));
            }

            let ref algo = seq[0];

            Ok(match *algo {
                ASN1Type::Object(Tup::T7(1, 2, 840, 113549, 1, 1, 1)) => AlgorithmIdentifier::RSA,
                _ => AlgorithmIdentifier::Unsupported
            })
        }
        _ => Err(X509Error::InvalidType(
            "AlgorithmIdentifier should be a sequence".to_string()))
    }
}

#[derive(Debug)]
pub enum PublicKey {
    RSA(BigUint, BigUint) // n, e
}

pub fn x509_parse_public_key_info(info: &ASN1Type) -> X509Result<PublicKey> {
    if let &ASN1Type::Sequence(ref algo_pubkey) = info {
        let ref algo_seq = algo_pubkey[0];
        let ref pubkey = algo_pubkey[1];

        let ai = try!(x509_parse_algorithm_identifier(algo_seq));

        if let &ASN1Type::BitString(ref bitstring) = pubkey {
            // TODO (bjorn): Fix this parsing, not super reliable.
            let mut derparser = DerParser::new(&bitstring[1..].iter().cloned().collect());
            let bs_tree = derparser.parse_entry();

            //println!("bitstring: {:?}", bs_tree)
            if let Ok(ASN1Type::Sequence(ref pk_seq)) = bs_tree {
                match ai {
                    AlgorithmIdentifier::RSA => {
                        let rsa_n = asn1_to_raw_integer(&pk_seq[0]).expect("TODO");
                        let rsa_e = asn1_to_raw_integer(&pk_seq[1]).expect("TODO");

                        Ok(PublicKey::RSA(rsa_n.to_biguint().expect("TODO"),
                                          rsa_e.to_biguint().expect("TODO")))
                    },
                    _ => Err(X509Error::InvalidPublicKey(
                        "Only RSA is supported".to_string()))
                }
            } else {
                Err(X509Error::InvalidType(
                    "public key material should be a sequence".to_string()))
            }
        } else {
            Err(X509Error::InvalidType(
                "SubjectPublicKeyInfo.subjectPublicKey should be a BitString".to_string()))
        }
    } else {
        Err(X509Error::InvalidType(
            "SubjectPublicKeyInfo should be a sequence".to_string()))
    }
}

#[derive(Debug)]
pub struct ParsedX509Certificate {
    pub key: PublicKey,
    pub validity: (DateTime<UTC>, DateTime<UTC>),
    pub subject: String,
}

pub struct X509Certificate {
    pub buf: Vec<u8>,
}

impl X509Certificate {
    pub fn new(der: Vec<u8>) -> X509Certificate {
        X509Certificate {
            buf: der,
        }
    }

    pub fn sha1_fingerprint(&self) -> X509Result<Vec<u8>> {
        let mut hash_sha1 = Sha1::new();
        hash_sha1.input(&self.buf);
        let mut hash_result: [u8; 20] = [0; 20];
        hash_sha1.result(&mut hash_result[0..20]);
        Ok(hash_result.iter().cloned().collect())
    }

    pub fn parse(&self) -> X509Result<ParsedX509Certificate> {
        let mut derparser = DerParser::new(&self.buf);

        let asn1tree = derparser.parse_entry();
        if asn1tree.is_err() {
            return Err(X509Error::InvalidASN1(asn1tree.unwrap_err()));
        }
        let tree = asn1tree.unwrap();

        // Slice patterns are experimental right now, so lets do this
        // awkwardly.
        match tree {
            ASN1Type::Sequence(body) => {
                match body[0] {
                    ASN1Type::Sequence(ref part0) => {
                        //for ent in &*part0 {
                        //    println!("seq {:?}", ent);
                        //}

                        let ref tbs = *part0;

                        //let ref version = tbs[0];
                        //let ref serialNumber = tbs[1];
                        //let ref signature = tbs[2];
                        //let ref issuer = tbs[3];
                        let ref validity = tbs[4];
                        let ref subject = tbs[5];
                        let ref subject_public_key_info = tbs[6];

                        let field_subject = try!(x509_subject_to_string(subject));
                        let field_validity = try!(x509_validity_to_datetime(validity));
                        let field_public_key = try!(x509_parse_public_key_info(subject_public_key_info));

                        let fields = ParsedX509Certificate {
                            key: field_public_key,
                            validity: field_validity,
                            subject: field_subject,
                        };

                        Ok(fields)
                    }
                    _ => {
                        Err(X509Error::InvalidType(
                            "certificate should be a sequence".to_string()))
                    }
                }
            }
            _ => {
                Err(X509Error::InvalidType(
                    "certificate should be a sequence".to_string()))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
	_buffer: &'a B,
	offset: usize,
	size: usize,
}

impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
	fn range(&self) -> ::std::ops::Range<usize> {
		self.offset..self.offset+self.size
	}
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		check_limits(memory_type.limits())?;

		if let Some(maximum_pages) = memory_type.limits().maximum() {
			if maximum_pages > LINEAR_MEMORY_MAX_PAGES {
				return Err(Error::Memory(format!("memory size must be at most 65536 pages")));
			}
		}

		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::new()), // TODO: with_capacity
			maximum_size: memory_type.limits().maximum()
				.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
				.unwrap_or(u32::MAX),
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
		}
		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let buffer = self.buffer.read();
		let region = self.checked_region(&buffer, offset as usize, size)?;

		Ok(buffer[region.range()].to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let mut buffer = self.buffer.write();
		let range = self.checked_region(&buffer, offset as usize, value.len())?.range();

		buffer[range].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
			None => Ok(u32::MAX),
			Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
			Some(new_size) => {
				buffer.extend(vec![0; (new_size - old_size) as usize]);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}

	fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
		where B: ::std::ops::Deref<Target=Vec<u8>>
	{
		let end = offset.checked_add(size)
			.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;

		if end > buffer.len() {
			return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
		}

		Ok(CheckedRegion {
			_buffer: buffer,
			offset: offset,
			size: size,
		})
	}

	pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
		let buffer = self.buffer.write();

		let read_region = self.checked_region(&buffer, src_offset, len)?;
		let write_region = self.checked_region(&buffer, dst_offset, len)?;

		unsafe { ::std::ptr::copy(
			buffer[read_region.range()].as_ptr(),
			buffer[write_region.range()].as_ptr() as *mut _,
			len,
		)}

		Ok(())
	}
}
<commit_msg>fix warnings<commit_after>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
	buffer: &'a B,
	offset: usize,
	size: usize,
}

impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
	fn range(&self) -> ::std::ops::Range<usize> {
		self.offset..self.offset+self.size
	}

	fn slice(&self) -> &[u8] {
		&*self.buffer
	}
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		check_limits(memory_type.limits())?;

		if let Some(maximum_pages) = memory_type.limits().maximum() {
			if maximum_pages > LINEAR_MEMORY_MAX_PAGES {
				return Err(Error::Memory(format!("memory size must be at most 65536 pages")));
			}
		}

		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::new()), // TODO: with_capacity
			maximum_size: memory_type.limits().maximum()
				.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
				.unwrap_or(u32::MAX),
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
		}
		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let buffer = self.buffer.read();
		let region = self.checked_region(&buffer, offset as usize, size)?;

		Ok(region.slice().to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let mut buffer = self.buffer.write();
		let range = self.checked_region(&buffer, offset as usize, value.len())?.range();

		buffer[range].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
			None => Ok(u32::MAX),
			Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
			Some(new_size) => {
				buffer.extend(vec![0; (new_size - old_size) as usize]);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}

	fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
		where B: ::std::ops::Deref<Target=Vec<u8>>
	{
		let end = offset.checked_add(size)
			.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;

		if end > buffer.len() {
			return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
		}

		Ok(CheckedRegion {
			buffer: buffer,
			offset: offset,
			size: size,
		})
	}

	/// Copy memory region
	pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
		let buffer = self.buffer.write();

		let read_region = self.checked_region(&buffer, src_offset, len)?;
		let write_region = self.checked_region(&buffer, dst_offset, len)?;

		unsafe { ::std::ptr::copy(
			buffer[read_region.range()].as_ptr(),
			buffer[write_region.range()].as_ptr() as *mut _,
			len,
		)}

		Ok(())
	}
}
<|endoftext|>


<commit_before>pub fn remove_mean_offset(signal: &[f32]) -> Vec<f32> {
    let mean = signal.iter().sum::<f32>()/signal.len() as f32;
    signal.iter().map(|x| x - mean).collect()
}

pub fn correlation(signal: &[f32]) -> Vec<f32> {
    (0..signal.len()).map(|offset| {
        signal.iter().take(signal.len() - offset)
            .zip(signal.iter().skip(offset))
            .map(|(sig_i, sig_j)| sig_i * sig_j)
            .sum()
    }).collect()
}

pub fn find_fundamental_frequency_correlation(signal: &[f32], sample_rate: f32) -> Option<f32> {
    let normalized_signal = remove_mean_offset(signal);

    if normalized_signal.iter().all(|&x| x.abs() < 0.05) {
        // silence
        return None;
    }

    let correlation = correlation(&normalized_signal);

    let first_peak_end = match correlation.iter().position(|&c| c < 0.0) {
        Some(p) => p,
        None => {
            // musical signals will drop below 0 at some point
            return None
        }
    };

    let peak = correlation.iter()
        .enumerate()
        .skip(first_peak_end)
        .fold((first_peak_end, 0.0), |(xi, xmag), (yi, &ymag)| if ymag > xmag { (yi, ymag) } else { (xi, xmag) });

    let (peak_index, _) = peak;

    let refined_peak_index = refine_fundamentals(&correlation, peak_index as f32 - 0.5, peak_index as f32 + 0.5);

    if is_noise(&correlation, refined_peak_index) {
        None
    }
    else {
        Some(sample_rate / refined_peak_index)
    }
}

fn refine_fundamentals(correlation: &[f32], low_bound: f32, high_bound: f32) -> f32 {
    let data_points = 2 * correlation.len() / high_bound.ceil() as usize;
    let range = high_bound - low_bound;
    let midpoint = (low_bound + high_bound) / 2.0;

    if (range * data_points as f32) < 1.0 {
        midpoint
    }
    else {
        let low_guess = score_guess(correlation, low_bound, data_points);
        let high_guess = score_guess(correlation, high_bound, data_points);

        if high_guess > low_guess {
            refine_fundamentals(correlation, midpoint, high_bound)
        }
        else {
            refine_fundamentals(correlation, low_bound, midpoint)
        }
    }
}

fn is_noise(correlation: &[f32], fundamental: f32) -> bool {
    let value_at_point = interpolate(correlation, fundamental);
    let score_data_points = 2 * correlation.len() / fundamental.ceil() as usize;
    let score = score_guess(correlation, fundamental, score_data_points);

    value_at_point > 2.0*score
}

fn score_guess(correlation: &[f32], period: f32, data_points: usize) -> f32 {
    (1..data_points).map(|i| {
        let expected_sign = if i % 2 == 0 { 1.0 } else { -1.0 };
        let x = i as f32 * period / 2.0;
        let weight = 0.5 * i as f32;
        expected_sign * weight * interpolate(correlation, x)
    }).sum()
}

fn interpolate(correlation: &[f32], x: f32) -> f32 {
    if x < 0.0 {
        correlation[0]
    }
    else if x >= correlation.len() as f32 {
        correlation[correlation.len()-1]
    }
    else {
        let x0 = x.floor();
        let y0 = correlation[x0 as usize];
        let x1 = x.ceil();
        let y1 = correlation[x1 as usize];

        if x0 as usize == x1 as usize {
            y0
        }
        else {
            (y0*(x1-x) + y1*(x-x0)) / (x1-x0)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f32::consts::PI;

    const SAMPLE_RATE: f32 = 44100.0;
    const FRAMES: usize = 512;

    fn frequency_resolution() -> f32 {
        SAMPLE_RATE / 2.0 / FRAMES as f32
    }

    fn sin_arg(f: f32, t: f32, phase: f32) -> f32 {
        2.0 as f32 * PI * f * t + phase
    }

    fn sample_sinusoud(amplitude: f32, frequency: f32, phase: f32) -> Vec<f32> {
        (0..FRAMES)
            .map(|x| {
                let t = x as f32 / SAMPLE_RATE;
                sin_arg(frequency, t, phase).sin() * amplitude
            }).collect()
    }

    #[test]
    fn correlation_on_sine_wave() {
        let frequency = 440.0 as f32; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");
        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn correlation_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples: Vec<f32> = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();

        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn interpolate_half_way() {
        assert_eq!(0.5, interpolate(&vec!(0.0, 1.0), 0.5))
    }
}

pub fn hz_to_midi_number(hz: f32) -> f32 {
    69.0 + 12.0 * (hz / 440.0).log2()
}

pub fn hz_to_cents_error(hz: f32) -> f32 {
    let midi_number = hz_to_midi_number(hz);
    let cents = (midi_number * 100.0).round() % 100.0;
    if cents >= 50.0 {
        cents - 100.0
    }
    else {
        cents
    }
}

pub fn hz_to_pitch(hz: f32) -> String {
    let pitch_names = [
        "C",
        "C♯",
        "D",
        "E♭",
        "E",
        "F",
        "F♯",
        "G",
        "G♯",
        "A",
        "B♭",
        "B"
    ];

    let midi_number = hz_to_midi_number(hz);
    //midi_number of 0 is C-1.

    let rounded_pitch = midi_number.round() as i32;
    let name = pitch_names[rounded_pitch as usize % pitch_names.len()];
    let octave = rounded_pitch / pitch_names.len() as i32 - 1; //0 is C-1
    if octave < 0 {
        return "< C 1".to_string();
    }

    format!("{: <2}{}", name, octave)
}

#[test]
fn a4_is_correct() {
    assert_eq!(hz_to_pitch(440.0), "A 4");
}

#[test]
fn a2_is_correct() {
    assert_eq!(hz_to_pitch(110.0), "A 2");
}

#[test]
fn c4_is_correct() {
    assert_eq!(hz_to_pitch(261.63), "C 4");
}

#[test]
fn f5_is_correct() {
    assert_eq!(hz_to_pitch(698.46), "F 5");
}

pub fn align_to_rising_edge(samples: &[f32]) -> Vec<f32> {
    remove_mean_offset(samples)
        .iter()
        .skip_while(|x| !x.is_sign_negative())
        .skip_while(|x| x.is_sign_negative())
        .cloned()
        .collect()
}
<commit_msg>Fixed potential index out of bounds error<commit_after>pub fn remove_mean_offset(signal: &[f32]) -> Vec<f32> {
    let mean = signal.iter().sum::<f32>()/signal.len() as f32;
    signal.iter().map(|x| x - mean).collect()
}

pub fn correlation(signal: &[f32]) -> Vec<f32> {
    (0..signal.len()).map(|offset| {
        signal.iter().take(signal.len() - offset)
            .zip(signal.iter().skip(offset))
            .map(|(sig_i, sig_j)| sig_i * sig_j)
            .sum()
    }).collect()
}

pub fn find_fundamental_frequency_correlation(signal: &[f32], sample_rate: f32) -> Option<f32> {
    let normalized_signal = remove_mean_offset(signal);

    if normalized_signal.iter().all(|&x| x.abs() < 0.05) {
        // silence
        return None;
    }

    let correlation = correlation(&normalized_signal);

    let first_peak_end = match correlation.iter().position(|&c| c < 0.0) {
        Some(p) => p,
        None => {
            // musical signals will drop below 0 at some point
            return None
        }
    };

    let peak = correlation.iter()
        .enumerate()
        .skip(first_peak_end)
        .fold((first_peak_end, 0.0), |(xi, xmag), (yi, &ymag)| if ymag > xmag { (yi, ymag) } else { (xi, xmag) });

    let (peak_index, _) = peak;

    let refined_peak_index = refine_fundamentals(&correlation, peak_index as f32 - 0.5, peak_index as f32 + 0.5);

    if is_noise(&correlation, refined_peak_index) {
        None
    }
    else {
        Some(sample_rate / refined_peak_index)
    }
}

fn refine_fundamentals(correlation: &[f32], low_bound: f32, high_bound: f32) -> f32 {
    let data_points = 2 * correlation.len() / high_bound.ceil() as usize;
    let range = high_bound - low_bound;
    let midpoint = (low_bound + high_bound) / 2.0;

    if (range * data_points as f32) < 1.0 {
        midpoint
    }
    else {
        let low_guess = score_guess(correlation, low_bound, data_points);
        let high_guess = score_guess(correlation, high_bound, data_points);

        if high_guess > low_guess {
            refine_fundamentals(correlation, midpoint, high_bound)
        }
        else {
            refine_fundamentals(correlation, low_bound, midpoint)
        }
    }
}

fn is_noise(correlation: &[f32], fundamental: f32) -> bool {
    let value_at_point = interpolate(correlation, fundamental);
    let score_data_points = 2 * correlation.len() / fundamental.ceil() as usize;
    let score = score_guess(correlation, fundamental, score_data_points);

    value_at_point > 2.0*score
}

fn score_guess(correlation: &[f32], period: f32, data_points: usize) -> f32 {
    (1..data_points).map(|i| {
        let expected_sign = if i % 2 == 0 { 1.0 } else { -1.0 };
        let x = i as f32 * period / 2.0;
        let weight = 0.5 * i as f32;
        expected_sign * weight * interpolate(correlation, x)
    }).sum()
}

fn interpolate(correlation: &[f32], x: f32) -> f32 {
    if x.floor() < 0.0 {
        correlation[0]
    }
    else if x.ceil() >= correlation.len() as f32 {
        correlation[correlation.len()-1]
    }
    else {
        let x0 = x.floor();
        let y0 = correlation[x0 as usize];
        let x1 = x.ceil();
        let y1 = correlation[x1 as usize];

        if x0 as usize == x1 as usize {
            y0
        }
        else {
            (y0*(x1-x) + y1*(x-x0)) / (x1-x0)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f32::consts::PI;

    const SAMPLE_RATE: f32 = 44100.0;
    const FRAMES: usize = 512;

    fn frequency_resolution() -> f32 {
        SAMPLE_RATE / 2.0 / FRAMES as f32
    }

    fn sin_arg(f: f32, t: f32, phase: f32) -> f32 {
        2.0 as f32 * PI * f * t + phase
    }

    fn sample_sinusoud(amplitude: f32, frequency: f32, phase: f32) -> Vec<f32> {
        (0..FRAMES)
            .map(|x| {
                let t = x as f32 / SAMPLE_RATE;
                sin_arg(frequency, t, phase).sin() * amplitude
            }).collect()
    }

    #[test]
    fn correlation_on_sine_wave() {
        let frequency = 440.0 as f32; //concert A

        let samples = sample_sinusoud(1.0, frequency, 0.0);
        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");
        assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental);
    }

    #[test]
    fn correlation_on_two_sine_waves() {
        //Unfortunately, real signals won't be this neat
        let samples1a = sample_sinusoud(2.0, 440.0, 0.0);
        let samples2a = sample_sinusoud(1.0, 880.0, 0.0);
        let expected_fundamental = 440.0;

        let samples: Vec<f32> = samples1a.iter().zip(samples2a.iter())
            .map(|(a, b)| a+b)
            .collect();

        let fundamental = find_fundamental_frequency_correlation(&samples, SAMPLE_RATE).expect("Find fundamental returned None");

        assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental);
    }

    #[test]
    fn interpolate_half_way() {
        assert_eq!(0.5, interpolate(&vec!(0.0, 1.0), 0.5))
    }
}

pub fn hz_to_midi_number(hz: f32) -> f32 {
    69.0 + 12.0 * (hz / 440.0).log2()
}

pub fn hz_to_cents_error(hz: f32) -> f32 {
    let midi_number = hz_to_midi_number(hz);
    let cents = (midi_number * 100.0).round() % 100.0;
    if cents >= 50.0 {
        cents - 100.0
    }
    else {
        cents
    }
}

pub fn hz_to_pitch(hz: f32) -> String {
    let pitch_names = [
        "C",
        "C♯",
        "D",
        "E♭",
        "E",
        "F",
        "F♯",
        "G",
        "G♯",
        "A",
        "B♭",
        "B"
    ];

    let midi_number = hz_to_midi_number(hz);
    //midi_number of 0 is C-1.

    let rounded_pitch = midi_number.round() as i32;
    let name = pitch_names[rounded_pitch as usize % pitch_names.len()];
    let octave = rounded_pitch / pitch_names.len() as i32 - 1; //0 is C-1
    if octave < 0 {
        return "< C 1".to_string();
    }

    format!("{: <2}{}", name, octave)
}

#[test]
fn a4_is_correct() {
    assert_eq!(hz_to_pitch(440.0), "A 4");
}

#[test]
fn a2_is_correct() {
    assert_eq!(hz_to_pitch(110.0), "A 2");
}

#[test]
fn c4_is_correct() {
    assert_eq!(hz_to_pitch(261.63), "C 4");
}

#[test]
fn f5_is_correct() {
    assert_eq!(hz_to_pitch(698.46), "F 5");
}

pub fn align_to_rising_edge(samples: &[f32]) -> Vec<f32> {
    remove_mean_offset(samples)
        .iter()
        .skip_while(|x| !x.is_sign_negative())
        .skip_while(|x| x.is_sign_negative())
        .cloned()
        .collect()
}
<|endoftext|>


<commit_before>//! Logging facilities

use std::path::Path;

use log::LevelFilter;
use log4rs::{
    append::console::{ConsoleAppender, Target},
    config::{Appender, Config, Logger, Root},
    encode::pattern::PatternEncoder,
};

use crate::config::LogConfig;

/// Initialize logger ([log4rs](https://crates.io/crates/log4rs)) from yaml configuration file
pub fn init_with_file<P>(path: P)
where
    P: AsRef<Path>,
{
    log4rs::init_file(path, Default::default()).expect("init logging with file");
}

/// Initialize logger with default configuration
pub fn init_with_config(bin_name: &str, config: &LogConfig) {
    let debug_level = config.level;
    let without_time = config.format.without_time;

    let mut pattern = String::new();
    if !without_time {
        pattern += "{d} ";
    }
    pattern += "{h({l}):<5} ";
    if debug_level >= 1 {
        pattern += "[{P}:{I}] [{M}] ";
    }
    pattern += "{m}{n}";

    let logging_builder = Config::builder().appender(
        Appender::builder().build(
            "console",
            Box::new(
                ConsoleAppender::builder()
                    .encoder(Box::new(PatternEncoder::new(&pattern)))
                    .target(Target::Stderr)
                    .build(),
            ),
        ),
    );

    let config = match debug_level {
        0 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Info))
            .logger(Logger::builder().build("shadowsocks_rust", LevelFilter::Info))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Info))
            .logger(Logger::builder().build("shadowsocks_service", LevelFilter::Info))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        1 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Debug))
            .logger(Logger::builder().build("shadowsocks_rust", LevelFilter::Debug))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Debug))
            .logger(Logger::builder().build("shadowsocks_service", LevelFilter::Debug))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        2 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks_rust", LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks_service", LevelFilter::Trace))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        3 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks_rust", LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks_service", LevelFilter::Trace))
            .build(Root::builder().appender("console").build(LevelFilter::Debug)),
        _ => logging_builder.build(Root::builder().appender("console").build(LevelFilter::Trace)),
    }
    .expect("logging");

    log4rs::init_config(config).expect("logging");
}

/// Init a default logger
pub fn init_with_default(bin_name: &str) {
    init_with_config(bin_name, &LogConfig::default());
}
<commit_msg>optimize logging code<commit_after>//! Logging facilities

use std::path::Path;

use log::LevelFilter;
use log4rs::{
    append::console::{ConsoleAppender, Target},
    config::{Appender, Config, Logger, Root},
    encode::pattern::PatternEncoder,
};

use crate::config::LogConfig;

/// Initialize logger ([log4rs](https://crates.io/crates/log4rs)) from yaml configuration file
pub fn init_with_file<P>(path: P)
where
    P: AsRef<Path>,
{
    log4rs::init_file(path, Default::default()).expect("init logging with file");
}

/// Initialize logger with default configuration
pub fn init_with_config(bin_name: &str, config: &LogConfig) {
    let debug_level = config.level;
    let without_time = config.format.without_time;

    let mut pattern = String::new();
    if !without_time {
        pattern += "{d} ";
    }
    pattern += "{h({l}):<5} ";
    if debug_level >= 1 {
        pattern += "[{P}:{I}] [{M}] ";
    }
    pattern += "{m}{n}";

    let logging_builder = Config::builder().appender(
        Appender::builder().build(
            "console",
            Box::new(
                ConsoleAppender::builder()
                    .encoder(Box::new(PatternEncoder::new(&pattern)))
                    .target(Target::Stderr)
                    .build(),
            ),
        ),
    );

    let (l1, l2) = match debug_level {
        0 => (LevelFilter::Info, LevelFilter::Off),
        1 => (LevelFilter::Debug, LevelFilter::Off),
        2 => (LevelFilter::Trace, LevelFilter::Off),
        3 => (LevelFilter::Trace, LevelFilter::Debug),
        _ => (LevelFilter::Off, LevelFilter::Trace),
    };

    let config = match debug_level {
        0 | 1 | 2 | 3 => logging_builder
            .logger(Logger::builder().build(bin_name, l1))
            .logger(Logger::builder().build("shadowsocks_rust", l1))
            .logger(Logger::builder().build("shadowsocks", l1))
            .logger(Logger::builder().build("shadowsocks_service", l1)),
        _ => logging_builder,
    }
    .build(Root::builder().appender("console").build(l2))
    .expect("logging");

    log4rs::init_config(config).expect("logging");
}

/// Init a default logger
pub fn init_with_default(bin_name: &str) {
    init_with_config(bin_name, &LogConfig::default());
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

//! The Rust Prelude
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particuarly traits, which are used in almost every single Rust
//! program.
//!
//! On a technical level, Rust inserts
//!
//! ```ignore
//! extern crate std;
//! ```
//!
//! into the crate root of every crate, and
//!
//! ```ignore
//! use std::prelude::v1::*;
//! ```
//!
//! into every module.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: ../io/prelude/index.html
//!
//! The differece between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their consitutent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and reexports the following.
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`]}. The marker
//!   traits indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
//!   operations for both destuctors and overloading `()`.
//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a
//!   value.
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
//!   [`to_owned()`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`],
//!   the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [`std::default`]::[`Default`], types that have default values.
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various
//!   kinds.
//! * [`std::option`]::[`Option`]::{`self`, `Some`, `None`}. A type which
//!   expresses the presence or absence of a value. This type is so commonly
//!   used, its variants are also exported.
//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions
//!   that may succeed or fail. Like [`Option`], its variants are exported as
//!   well.
//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical
//!   reasons, but shouldn't have to exist. It provides a few useful methods on
//!   slices.
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated
//!   vector.
//!
//! [`AsMut`]: ../convert/trait.AsMut.html
//! [`AsRef`]: ../convert/trait.AsRef.html
//! [`Box`]: ../boxed/struct.Box.html
//! [`Clone`]: ../clone/trait.Clone.html
//! [`Copy`]: ../marker/trait.Copy.html
//! [`Default`]: ../default/trait.Default.html
//! [`DoubleEndedIterator`]: ../iter/trait.DoubleEndedIterator.html
//! [`Drop`]: ../ops/trait.Drop.html
//! [`Eq`]: ../cmp/trait.Eq.html
//! [`ExactSizeIterator`]: ../iter/trait.ExactSizeIterator.html
//! [`Extend`]: ../iter/trait.Extend.html
//! [`FnMut`]: ../ops/trait.FnMut.html
//! [`FnOnce`]: ../ops/trait.FnOnce.html
//! [`Fn`]: ../ops/trait.Fn.html
//! [`From`]: ../convert/trait.From.html
//! [`IntoIterator`]: ../iter/trait.IntoIterator.html
//! [`Into`]: ../convert/trait.Into.html
//! [`Iterator`]: ../iter/trait.Iterator.html
//! [`Option`]: ../option/enum.Option.html
//! [`Ord`]: ../cmp/trait.Ord.html
//! [`PartialEq`]: ../cmp/trait.PartialEq.html
//! [`PartialOrd`]: ../cmp/trait.PartialOrd.html
//! [`Result`]: ../result/enum.Result.html
//! [`Send`]: ../marker/trait.Send.html
//! [`Sized`]: ../marker/trait.Sized.html
//! [`SliceConcatExt`]: ../slice/trait.SliceConcatExt.html
//! [`String`]: ../string/struct.String.html
//! [`Sync`]: ../marker/trait.Sync.html
//! [`ToOwned`]: ../borrow/trait.ToOwned.html
//! [`ToString`]: ../string/trait.ToString.html
//! [`Vec`]: ../vec/struct.Vec.html
//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone
//! [`drop`]: ../mem/fn.drop.html
//! [`std::borrow`]: ../borrow/index.html
//! [`std::boxed`]: ../boxed/index.html
//! [`std::clone`]: ../clone/index.html
//! [`std::cmp`]: ../cmp/index.html
//! [`std::convert`]: ../convert/index.html
//! [`std::default`]: ../default/index.html
//! [`std::iter`]: ../iter/index.html
//! [`std::marker`]: ../marker/index.html
//! [`std::mem`]: ../mem/index.html
//! [`std::ops`]: ../ops/index.html
//! [`std::option`]: ../option/index.html
//! [`std::prelude::v1`]: v1/index.html
//! [`std::result`]: ../result/index.html
//! [`std::slice`]: ../slice/index.html
//! [`std::string`]: ../string/index.html
//! [`std::vec`]: ../vec/index.html
//! [`to_owned()`]: ../borrow/trait.ToOwned.html#tymethod.to_owned
//! [book-closures]: ../../book/closures.html
//! [book-dtor]: ../../book/drop.html
//! [book-enums]: ../../book/enums.html
//! [book-iter]: ../../book/iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<commit_msg>Rollup merge of #30442 - tshepang:typo, r=steveklabnik<commit_after>// Copyright 2014 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.

//! The Rust Prelude
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particuarly traits, which are used in almost every single Rust
//! program.
//!
//! On a technical level, Rust inserts
//!
//! ```ignore
//! extern crate std;
//! ```
//!
//! into the crate root of every crate, and
//!
//! ```ignore
//! use std::prelude::v1::*;
//! ```
//!
//! into every module.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: ../io/prelude/index.html
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their consitutent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and reexports the following.
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`]}. The marker
//!   traits indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
//!   operations for both destuctors and overloading `()`.
//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a
//!   value.
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
//!   [`to_owned()`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`],
//!   the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [`std::default`]::[`Default`], types that have default values.
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various
//!   kinds.
//! * [`std::option`]::[`Option`]::{`self`, `Some`, `None`}. A type which
//!   expresses the presence or absence of a value. This type is so commonly
//!   used, its variants are also exported.
//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions
//!   that may succeed or fail. Like [`Option`], its variants are exported as
//!   well.
//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical
//!   reasons, but shouldn't have to exist. It provides a few useful methods on
//!   slices.
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated
//!   vector.
//!
//! [`AsMut`]: ../convert/trait.AsMut.html
//! [`AsRef`]: ../convert/trait.AsRef.html
//! [`Box`]: ../boxed/struct.Box.html
//! [`Clone`]: ../clone/trait.Clone.html
//! [`Copy`]: ../marker/trait.Copy.html
//! [`Default`]: ../default/trait.Default.html
//! [`DoubleEndedIterator`]: ../iter/trait.DoubleEndedIterator.html
//! [`Drop`]: ../ops/trait.Drop.html
//! [`Eq`]: ../cmp/trait.Eq.html
//! [`ExactSizeIterator`]: ../iter/trait.ExactSizeIterator.html
//! [`Extend`]: ../iter/trait.Extend.html
//! [`FnMut`]: ../ops/trait.FnMut.html
//! [`FnOnce`]: ../ops/trait.FnOnce.html
//! [`Fn`]: ../ops/trait.Fn.html
//! [`From`]: ../convert/trait.From.html
//! [`IntoIterator`]: ../iter/trait.IntoIterator.html
//! [`Into`]: ../convert/trait.Into.html
//! [`Iterator`]: ../iter/trait.Iterator.html
//! [`Option`]: ../option/enum.Option.html
//! [`Ord`]: ../cmp/trait.Ord.html
//! [`PartialEq`]: ../cmp/trait.PartialEq.html
//! [`PartialOrd`]: ../cmp/trait.PartialOrd.html
//! [`Result`]: ../result/enum.Result.html
//! [`Send`]: ../marker/trait.Send.html
//! [`Sized`]: ../marker/trait.Sized.html
//! [`SliceConcatExt`]: ../slice/trait.SliceConcatExt.html
//! [`String`]: ../string/struct.String.html
//! [`Sync`]: ../marker/trait.Sync.html
//! [`ToOwned`]: ../borrow/trait.ToOwned.html
//! [`ToString`]: ../string/trait.ToString.html
//! [`Vec`]: ../vec/struct.Vec.html
//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone
//! [`drop`]: ../mem/fn.drop.html
//! [`std::borrow`]: ../borrow/index.html
//! [`std::boxed`]: ../boxed/index.html
//! [`std::clone`]: ../clone/index.html
//! [`std::cmp`]: ../cmp/index.html
//! [`std::convert`]: ../convert/index.html
//! [`std::default`]: ../default/index.html
//! [`std::iter`]: ../iter/index.html
//! [`std::marker`]: ../marker/index.html
//! [`std::mem`]: ../mem/index.html
//! [`std::ops`]: ../ops/index.html
//! [`std::option`]: ../option/index.html
//! [`std::prelude::v1`]: v1/index.html
//! [`std::result`]: ../result/index.html
//! [`std::slice`]: ../slice/index.html
//! [`std::string`]: ../string/index.html
//! [`std::vec`]: ../vec/index.html
//! [`to_owned()`]: ../borrow/trait.ToOwned.html#tymethod.to_owned
//! [book-closures]: ../../book/closures.html
//! [book-dtor]: ../../book/drop.html
//! [book-enums]: ../../book/enums.html
//! [book-iter]: ../../book/iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<|endoftext|>