<commit_before>use hyper::client::Client;

use html5ever::parse_document;
use html5ever::rcdom::{RcDom, Handle, NodeEnum};
use html5ever::tendril::TendrilSink;

use encoding::{Encoding, DecoderTrap};
use encoding::all::WINDOWS_949;

use std::io::Read;
use std::fmt;

enum ValueItem {
    NONE,
    ROE,
    PER,
    PBR,
}

pub struct Company {
    name : String,
    code : String,
    roe : f32,
    per : f32,
    pbr : f32,
}

// impl of Company
impl fmt::Debug for Company {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}, {}, {}, {}, {}",
            self.name(), self.code(), self.roe(), self.per(), self.pbr)
    }
}

impl Company {
    pub fn new(name : &str, code : &str, roe : f32, per : f32, pbr : f32) -> Company {
        Company {
            name : name.to_string(),
            code : code.to_string(),
            roe : roe,
            per : per,
            pbr : pbr
        }
    }

    pub fn name(&self) -> &str { &self.name }
    pub fn code(&self) -> &str { &self.code }
    pub fn roe(&self) -> f32 { self.roe }
    pub fn per(&self) -> f32 { self.per }
    pub fn pbr(&self) -> f32 { self.pbr }
}

// public methods
pub fn get_values_with_code<'a>(code : &'a str) -> Result<(f32, f32, f32), &str> {
    let mut html_str = String::new();

    // get html string with code
    if get_page_html(code, &mut html_str) == false {
        return Err("Getting html page is failed!");
    }

    // parse html
    let decoder = parse_document(RcDom::default(), Default::default()).from_utf8();
    let mut html_bytes = html_str.as_bytes();
    let dom = match decoder.read_from(&mut html_bytes) {
        Err(_)  => {
            return Err("Parsing html is failed!");
        },
        Ok(x)   => x
    };

    // get values
    let values = match get_value_from_dom(dom) {
        Err(_)  => {
            return Err("get_value_from_dom() - fail!");
        },
        Ok(x)   => x
    };

    Ok(values)
}

fn get_value_from_dom<'a>(dom : RcDom) -> Result<(f32, f32, f32), &'a str> {

    // find text nodes
    let text_node_list = find_text_node(&dom.document);
    if text_node_list.len() == 0 {
        return Err("Failed to collect nodes.");
    }

    // compose text list
    let mut text_list : Vec<String> = Vec::new();
    if collect_text_in_text_nodes(text_node_list, &mut text_list) == 0 {
        return Err("Failed to collect texts.");
    }

    // result
    let values = match get_values_from_text_list(text_list) {
        Err(_)  => {
            return Err("Failed to get values from text list!");
        },
        Ok(x)   => x
    };

    Ok(values)
}

fn get_page_html<'a>(code : &str, html_str : &mut String) -> bool {
    let base_url = "http://finance.naver.com/item/main.nhn?code=";
    let client = Client::new();
    let mut buff = Vec::new();

    // url
    let target_url = base_url.to_string() + code;

    // send request to server
    let mut resp = match client.get(&target_url).send() {
        Err(x)  => {
            println!("{:?}", x);
            return false;
        },
        Ok(x)   => x
    };

    // read html binary
    match resp.read_to_end(&mut buff) {
        Err(x)  => {
            println!("{:?}", x);
            return false;
        },
        Ok(_)   => {}
    };

    // encoding 을 utf-8 로 변경
    let html_src = match WINDOWS_949.decode(&buff[..], DecoderTrap::Replace) {
        Err(x) => {
            println!("{:?}", x);
            return false;
        },
        Ok(x) => x
    };

    html_str.push_str(&html_src);

    true
}

fn get_values_from_text_list<'a>(text_list : Vec<String>) -> Result<(f32, f32, f32), &'a str> {

    let mut roe_list : Vec<f32> = Vec::new();
    let mut per_list : Vec<f32> = Vec::new();
    let mut pbr_list : Vec<f32> = Vec::new();

    let mut item = ValueItem::NONE;
    for text in text_list {
        match item {
            ValueItem::ROE => {
                match text.parse::<f32>() {
                    Ok(x)   => {
                        roe_list.push(x);
                        continue;
                    },
                    Err(_) => {
                        item = text_to_item(&text);
                    }
                };
            },
            ValueItem::PER => {
                match text.parse::<f32>() {
                    Ok(x)   => {
                        per_list.push(x);
                        continue;
                    },
                    Err(_) => {
                        item = text_to_item(&text);
                    }
                };
            },
            ValueItem::PBR => {
                match text.parse::<f32>() {
                    Ok(x)   => {
                        pbr_list.push(x);
                        continue;
                    },
                    Err(_) => {
                        item = text_to_item(&text);
                    }
                };
            },
            _ => item = text_to_item(&text)
        };
    }

    if roe_list.len() == 0 {
        return Err("No ROE value!");
    }

    if per_list.len() == 0 {
        return Err("No PER value!");
    }

    if pbr_list.len() == 0 {
        return Err("No PBR value!");
    }

    Ok((roe_list[0], per_list[0], pbr_list[0]))
}

fn text_to_item(text : &str) -> ValueItem {
    if text == "ROE(%)" {
        return ValueItem::ROE;
    }
    else if text == "PER(%)" {
        return ValueItem::PER;
    }
    else if text == "PBR(배)" {
        return ValueItem::PBR;
    }
    else {
        return ValueItem::NONE;
    }
}

fn collect_text_in_text_nodes(node_list : Vec<Handle>, text_list : &mut Vec<String>) -> usize {
    for handle in node_list {
        if let NodeEnum::Text(ref x) = handle.borrow().node {
            // get raw text
            let raw_text = format!("{}", x);

            // process text
            let text = raw_text.chars()
                               .filter(|c| *c != '\r' && *c != '\n' && *c != '\t')
                               .collect::<String>();
            // string data
            if text.len() > 0 {
                text_list.push(text);
            }
        }
    }

    text_list.len()
}

fn find_text_node(root : &Handle) -> Vec<Handle> {
    let mut buffer : Vec<Handle> = Vec::new();

    for child in &root.borrow().children {
        if let NodeEnum::Text(_) = child.borrow().node {
            buffer.push(child.clone());
        }

        let mut buff_for_child = find_text_node(child);
        buffer.append(&mut buff_for_child);
    }

    buffer
}
<commit_msg>코드 정리 중<commit_after>use hyper::client::Client;

use html5ever::parse_document;
use html5ever::rcdom::{RcDom, Handle, NodeEnum};
use html5ever::tendril::TendrilSink;

use encoding::{Encoding, DecoderTrap};
use encoding::all::WINDOWS_949;

use std::io::Read;
use std::fmt;

enum ValueItem {
    NONE,
    ROE,
    PER,
    PBR,
}

pub struct Company {
    name : String,
    code : String,
    roe : f32,
    per : f32,
    pbr : f32,
}

// impl of Company
impl fmt::Debug for Company {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}, {}, {}, {}, {}",
            self.name(), self.code(), self.roe(), self.per(), self.pbr)
    }
}

impl Company {
    pub fn new(name : &str, code : &str, roe : f32, per : f32, pbr : f32) -> Company {
        Company {
            name : name.to_string(),
            code : code.to_string(),
            roe : roe,
            per : per,
            pbr : pbr
        }
    }

    pub fn name(&self) -> &str { &self.name }
    pub fn code(&self) -> &str { &self.code }
    pub fn roe(&self) -> f32 { self.roe }
    pub fn per(&self) -> f32 { self.per }
    pub fn pbr(&self) -> f32 { self.pbr }
}

// public methods
pub fn get_values_with_code<'a>(code : &'a str) -> Result<(f32, f32, f32), &str> {
    let mut html_str = String::new();
    // get html string with code
    if get_page_html(code, &mut html_str) == false {
        return Err("Getting html page is failed!");
    }

    // parse html
    let decoder = parse_document(RcDom::default(), Default::default()).from_utf8();
    let mut html_bytes = html_str.as_bytes();
    let dom = match decoder.read_from(&mut html_bytes) {
        Err(_)  => {
            return Err("Parsing html is failed!");
        },
        Ok(x)   => x
    };

    // get values
    get_value_from_dom(dom)
}

fn get_value_from_dom<'a>(dom : RcDom) -> Result<(f32, f32, f32), &'a str> {
    // find text nodes
    let text_node_list = find_text_node(&dom.document);
    if text_node_list.len() == 0 {
        return Err("Failed to collect nodes.");
    }

    // compose text list
    let text_list;
    if let Some(x) = collect_text_in_text_nodes(text_node_list) {
        text_list = x;
    }
    else {
        return Err("Failed to collect texts.");
    }

    // result
    get_values_from_text_list(text_list)
}

fn get_page_html<'a>(code : &str, html_str : &mut String) -> bool {
    let base_url = "http://finance.naver.com/item/main.nhn?code=";
    let client = Client::new();
    let mut buff = Vec::new();

    // url
    let target_url = base_url.to_string() + code;

    // send request to server
    let mut resp = match client.get(&target_url).send() {
        Err(x)  => {
            println!("{:?}", x);
            return false;
        },
        Ok(x)   => x
    };

    // read html binary
    match resp.read_to_end(&mut buff) {
        Err(x)  => {
            println!("{:?}", x);
            return false;
        },
        Ok(_)   => {}
    };

    // encoding 을 utf-8 로 변경
    let html_src = match WINDOWS_949.decode(&buff[..], DecoderTrap::Replace) {
        Err(x) => {
            println!("{:?}", x);
            return false;
        },
        Ok(x) => x
    };

    html_str.push_str(&html_src);

    true
}

fn get_values_from_text_list<'a>(text_list : Vec<String>) -> Result<(f32, f32, f32), &'a str> {

    let mut roe_list : Vec<f32> = Vec::new();
    let mut per_list : Vec<f32> = Vec::new();
    let mut pbr_list : Vec<f32> = Vec::new();

    let mut item = ValueItem::NONE;
    for text in text_list {
        match item {
            ValueItem::ROE => {
                match text.parse::<f32>() {
                    Ok(x)   => {
                        roe_list.push(x);
                        continue;
                    },
                    Err(_) => {
                        item = text_to_item(&text);
                    }
                };
            },
            ValueItem::PER => {
                match text.parse::<f32>() {
                    Ok(x)   => {
                        per_list.push(x);
                        continue;
                    },
                    Err(_) => {
                        item = text_to_item(&text);
                    }
                };
            },
            ValueItem::PBR => {
                match text.parse::<f32>() {
                    Ok(x)   => {
                        pbr_list.push(x);
                        continue;
                    },
                    Err(_) => {
                        item = text_to_item(&text);
                    }
                };
            },
            _ => item = text_to_item(&text)
        };
    }

    if roe_list.len() == 0 {
        return Err("No ROE value!");
    }

    if per_list.len() == 0 {
        return Err("No PER value!");
    }

    if pbr_list.len() == 0 {
        return Err("No PBR value!");
    }

    Ok((roe_list[0], per_list[0], pbr_list[0]))
}

fn text_to_item(text : &str) -> ValueItem {
    if text == "ROE(%)" {
        return ValueItem::ROE;
    }
    else if text == "PER(%)" {
        return ValueItem::PER;
    }
    else if text == "PBR(배)" {
        return ValueItem::PBR;
    }
    else {
        return ValueItem::NONE;
    }
}

fn collect_text_in_text_nodes(node_list : Vec<Handle>) -> Option<Vec<String>> {
    let mut text_list : Vec<String> = Vec::new();
    let mut node_iter = node_list.iter();
    while let Some(handle) = node_iter.next() {
        if let NodeEnum::Text(ref x) = handle.borrow().node {
            // get text
            let text = format!("{}", x).chars()
                                       .filter(|c| *c != '\r' && *c != '\n' && *c != '\t')
                                       .collect::<String>();
            // string data
            if text.len() > 0 {
                text_list.push(text);
            }
        }
    }

    if text_list.len() > 0 {
        return Some(text_list);
    }
    else {
        return None;
    }
}

fn find_text_node(root : &Handle) -> Vec<Handle> {
    let mut buffer : Vec<Handle> = Vec::new();

    let root_bind = root.borrow();
    let mut child_iter = root_bind.children.iter();
    while let Some(child) = child_iter.next() {
        if let NodeEnum::Text(_) = child.borrow().node {
            buffer.push(child.clone());
        }

        let mut buff_for_child = find_text_node(child);
        buffer.append(&mut buff_for_child);
    }

    buffer
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::str::FromStr;
use toml::Value;

use library;
use library::{Library, TypeId, MAIN_NAMESPACE};
use config::error::TomlHelper;
use config::parsable::{Parsable, Parse};
use super::child_properties::ChildProperties;
use super::functions::Functions;
use super::members::Members;
use super::properties::Properties;
use super::signals::{Signals, Signal};
use version::Version;
use analysis::ref_mode;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GStatus {
    Manual, // already generated
    Generate,
    Comment,
    Ignore,
}

impl GStatus {
    pub fn ignored(&self) -> bool {
        self == &GStatus::Ignore
    }
    pub fn need_generate(&self) -> bool {
        self == &GStatus::Generate
    }
    pub fn normal(&self) -> bool {
        self == &GStatus::Generate || self == &GStatus::Manual
    }
}

impl Default for GStatus {
    fn default() -> GStatus {
        GStatus::Ignore
    }
}

impl FromStr for GStatus {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "manual" => Ok(GStatus::Manual),
            "generate" => Ok(GStatus::Generate),
            "comment" => Ok(GStatus::Comment),
            "ignore" => Ok(GStatus::Ignore),
            e => Err(format!("Wrong object status: \"{}\"", e)),
        }
    }
}

/// Info about `GObject` descendant
#[derive(Clone, Debug)]
pub struct GObject {
    pub name: String,
    pub functions: Functions,
    pub signals: Signals,
    pub members: Members,
    pub properties: Properties,
    pub status: GStatus,
    pub module_name: Option<String>,
    pub version: Option<Version>,
    pub cfg_condition: Option<String>,
    pub type_id: Option<TypeId>,
    pub generate_trait: bool,
    pub trait_name: Option<String>,
    pub child_properties: Option<ChildProperties>,
    pub concurrency: library::Concurrency,
    pub ref_mode: Option<ref_mode::RefMode>,
}

impl Default for GObject {
    fn default() -> GObject {
        GObject {
            name: "Default".into(),
            functions: Functions::new(),
            signals: Signals::new(),
            members: Members::new(),
            properties: Properties::new(),
            status: Default::default(),
            module_name: None,
            version: None,
            cfg_condition: None,
            type_id: None,
            generate_trait: true,
            trait_name: None,
            child_properties: None,
            concurrency: Default::default(),
            ref_mode: None,
        }
    }
}

//TODO: ?change to HashMap<String, GStatus>
pub type GObjects = BTreeMap<String, GObject>;

pub fn parse_toml(toml_objects: &Value, concurrency: library::Concurrency) -> GObjects {
    let mut objects = GObjects::new();
    for toml_object in toml_objects.as_array().unwrap() {
        let gobject = parse_object(toml_object, concurrency);
        objects.insert(gobject.name.clone(), gobject);
    }
    objects
}

fn ref_mode_from_str(ref_mode: &str) -> Option<ref_mode::RefMode> {
    match ref_mode {
        "none" => Some(ref_mode::RefMode::None),
        "ref" => Some(ref_mode::RefMode::ByRef),
        "ref-mut" => Some(ref_mode::RefMode::ByRefMut),
        "ref-immut" => Some(ref_mode::RefMode::ByRefImmut),
        "ref-fake" => Some(ref_mode::RefMode::ByRefFake),
        _ => None,
    }
}

fn parse_object(toml_object: &Value, concurrency: library::Concurrency) -> GObject {
    let name: String = toml_object
        .lookup("name")
        .expect("Object name not defined")
        .as_str()
        .unwrap()
        .into();
    // Also checks for ChildProperties
    toml_object.check_unwanted(&["name", "status", "function", "signal", "member", "property",
                                 "module_name", "version", "concurrency", "ref_mode", "child_prop",
                                 "child_name", "child_type", "trait", "trait_name", "cfg_condition"],
                               &format!("object {}", name));

    let status = match toml_object.lookup("status") {
        Some(value) => {
            GStatus::from_str(value.as_str().unwrap()).unwrap_or_else(|_| Default::default())
        }
        None => Default::default(),
    };

    let functions = Functions::parse(toml_object.lookup("function"), &name);
    let signals = {
        let mut v = Vec::new();
        if let Some(configs) = toml_object.lookup("signal").and_then(|val| val.as_array()) {
            for config in configs {
                if let Some(item) = Signal::parse(config, &name, concurrency) {
                    v.push(item);
                }
            }
        }

        v
    };
    let members = Members::parse(toml_object.lookup("member"), &name);
    let properties = Properties::parse(toml_object.lookup("property"), &name);
    let module_name = toml_object
        .lookup("module_name")
        .and_then(|v| v.as_str())
        .map(|s| s.to_owned());
    let version = toml_object
        .lookup("version")
        .and_then(|v| v.as_str())
        .and_then(|s| s.parse().ok());
    let cfg_condition = toml_object
        .lookup("cfg_condition")
        .and_then(|v| v.as_str())
        .map(|s| s.to_owned());
    let generate_trait = toml_object
        .lookup("trait")
        .and_then(|v| v.as_bool())
        .unwrap_or(true);
    let trait_name = toml_object
        .lookup("trait_name")
        .and_then(|v| v.as_str())
        .map(|s| s.to_owned());
    let concurrency = toml_object
        .lookup("concurrency")
        .and_then(|v| v.as_str())
        .and_then(|v| v.parse().ok())
        .unwrap_or(concurrency);
    let ref_mode = toml_object
        .lookup("ref_mode")
        .and_then(|v| v.as_str())
        .and_then(ref_mode_from_str);
    let child_properties = ChildProperties::parse(toml_object, &name);

    if status != GStatus::Manual && ref_mode != None {
        warn!("ref_mode configuration used for non-manual object {}", name);
    }

    GObject {
        name: name,
        functions: functions,
        signals: signals,
        members: members,
        properties: properties,
        status: status,
        module_name: module_name,
        version: version,
        cfg_condition: cfg_condition,
        type_id: None,
        generate_trait: generate_trait,
        trait_name: trait_name,
        child_properties: child_properties,
        concurrency: concurrency,
        ref_mode: ref_mode,
    }
}

pub fn parse_status_shorthands(
    objects: &mut GObjects,
    toml: &Value,
    concurrency: library::Concurrency,
) {
    use self::GStatus::*;
    for &status in &[Manual, Generate, Comment, Ignore] {
        parse_status_shorthand(objects, status, toml, concurrency);
    }
}

fn parse_status_shorthand(
    objects: &mut GObjects,
    status: GStatus,
    toml: &Value,
    concurrency: library::Concurrency,
) {
    let name = format!("options.{:?}", status).to_ascii_lowercase();
    toml.lookup(&name).map(|a| a.as_array().unwrap()).map(
        |a| for name_ in a.iter().map(|s| s.as_str().unwrap()) {
            match objects.get(name_) {
                None => {
                    objects.insert(
                        name_.into(),
                        GObject {
                            name: name_.into(),
                            status: status,
                            concurrency: concurrency,
                            ..Default::default()
                        },
                    );
                }
                Some(_) => panic!("Bad name in {}: {} already defined", name, name_),
            }
        },
    );
}

pub fn resolve_type_ids(objects: &mut GObjects, library: &Library) {
    let ns = library.namespace(MAIN_NAMESPACE);
    let global_functions_name = format!("{}.*", ns.name);

    for (name, object) in objects.iter_mut() {
        let type_id = library.find_type(0, name);
        if type_id.is_none() && name != &global_functions_name {
            warn!("Configured object `{}` missing from the library", name);
        }
        object.type_id = type_id;
    }
}
<commit_msg>Add back std::ascii::AsciiExt - it is required on stable<commit_after>use std::ascii::AsciiExt;
use std::collections::BTreeMap;
use std::str::FromStr;
use toml::Value;

use library;
use library::{Library, TypeId, MAIN_NAMESPACE};
use config::error::TomlHelper;
use config::parsable::{Parsable, Parse};
use super::child_properties::ChildProperties;
use super::functions::Functions;
use super::members::Members;
use super::properties::Properties;
use super::signals::{Signals, Signal};
use version::Version;
use analysis::ref_mode;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GStatus {
    Manual, // already generated
    Generate,
    Comment,
    Ignore,
}

impl GStatus {
    pub fn ignored(&self) -> bool {
        self == &GStatus::Ignore
    }
    pub fn need_generate(&self) -> bool {
        self == &GStatus::Generate
    }
    pub fn normal(&self) -> bool {
        self == &GStatus::Generate || self == &GStatus::Manual
    }
}

impl Default for GStatus {
    fn default() -> GStatus {
        GStatus::Ignore
    }
}

impl FromStr for GStatus {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "manual" => Ok(GStatus::Manual),
            "generate" => Ok(GStatus::Generate),
            "comment" => Ok(GStatus::Comment),
            "ignore" => Ok(GStatus::Ignore),
            e => Err(format!("Wrong object status: \"{}\"", e)),
        }
    }
}

/// Info about `GObject` descendant
#[derive(Clone, Debug)]
pub struct GObject {
    pub name: String,
    pub functions: Functions,
    pub signals: Signals,
    pub members: Members,
    pub properties: Properties,
    pub status: GStatus,
    pub module_name: Option<String>,
    pub version: Option<Version>,
    pub cfg_condition: Option<String>,
    pub type_id: Option<TypeId>,
    pub generate_trait: bool,
    pub trait_name: Option<String>,
    pub child_properties: Option<ChildProperties>,
    pub concurrency: library::Concurrency,
    pub ref_mode: Option<ref_mode::RefMode>,
}

impl Default for GObject {
    fn default() -> GObject {
        GObject {
            name: "Default".into(),
            functions: Functions::new(),
            signals: Signals::new(),
            members: Members::new(),
            properties: Properties::new(),
            status: Default::default(),
            module_name: None,
            version: None,
            cfg_condition: None,
            type_id: None,
            generate_trait: true,
            trait_name: None,
            child_properties: None,
            concurrency: Default::default(),
            ref_mode: None,
        }
    }
}

//TODO: ?change to HashMap<String, GStatus>
pub type GObjects = BTreeMap<String, GObject>;

pub fn parse_toml(toml_objects: &Value, concurrency: library::Concurrency) -> GObjects {
    let mut objects = GObjects::new();
    for toml_object in toml_objects.as_array().unwrap() {
        let gobject = parse_object(toml_object, concurrency);
        objects.insert(gobject.name.clone(), gobject);
    }
    objects
}

fn ref_mode_from_str(ref_mode: &str) -> Option<ref_mode::RefMode> {
    match ref_mode {
        "none" => Some(ref_mode::RefMode::None),
        "ref" => Some(ref_mode::RefMode::ByRef),
        "ref-mut" => Some(ref_mode::RefMode::ByRefMut),
        "ref-immut" => Some(ref_mode::RefMode::ByRefImmut),
        "ref-fake" => Some(ref_mode::RefMode::ByRefFake),
        _ => None,
    }
}

fn parse_object(toml_object: &Value, concurrency: library::Concurrency) -> GObject {
    let name: String = toml_object
        .lookup("name")
        .expect("Object name not defined")
        .as_str()
        .unwrap()
        .into();
    // Also checks for ChildProperties
    toml_object.check_unwanted(&["name", "status", "function", "signal", "member", "property",
                                 "module_name", "version", "concurrency", "ref_mode", "child_prop",
                                 "child_name", "child_type", "trait", "trait_name", "cfg_condition"],
                               &format!("object {}", name));

    let status = match toml_object.lookup("status") {
        Some(value) => {
            GStatus::from_str(value.as_str().unwrap()).unwrap_or_else(|_| Default::default())
        }
        None => Default::default(),
    };

    let functions = Functions::parse(toml_object.lookup("function"), &name);
    let signals = {
        let mut v = Vec::new();
        if let Some(configs) = toml_object.lookup("signal").and_then(|val| val.as_array()) {
            for config in configs {
                if let Some(item) = Signal::parse(config, &name, concurrency) {
                    v.push(item);
                }
            }
        }

        v
    };
    let members = Members::parse(toml_object.lookup("member"), &name);
    let properties = Properties::parse(toml_object.lookup("property"), &name);
    let module_name = toml_object
        .lookup("module_name")
        .and_then(|v| v.as_str())
        .map(|s| s.to_owned());
    let version = toml_object
        .lookup("version")
        .and_then(|v| v.as_str())
        .and_then(|s| s.parse().ok());
    let cfg_condition = toml_object
        .lookup("cfg_condition")
        .and_then(|v| v.as_str())
        .map(|s| s.to_owned());
    let generate_trait = toml_object
        .lookup("trait")
        .and_then(|v| v.as_bool())
        .unwrap_or(true);
    let trait_name = toml_object
        .lookup("trait_name")
        .and_then(|v| v.as_str())
        .map(|s| s.to_owned());
    let concurrency = toml_object
        .lookup("concurrency")
        .and_then(|v| v.as_str())
        .and_then(|v| v.parse().ok())
        .unwrap_or(concurrency);
    let ref_mode = toml_object
        .lookup("ref_mode")
        .and_then(|v| v.as_str())
        .and_then(ref_mode_from_str);
    let child_properties = ChildProperties::parse(toml_object, &name);

    if status != GStatus::Manual && ref_mode != None {
        warn!("ref_mode configuration used for non-manual object {}", name);
    }

    GObject {
        name: name,
        functions: functions,
        signals: signals,
        members: members,
        properties: properties,
        status: status,
        module_name: module_name,
        version: version,
        cfg_condition: cfg_condition,
        type_id: None,
        generate_trait: generate_trait,
        trait_name: trait_name,
        child_properties: child_properties,
        concurrency: concurrency,
        ref_mode: ref_mode,
    }
}

pub fn parse_status_shorthands(
    objects: &mut GObjects,
    toml: &Value,
    concurrency: library::Concurrency,
) {
    use self::GStatus::*;
    for &status in &[Manual, Generate, Comment, Ignore] {
        parse_status_shorthand(objects, status, toml, concurrency);
    }
}

fn parse_status_shorthand(
    objects: &mut GObjects,
    status: GStatus,
    toml: &Value,
    concurrency: library::Concurrency,
) {
    let name = format!("options.{:?}", status).to_ascii_lowercase();
    toml.lookup(&name).map(|a| a.as_array().unwrap()).map(
        |a| for name_ in a.iter().map(|s| s.as_str().unwrap()) {
            match objects.get(name_) {
                None => {
                    objects.insert(
                        name_.into(),
                        GObject {
                            name: name_.into(),
                            status: status,
                            concurrency: concurrency,
                            ..Default::default()
                        },
                    );
                }
                Some(_) => panic!("Bad name in {}: {} already defined", name, name_),
            }
        },
    );
}

pub fn resolve_type_ids(objects: &mut GObjects, library: &Library) {
    let ns = library.namespace(MAIN_NAMESPACE);
    let global_functions_name = format!("{}.*", ns.name);

    for (name, object) in objects.iter_mut() {
        let type_id = library.find_type(0, name);
        if type_id.is_none() && name != &global_functions_name {
            warn!("Configured object `{}` missing from the library", name);
        }
        object.type_id = type_id;
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::ops::RangeInclusive;

use crate::common::Lines;
use crate::Solution;

fn split_nums<'a>(s: &'a str) -> impl Iterator<Item = u32> + 'a {
    s.split(|c: char| !c.is_ascii_digit()).filter_map(|s| {
        if s.is_empty() {
            None
        } else {
            Some(s.parse().unwrap())
        }
    })
}

fn read_input(input: &mut dyn Read) -> (HashMap<String, Vec<RangeInclusive<u32>>>, Vec<Vec<u32>>) {
    let mut lines = Lines::new(input).filter(|s| !s.is_empty());

    let mut rules = HashMap::new();
    let mut tickets = Vec::new();

    while let Some(line) = lines.next() {
        if line.as_str() == "your ticket:" {
            break;
        }

        let colon = line.find(':').unwrap();

        let nums: Vec<_> = split_nums(&line[colon..]).collect();

        let ranges: Vec<_> = nums.chunks_exact(2).map(|s| s[0]..=s[1]).collect();

        rules.insert(line[..colon].to_owned(), ranges);
    }

    while let Some(line) = lines.next() {
        if line.as_str() == "nearby tickets:" {
            continue;
        }

        tickets.push(split_nums(&line).collect());
    }

    (rules, tickets)
}

#[derive(Default)]
pub struct Day16;

impl Solution for Day16 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);

        let mut rate = 0;

        for ticket in &tickets[1..] {
            for value in ticket {
                if rules.values().flatten().all(|r| !r.contains(value)) {
                    rate += value;
                }
            }
        }

        rate.to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);
        let mut tickets = tickets;

        // O(n) operation but it's fine
        let my_ticket = tickets.remove(0);

        // Filter out invalid tickets
        tickets.retain(|t| {
            t.iter()
                .all(|v| rules.values().flatten().any(|r| r.contains(v)))
        });

        let all_fields: HashSet<_> = rules.keys().cloned().collect();

        let mut pos_can_be = vec![all_fields; my_ticket.len()];

        let mut fixed_fields = HashMap::new();

        for ticket in &tickets {
            for (field, ranges) in &rules {
                for (pos, value) in ticket.iter().enumerate() {
                    if pos_can_be[pos].len() <= 1 {
                        continue;
                    }

                    if !ranges.iter().any(|r| r.contains(value)) {
                        pos_can_be[pos].remove(field);
                    }
                }
            }
        }

        while fixed_fields.len() != rules.len() {
            // Fix fields that are the only option for a certain spot
            for pos in 0..pos_can_be.len() {
                if pos_can_be[pos].len() == 1 {
                    let field = pos_can_be[pos]
                        .drain()
                        .next()
                        .expect("Safe because if statement");

                    assert!(!fixed_fields.contains_key(&field));

                    for can_be in pos_can_be.iter_mut() {
                        can_be.remove(&field);
                    }

                    fixed_fields.insert(field, pos);
                }
            }

            // Check if there are fields that only fit a single spot
            let mut can_fit: HashMap<_, Vec<usize>> = HashMap::new();

            for (pos, candiates) in pos_can_be.iter().enumerate() {
                for candidate in candiates {
                    can_fit.entry(candidate.clone()).or_default().push(pos);
                }
            }

            for (field, pos) in can_fit.into_iter().filter(|(_, v)| v.len() == 1) {
                let pos = pos[0];
                assert!(!fixed_fields.contains_key(&field));

                pos_can_be[pos].clear();

                fixed_fields.insert(field, pos);
            }
        }

        fixed_fields
            .iter()
            .filter(|(k, _)| k.starts_with("departure"))
            .map(|(_, &v)| my_ticket[v])
            .fold(1u64, |a, b| a * (b as u64))
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/16.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day16, 1, SAMPLE, 71);
    }
}
<commit_msg>Use bitsets for tracking what fits.<commit_after>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::ops::RangeInclusive;

use crate::common::Lines;
use crate::Solution;

fn split_nums<'a>(s: &'a str) -> impl Iterator<Item = u32> + 'a {
    s.split(|c: char| !c.is_ascii_digit()).filter_map(|s| {
        if s.is_empty() {
            None
        } else {
            Some(s.parse().unwrap())
        }
    })
}

fn read_input(input: &mut dyn Read) -> (HashMap<String, Vec<RangeInclusive<u32>>>, Vec<Vec<u32>>) {
    let mut lines = Lines::new(input).filter(|s| !s.is_empty());

    let mut rules = HashMap::new();
    let mut tickets = Vec::new();

    while let Some(line) = lines.next() {
        if line.as_str() == "your ticket:" {
            break;
        }

        let colon = line.find(':').unwrap();

        let nums: Vec<_> = split_nums(&line[colon..]).collect();

        let ranges: Vec<_> = nums.chunks_exact(2).map(|s| s[0]..=s[1]).collect();

        rules.insert(line[..colon].to_owned(), ranges);
    }

    while let Some(line) = lines.next() {
        if line.as_str() == "nearby tickets:" {
            continue;
        }

        tickets.push(split_nums(&line).collect());
    }

    (rules, tickets)
}

#[derive(Default)]
pub struct Day16;

impl Solution for Day16 {
    fn part1(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);

        let mut rate = 0;

        for ticket in &tickets[1..] {
            for value in ticket {
                if rules.values().flatten().all(|r| !r.contains(value)) {
                    rate += value;
                }
            }
        }

        rate.to_string()
    }

    fn part2(&mut self, input: &mut dyn Read) -> String {
        let (rules, tickets) = read_input(input);
        let mut tickets = tickets;

        // O(n) operation but it's fine
        let my_ticket = tickets.remove(0);

        // Filter out invalid tickets
        tickets.retain(|t| {
            t.iter()
                .all(|v| rules.values().flatten().any(|r| r.contains(v)))
        });

        let all_fields: HashSet<_> = rules.keys().cloned().collect();

        let mut pos_can_be = vec![all_fields; my_ticket.len()];

        let mut fixed_fields = HashMap::new();

        for ticket in &tickets {
            for (field, ranges) in &rules {
                for (pos, value) in ticket.iter().enumerate() {
                    if pos_can_be[pos].len() <= 1 {
                        continue;
                    }

                    if !ranges.iter().any(|r| r.contains(value)) {
                        pos_can_be[pos].remove(field);
                    }
                }
            }
        }

        let mut can_fit: HashMap<&str, u64> = rules.keys().map(|k| (k.as_str(), 0)).collect();

        while fixed_fields.len() != rules.len() {
            // Fix fields that are the only option for a certain spot
            for pos in 0..pos_can_be.len() {
                if pos_can_be[pos].len() == 1 {
                    let field = pos_can_be[pos]
                        .drain()
                        .next()
                        .expect("Safe because if statement");

                    assert!(!fixed_fields.contains_key(&field));

                    for can_be in pos_can_be.iter_mut() {
                        can_be.remove(&field);
                    }

                    fixed_fields.insert(field, pos);
                }
            }

            // Reset can_fit
            can_fit.values_mut().for_each(|v| *v = 0);

            for (pos, candiates) in pos_can_be.iter().enumerate() {
                for candidate in candiates {
                    *can_fit.get_mut(candidate.as_str()).unwrap() |= 1 << pos;
                }
            }

            for (&field, &pos) in can_fit.iter().filter(|(_, v)| v.count_ones() == 1) {
                let pos = pos.trailing_zeros() as usize;
                assert!(!fixed_fields.contains_key(field));

                pos_can_be[pos].clear();

                fixed_fields.insert(field.to_owned(), pos);
            }
        }

        fixed_fields
            .iter()
            .filter(|(k, _)| k.starts_with("departure"))
            .map(|(_, &v)| my_ticket[v])
            .fold(1u64, |a, b| a * (b as u64))
            .to_string()
    }
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("../samples/16.txt");

    #[test]
    fn sample_part1() {
        test_implementation!(Day16, 1, SAMPLE, 71);
    }
}
<|endoftext|>


<commit_before>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::mem;

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: C::State,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32,
    pool: Pool,
    separate: bool,
}

impl<C, N> TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state and threads count.
    pub fn new(rows: i32,
               cols: i32,
               nhood: N,
               state: C::State,
               threads: u32,
               separate: bool)
               -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let threads = if separate {
            threads
        } else {
            threads - 1
        };

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows),
            pool: Pool::new(threads),
            separate: separate,
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0..self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols && coord.y() >= 0 && coord.y() < self.rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    fn neighbors_iter<'b>(&self,
                          cells: &'b Vec<C>,
                          neighbors: &'b Vec<Option<usize>>)
                          -> Iter<'b, C> {

        Iter::new(cells, neighbors, self.nhood.neighbors_count())
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        for i in 0..self.cells.len() {
            unsafe {
                let ref neighbors = self.neighbors.get_unchecked(i);
                let neighbors_iter = self.neighbors_iter(&self.old_cells, &neighbors);

                let old = self.old_cells.get_unchecked(i);
                let cell = self.cells.get_unchecked_mut(i);
                cell.update(old, neighbors_iter, &self.evolution_state);
            }
        }

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn dimensions(&self) -> Self::Coord { self.dimensions.clone() }
}
<commit_msg>Using Option instead.<commit_after>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::mem;

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: C::State,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32,
    pool: Option<Pool>,
    separate: bool,
}

impl<C, N> TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state and threads count.
    pub fn new(rows: i32,
               cols: i32,
               nhood: N,
               state: C::State,
               threads: u32,
               separate: bool)
               -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let threads = if separate {
            threads
        } else {
            threads - 1
        };
        let pool = if threads > 1 {
            Some(Pool::new(threads))
        } else {
            None
        };

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows),
            pool: pool,
            separate: separate,
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0..self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols && coord.y() >= 0 && coord.y() < self.rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    fn neighbors_iter<'b>(&self,
                          cells: &'b Vec<C>,
                          neighbors: &'b Vec<Option<usize>>)
                          -> Iter<'b, C> {

        Iter::new(cells, neighbors, self.nhood.neighbors_count())
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        for i in 0..self.cells.len() {
            unsafe {
                let ref neighbors = self.neighbors.get_unchecked(i);
                let neighbors_iter = self.neighbors_iter(&self.old_cells, &neighbors);

                let old = self.old_cells.get_unchecked(i);
                let cell = self.cells.get_unchecked_mut(i);
                cell.update(old, neighbors_iter, &self.evolution_state);
            }
        }

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn dimensions(&self) -> Self::Coord { self.dimensions.clone() }
}
<|endoftext|>


<commit_before>// TODO: Rethink this in an architecture independent fashion in due time

use xen::arch::x86::callbacks::set_callbacks;

extern "C" {
    fn hypervisor_callback();
    fn failsafe_callback();
}

#[cfg(target_arch = "x86")]
fn init_callbacks() {
    unsafe {
        use xen::defs::FLAT_KERNEL_CS;

        set_callbacks(FLAT_KERNEL_CS, hypervisor_callback,
                      FLAT_KERNEL_CS, failsafe_callback);
    }
}

#[cfg(target_arch = "x86_64")]
fn init_callbacks() {
    unsafe {
        set_callbacks(hypervisor_callback, failsafe_callback, None);
    }
}

#[no_mangle]
pub unsafe extern "C" fn do_hypervisor_callback() {
    panic!("Hypercall callback");
}

pub fn init() {
    init_callbacks();

    println!("Event subsystem initialized");
}
<commit_msg>libboot: Events are now all masked on boot<commit_after>// TODO: Rethink this in an architecture independent fashion in due time

use xen::event::dispatcher;
use xen::arch::x86::callbacks::set_callbacks;

extern "C" {
    fn hypervisor_callback();
    fn failsafe_callback();
}

#[cfg(target_arch = "x86")]
fn init_callbacks() {
    unsafe {
        use xen::defs::FLAT_KERNEL_CS;

        set_callbacks(FLAT_KERNEL_CS, hypervisor_callback,
                      FLAT_KERNEL_CS, failsafe_callback);
    }
}

#[cfg(target_arch = "x86_64")]
fn init_callbacks() {
    unsafe {
        set_callbacks(hypervisor_callback, failsafe_callback, None);
    }
}

#[no_mangle]
pub unsafe extern "C" fn do_hypervisor_callback() {
    panic!("Hypercall callback");
}

pub fn init() {
    init_callbacks();

    dispatcher().mask_all();

    println!("Event subsystem initialized");
}
<|endoftext|>


<commit_before>//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

mod global;
mod layout;

#[stable(feature = "global_alloc", since = "1.28.0")]
pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::{Layout, LayoutErr};

use crate::fmt;
use crate::ptr::{self, NonNull};

/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;

// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("memory allocation failed")
    }
}

/// A desired initial state for allocated memory.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum AllocInit {
    /// The contents of the new memory are undefined.
    ///
    /// Reading uninitialized memory is Undefined Behavior; it must be initialized before use.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    Zeroed,
}

impl AllocInit {
    /// Initialize the specified memory block.
    ///
    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
    ///
    /// [off]: AllocInit::init_offset
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init(self, memory: MemoryBlock) {
        self.init_offset(memory, 0)
    }

    /// Initialize the memory block like specified by `init` at the specified `offset`.
    ///
    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    /// * `offset` must be smaller than or equal to `memory.size`
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
        debug_assert!(
            offset <= memory.size,
            "`offset` must be smaller than or equal to `memory.size`"
        );
        match self {
            AllocInit::Uninitialized => (),
            AllocInit::Zeroed => {
                memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset)
            }
        }
    }
}

/// Represents a block of allocated memory returned by an allocator.
#[derive(Debug, Copy, Clone)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub struct MemoryBlock {
    pub ptr: NonNull<u8>,
    pub size: usize,
}

/// A placement constraint when growing or shrinking an existing allocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum ReallocPlacement {
    /// The allocator is allowed to move the allocation to a different memory address.
    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
    //                          allocator" and link it at "valid location".
    ///
    /// If the allocation _does_ move, it's the responsibility of the allocator
    /// to also move the data from the previous location to the new location.
    MayMove,
    /// The address of the new memory must not change.
    ///
    /// If the allocation would have to be moved to a new location to fit, the
    /// reallocation request will fail.
    InPlace,
}

/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][].
///
/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory.
///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this case must be caught.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that:
///
/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
///   [`shrink`], and
///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
///   directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
///   remains valid.
///
/// [`alloc`]: AllocRef::alloc
/// [`grow`]: AllocRef::grow
/// [`shrink`]: AllocRef::shrink
/// [`dealloc`]: AllocRef::dealloc
///
/// ### Memory fitting
///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold:
///
/// * The block must be allocated with the same alignment as [`layout.align()`], and
///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
///   - `min` is the size of the layout most recently used to allocate the block, and
///   - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
///
/// # Safety
///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
///   until the instance and all of its clones are dropped, and
///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this
///   allocator. A cloned allocator must behave like the same allocator.
///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
///   method of the allocator.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait AllocRef {
    /// On success, returns a memory block meeting the size and alignment guarantees of `layout`.
    ///
    /// The returned block may have a larger size than specified by `layout.size()` and is
    /// initialized as specified by [`init`], all the way up to the returned size of the block.
    ///
    /// [`init`]: AllocInit
    ///
    /// # Errors
    ///
    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    /// allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;

    /// Deallocates the memory denoted by `memory`.
    ///
    /// # Safety
    ///
    /// `memory` must be a memory block returned by this allocator.
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);

    /// Attempts to extend the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If `ReallocPlacement::MayMove` is used then ownership of the memory block referenced by `ptr`
    /// is transferred to this allocator. The memory may or may not be freed, and should be
    /// considered unusable (unless of course it is transferred back to the caller again via the
    /// return value of this method).
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The memory block will contain the following contents after a successful call to `grow`:
    ///   * Bytes `0..layout.size()` are preserved from the original allocation.
    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
    ///     that was originally requested when it was allocated.
    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
    ///     the size of the `MemoryBlock` returned by the `grow` call.
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    /// [`init`]: AllocInit
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly greater than `memory.size` or both are zero
    /// * `new_size` must be greater than or equal to `layout.size()`
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
    ///   (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size >= size,
                    "`new_size` must be greater than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, init)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }

    /// Attempts to shrink the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    /// transferred to this allocator. The memory may or may not have been freed, and should be
    /// considered unusable unless it was transferred back to the caller again via the
    /// return value of this method.
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly smaller than `memory.size` or both are zero
    /// * `new_size` must be smaller than or equal to `layout.size()`
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size <= size,
                    "`new_size` must be smaller than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }
}
<commit_msg>Improve docs in `AllocRef`<commit_after>//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

mod global;
mod layout;

#[stable(feature = "global_alloc", since = "1.28.0")]
pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::{Layout, LayoutErr};

use crate::fmt;
use crate::ptr::{self, NonNull};

/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;

// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("memory allocation failed")
    }
}

/// A desired initial state for allocated memory.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum AllocInit {
    /// The contents of the new memory are uninitialized.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    Zeroed,
}

impl AllocInit {
    /// Initialize the specified memory block.
    ///
    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
    ///
    /// [off]: AllocInit::init_offset
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init(self, memory: MemoryBlock) {
        self.init_offset(memory, 0)
    }

    /// Initialize the memory block like specified by `init` at the specified `offset`.
    ///
    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    /// * `offset` must be smaller than or equal to `memory.size`
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
        debug_assert!(
            offset <= memory.size,
            "`offset` must be smaller than or equal to `memory.size`"
        );
        match self {
            AllocInit::Uninitialized => (),
            AllocInit::Zeroed => {
                memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset)
            }
        }
    }
}

/// Represents a block of allocated memory returned by an allocator.
#[derive(Debug, Copy, Clone)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub struct MemoryBlock {
    pub ptr: NonNull<u8>,
    pub size: usize,
}

/// A placement constraint when growing or shrinking an existing allocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum ReallocPlacement {
    /// The allocator is allowed to move the allocation to a different memory address.
    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
    //                          allocator" and link it at "valid location".
    ///
    /// If the allocation _does_ move, it's the responsibility of the allocator
    /// to also move the data from the previous location to the new location.
    MayMove,
    /// The address of the new memory must not change.
    ///
    /// If the allocation would have to be moved to a new location to fit, the
    /// reallocation request will fail.
    InPlace,
}

/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][].
///
/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory.
///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this case must be caught.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that:
///
/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
///   [`shrink`], and
///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
///   directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
///   remains valid.
///
/// [`alloc`]: AllocRef::alloc
/// [`grow`]: AllocRef::grow
/// [`shrink`]: AllocRef::shrink
/// [`dealloc`]: AllocRef::dealloc
///
/// ### Memory fitting
///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold:
///
/// * The block must be allocated with the same alignment as [`layout.align()`], and
///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
///   - `min` is the size of the layout most recently used to allocate the block, and
///   - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
///
/// # Safety
///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
///   until the instance and all of its clones are dropped, and
///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this
///   allocator. A cloned allocator must behave like the same allocator.
///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
///   method of the allocator.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait AllocRef {
    /// On success, returns a memory block meeting the size and alignment guarantees of `layout`.
    ///
    /// The returned block may have a larger size than specified by `layout.size()` and is
    /// initialized as specified by [`init`], all the way up to the returned size of the block.
    ///
    /// [`init`]: AllocInit
    ///
    /// # Errors
    ///
    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    /// allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;

    /// Deallocates the memory denoted by `memory`.
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator, and
    /// * `layout` must [*fit*] the `ptr`.
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);

    /// Attempts to extend the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If `ReallocPlacement::MayMove` is used then ownership of the memory block referenced by `ptr`
    /// is transferred to this allocator. The memory may or may not be freed, and should be
    /// considered unusable (unless of course it is transferred back to the caller again via the
    /// return value of this method).
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The memory block will contain the following contents after a successful call to `grow`:
    ///   * Bytes `0..layout.size()` are preserved from the original allocation.
    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
    ///     that was originally requested when it was allocated.
    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
    ///     the size of the `MemoryBlock` returned by the `grow` call.
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    /// [`init`]: AllocInit
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly greater than `memory.size` or both are zero
    /// * `new_size` must be greater than or equal to `layout.size()`
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
    ///   (i.e., the rounded value must be less than or equal to `usize::MAX`).
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size >= size,
                    "`new_size` must be greater than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, init)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }

    /// Attempts to shrink the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    /// transferred to this allocator. The memory may or may not have been freed, and should be
    /// considered unusable unless it was transferred back to the caller again via the
    /// return value of this method.
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly smaller than `memory.size` or both are zero
    /// * `new_size` must be smaller than or equal to `layout.size()`
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size <= size,
                    "`new_size` must be smaller than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }
}
<|endoftext|>


<commit_before>use math::sqrtf;
use stepper::StepperMotor;
use utils::Point3;
use teensy3::bindings;

#[derive(Debug)]
pub struct CartesianMotionPlanner {
    x_motor: StepperMotor,
    y_motor: StepperMotor,
    z_motor: StepperMotor,
    max_acceleration: f32,
    max_speed: f32,
    motion_distance: f32,
    delta_x: f32,
    delta_y: f32,
    delta_z: f32,
    top_x_speed: f32,
    top_y_speed: f32,
    top_z_speed: f32,
    start_time: u32,
}

impl CartesianMotionPlanner {
    fn new(x_motor: StepperMotor,
           y_motor: StepperMotor,
           z_motor: StepperMotor,
           max_acceleration: f32,
           max_speed: f32)
           -> CartesianMotionPlanner {

        CartesianMotionPlanner {
            x_motor: x_motor,
            y_motor: y_motor,
            z_motor: z_motor,
            max_acceleration: max_acceleration,
            max_speed: max_speed,
            motion_distance: 0.0,
            delta_x: 0.0,
            delta_y: 0.0,
            delta_z: 0.0,
            top_x_speed: 0.0,
            top_y_speed: 0.0,
            top_z_speed: 0.0,
            start_time: 0,
        }
    }

    fn get_current_position(&self) -> Point3 {
        Point3::new(self.x_motor.get_current_position(),
                    self.y_motor.get_current_position(),
                    self.z_motor.get_current_position())
    }

    fn get_current_velocity(&self) -> Point3 {
        Point3::new(self.x_motor.get_current_velocity(),
                    self.y_motor.get_current_velocity(),
                    self.z_motor.get_current_velocity())
    }

    /*
    fn get_current_acceleration(&self) -> Point3 {
        Point3::new(self.x_motor.get_current_acceleration(),
                    self.y_motor.get_current_acceleration(),
                    self.z_motor.get_current_acceleration())
    }
    */

    fn set_target(&mut self, point: Point3, feed_rate: f32) {
        let current_position = self.get_current_position();
        self.delta_x = point.x - current_position.x;
        self.delta_y = point.y - current_position.y;
        self.delta_z = point.z - current_position.z;
        self.motion_distance = sqrtf(self.delta_x * self.delta_x + self.delta_y * self.delta_y +
                                     self.delta_z * self.delta_z);
        self.top_x_speed = self.translate_to_axis(self.delta_x,
                                                  self.get_axis_top_speed(self.delta_x, feed_rate));
        self.top_y_speed = self.translate_to_axis(self.delta_y,
                                                  self.get_axis_top_speed(self.delta_y, feed_rate));
        self.top_z_speed = self.translate_to_axis(self.delta_z,
                                                  self.get_axis_top_speed(self.delta_z, feed_rate));
        self.start_time = unsafe { bindings::micros() };
    }

    fn update(&mut self) {
        let now = unsafe { bindings::micros() } - self.start_time;
        let current_speed = now as f32 * self.max_acceleration;

    }

    fn get_axis_top_speed(&self, delta: f32, top_speed: f32) -> f32 {
        let speedup_distance = top_speed / self.max_acceleration;
        if speedup_distance < delta / 2.0 {
            (delta / 2.0) * self.max_acceleration
        } else {
            top_speed
        }
    }

    #[inline]
    fn translate_to_axis(&self, delta: f32, axis_speed: f32) -> f32 {
        (axis_speed * delta) / self.motion_distance
    }
}
<commit_msg>More math<commit_after>use math::sqrtf;
use stepper::StepperMotor;
use utils::Point3;
use teensy3::bindings;

#[derive(Debug)]
pub struct CartesianMotionPlanner {
    x_motor: StepperMotor,
    y_motor: StepperMotor,
    z_motor: StepperMotor,
    max_acceleration: f32,
    max_speed: f32,
    motion_distance: f32,
    delta_x: f32,
    delta_y: f32,
    delta_z: f32,
    top_x_speed: f32,
    top_y_speed: f32,
    top_z_speed: f32,
    start_time: u32,
    transition1: u32,
    transition2: u32,
    end_time: u32,
}

impl CartesianMotionPlanner {
    fn new(x_motor: StepperMotor,
           y_motor: StepperMotor,
           z_motor: StepperMotor,
           max_acceleration: f32,
           max_speed: f32)
           -> CartesianMotionPlanner {

        CartesianMotionPlanner {
            x_motor: x_motor,
            y_motor: y_motor,
            z_motor: z_motor,
            max_acceleration: max_acceleration,
            max_speed: max_speed,
            motion_distance: 0.0,
            delta_x: 0.0,
            delta_y: 0.0,
            delta_z: 0.0,
            top_x_speed: 0.0,
            top_y_speed: 0.0,
            top_z_speed: 0.0,
            start_time: 0,
            transition1: 0,
            transition2: 0,
            end_time: 0,
        }
    }

    fn get_current_position(&self) -> Point3 {
        Point3::new(self.x_motor.get_current_position(),
                    self.y_motor.get_current_position(),
                    self.z_motor.get_current_position())
    }

    fn get_current_velocity(&self) -> Point3 {
        Point3::new(self.x_motor.get_current_velocity(),
                    self.y_motor.get_current_velocity(),
                    self.z_motor.get_current_velocity())
    }

    // fn get_current_acceleration(&self) -> Point3 {
    // Point3::new(self.x_motor.get_current_acceleration(),
    // self.y_motor.get_current_acceleration(),
    // self.z_motor.get_current_acceleration())
    // }
    //

    fn set_target(&mut self, point: Point3, feed_rate: f32) {
        let current_position = self.get_current_position();
        self.delta_x = point.x - current_position.x;
        self.delta_y = point.y - current_position.y;
        self.delta_z = point.z - current_position.z;
        self.motion_distance = sqrtf(self.delta_x * self.delta_x + self.delta_y * self.delta_y +
                                     self.delta_z * self.delta_z);
        self.top_x_speed = self.translate_to_axis(self.delta_x,
                                                  self.get_axis_top_speed(self.delta_x, feed_rate));
        self.top_y_speed = self.translate_to_axis(self.delta_y,
                                                  self.get_axis_top_speed(self.delta_y, feed_rate));
        self.top_z_speed = self.translate_to_axis(self.delta_z,
                                                  self.get_axis_top_speed(self.delta_z, feed_rate));
        self.transition1 = (feed_rate / self.max_acceleration) as u32;

        self.start_time = unsafe { bindings::micros() };
    }

    fn update(&mut self) {
        let now = unsafe { bindings::micros() } - self.start_time;
        let current_speed = now as f32 * self.max_acceleration;
        if now < (self.top_x_speed * self.translate_to_axis(self.delta_x, self.max_acceleration)) as u32 {

        }
    }

    fn get_axis_top_speed(&self, delta: f32, top_speed: f32) -> f32 {
        let speedup_distance = top_speed / self.max_acceleration;
        if speedup_distance < delta / 2.0 {
            (delta / 2.0) * self.max_acceleration
        } else {
            top_speed
        }
    }

    #[inline]
    fn translate_to_axis(&self, delta: f32, axis_speed: f32) -> f32 {
        (axis_speed * delta) / self.motion_distance
    }
}
<|endoftext|>


<commit_before>//! Tidy check to ensure below in UI test directories:
//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
//! - there are no stray `.stderr` files

use std::fs;
use std::path::Path;

const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1580;
const ISSUES_ENTRY_LIMIT: usize = 2830;

fn check_entries(path: &Path, bad: &mut bool) {
    let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
        .into_iter()
        .filter_entry(|e| e.file_type().is_dir());
    for dir in dirs {
        if let Ok(dir) = dir {
            let dir_path = dir.path();

            // Use special values for these dirs.
            let is_root = path.join("test/ui") == dir_path;
            let is_issues_dir = path.join("test/ui/issues") == dir_path;
            let limit = if is_root {
                ROOT_ENTRY_LIMIT
            } else if is_issues_dir {
                ISSUES_ENTRY_LIMIT
            } else {
                ENTRY_LIMIT
            };

            let count = std::fs::read_dir(dir_path).unwrap().count();
            if count >= limit {
                tidy_error!(
                    bad,
                    "following path contains more than {} entries, \
                    you should move the test to some relevant subdirectory (current: {}): {}",
                    limit,
                    count,
                    dir_path.display()
                );
            }
        }
    }
}

pub fn check(path: &Path, bad: &mut bool) {
    check_entries(&path, bad);
    for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] {
        super::walk_no_read(path, &mut |_| false, &mut |entry| {
            let file_path = entry.path();
            if let Some(ext) = file_path.extension() {
                if ext == "stderr" || ext == "stdout" {
                    // Test output filenames have one of the formats:
                    // ```
                    // $testname.stderr
                    // $testname.$mode.stderr
                    // $testname.$revision.stderr
                    // $testname.$revision.$mode.stderr
                    // ```
                    //
                    // For now, just make sure that there is a corresponding
                    // `$testname.rs` file.
                    //
                    // NB: We do not use file_stem() as some file names have multiple `.`s and we
                    // must strip all of them.
                    let testname =
                        file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
                    if !file_path.with_file_name(testname).with_extension("rs").exists() {
                        tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
                    }

                    if let Ok(metadata) = fs::metadata(file_path) {
                        if metadata.len() == 0 {
                            tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
                        }
                    }
                }
            }
        });
    }
}
<commit_msg>Reduce `ROOT_ENTRY_LIMIT` to 1500<commit_after>//! Tidy check to ensure below in UI test directories:
//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
//! - there are no stray `.stderr` files

use std::fs;
use std::path::Path;

const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1500;
const ISSUES_ENTRY_LIMIT: usize = 2830;

fn check_entries(path: &Path, bad: &mut bool) {
    let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
        .into_iter()
        .filter_entry(|e| e.file_type().is_dir());
    for dir in dirs {
        if let Ok(dir) = dir {
            let dir_path = dir.path();

            // Use special values for these dirs.
            let is_root = path.join("test/ui") == dir_path;
            let is_issues_dir = path.join("test/ui/issues") == dir_path;
            let limit = if is_root {
                ROOT_ENTRY_LIMIT
            } else if is_issues_dir {
                ISSUES_ENTRY_LIMIT
            } else {
                ENTRY_LIMIT
            };

            let count = std::fs::read_dir(dir_path).unwrap().count();
            if count >= limit {
                tidy_error!(
                    bad,
                    "following path contains more than {} entries, \
                    you should move the test to some relevant subdirectory (current: {}): {}",
                    limit,
                    count,
                    dir_path.display()
                );
            }
        }
    }
}

pub fn check(path: &Path, bad: &mut bool) {
    check_entries(&path, bad);
    for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] {
        super::walk_no_read(path, &mut |_| false, &mut |entry| {
            let file_path = entry.path();
            if let Some(ext) = file_path.extension() {
                if ext == "stderr" || ext == "stdout" {
                    // Test output filenames have one of the formats:
                    // ```
                    // $testname.stderr
                    // $testname.$mode.stderr
                    // $testname.$revision.stderr
                    // $testname.$revision.$mode.stderr
                    // ```
                    //
                    // For now, just make sure that there is a corresponding
                    // `$testname.rs` file.
                    //
                    // NB: We do not use file_stem() as some file names have multiple `.`s and we
                    // must strip all of them.
                    let testname =
                        file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
                    if !file_path.with_file_name(testname).with_extension("rs").exists() {
                        tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
                    }

                    if let Ok(metadata) = fs::metadata(file_path) {
                        if metadata.len() == 0 {
                            tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
                        }
                    }
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>use serde_json::from_reader;
use std::path::Path;
use std::fs::File;

use id::Id;
use linear::{Matrix4, Quaternion, ToHomogeneous, Unit};
use model::Model;
use resource::{Cache, Get, Load, LoadError};
use transform::{Orientation, Position, Scale, Transformable, translation_matrix};

pub struct Object<'a> {
  pub model: Id<'a, Model>,
  pub position: Position,
  pub orientation: Orientation,
  pub scale: Scale
}

impl<'a> Transformable for Object<'a> {
  fn transform(&self) -> Matrix4<f32> {
    translation_matrix(-self.position) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous()
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ObjectManifest {
  model: String,
  position: [f32; 3],
  orientation: [f32; 4],
  scale: [f32; 3]
}

impl<'a> Load<'a> for Object<'a> {
  type Args = ();

  fn load<P>(path: P, cache: &mut Cache<'a>, _: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading object {:?}", path);

    // read the manifest
    let manifest: ObjectManifest = {
      let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    // get the model id
    let model_id = cache.get_id(&manifest.model, ()).ok_or(LoadError::ConversionFailed(format!("unable to find model {} for object at {:?}", manifest.model, path)))?;

    Ok(Object {
      model: model_id,
      position: (&manifest.position).into(),
      orientation: Unit::new(&Quaternion::from(&manifest.orientation)),
      scale: (&manifest.scale).into()
    })
  }
}
<commit_msg>Added default position, orientation and scale for serializing ObjectManifest.<commit_after>use serde_json::from_reader;
use std::path::Path;
use std::fs::File;

use id::Id;
use linear::{Matrix4, Quaternion, ToHomogeneous, Unit};
use model::Model;
use resource::{Cache, Get, Load, LoadError};
use transform::{Orientation, Position, Scale, Transformable, translation_matrix};

pub struct Object<'a> {
  pub model: Id<'a, Model>,
  pub position: Position,
  pub orientation: Orientation,
  pub scale: Scale
}

impl<'a> Transformable for Object<'a> {
  fn transform(&self) -> Matrix4<f32> {
    translation_matrix(-self.position) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous()
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ObjectManifest {
  model: String,
  #[serde(default = "def_position")]
  position: [f32; 3],
  #[serde(default = "def_orientation")]
  orientation: [f32; 4],
  #[serde(default = "def_scale")]
  scale: [f32; 3]
}

impl<'a> Load<'a> for Object<'a> {
  type Args = ();

  fn load<P>(path: P, cache: &mut Cache<'a>, _: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading object {:?}", path);

    // read the manifest
    let manifest: ObjectManifest = {
      let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    // get the model id
    let model_id = cache.get_id(&manifest.model, ()).ok_or(LoadError::ConversionFailed(format!("unable to find model {} for object at {:?}", manifest.model, path)))?;

    Ok(Object {
      model: model_id,
      position: (&manifest.position).into(),
      orientation: Unit::new(&Quaternion::from(&manifest.orientation)),
      scale: (&manifest.scale).into()
    })
  }
}

fn def_position() -> [f32; 3] { [0., 0., 0.] }
fn def_orientation() -> [f32; 4] { [1., 0., 0., 0.] }
fn def_scale() -> [f32; 3] { [1., 1., 1.] }
<|endoftext|>