<commit_before>use std::io::{Result, Write};

use analysis;
use analysis::symbols;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use writer::primitives;

use stripper_interface as stripper;
use stripper_interface::Type as SType;
use stripper_interface::TypeStruct;
use stripper_interface::{FILE, /*FILE_COMMENT, */MOD_COMMENT};

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> stripper::TypeStruct;
    fn doc(&self) -> Option<String>;
    fn doc_deprecated(&self) -> Option<String>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<String> {
                self.doc.clone()
            }

            fn doc_deprecated(&self) -> Option<String> {
                self.doc_deprecated.clone()
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Type);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("doc.cmts");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(writeln!(w, "{}*", FILE));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        if let Some(info) = info {
            try!(create_object_doc(w, env, &info));
        }
    }

    let symbols = env.symbols.borrow();
    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, &symbols));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, symbols: &symbols::Info) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, symbols),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, symbols),
        LType::Function(ref f) => create_fn_doc(w, &f, None, symbols),
        _ => Ok(()),
    }
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let tabs = "";
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &format!("{}Ext", info.name));
    let has_trait = info.has_children;
    let class: &ToStripperType;
    let functions: &[Function];
    let implements: Vec<TypeId>;

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            class = cl;
            functions = &cl.functions;
            implements = cl.parents.iter()
                .chain(cl.implements.iter())
                .map(|&tid| tid)
                .collect();
        }
        Type::Interface(ref iface) => {
            class = iface;
            functions = &iface.functions;
            implements = iface.prereq_parents.clone();
        }
        _ => unreachable!(),
    }

    try!(writeln!(w, "{}{}", MOD_COMMENT, ty));

    if let Some(ref class_doc) = class.doc() {
        try!(write_lines(w, &class_doc, &tabs, &symbols));
    }

    try!(write_header(w, &tabs, "Implements"));
    let implements = implements.iter()
        .filter(|&tid| !env.type_status(&tid.full_name(&env.library)).ignored())
        .map(|&tid| format!("`{}Ext`", env.library.type_(tid).get_name()))
        .collect::<Vec<_>>();
    try!(write_verbatim(w, &implements.join(", "), &tabs));

    if let Some(ref class_doc) = class.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &class_doc, &tabs, &symbols));
    }

    if has_trait {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty_ext));
        try!(write_verbatim(w, &format!("Trait containing all `{}` methods.", ty.name), &tabs));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), &symbols));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration, symbols: &symbols::Info) -> Result<()> {
    let ty = enum_.convert();
    let tabs = "";

    if enum_.doc().is_some() || enum_.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty));
    }

    if let Some(ref enum_doc) = enum_.doc() {
        try!(write_lines(w, &enum_doc, &tabs, symbols));
    }
    if let Some(ref enum_doc) = enum_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &enum_doc, &tabs, symbols));
    }

    let tabs = "\t";
    for member_doc in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member_doc.convert();

        if member_doc.doc().is_some() || member_doc.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
        }
        if let Some(ref m_doc) = member_doc.doc() {
            try!(write_lines(w, &m_doc, &tabs, symbols));
        }
        if let Some(ref m_doc) = member_doc.doc_deprecated() {
            try!(write_header(w, &tabs, "Deprecated"));
            try!(write_lines(w, &m_doc, &tabs, symbols));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names(doc: &str, self_name: &Option<String>) -> String {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into()
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 symbols: &symbols::Info) -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent) + 1);

    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;

    let self_name: Option<String> = fn_.parameters.iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));

    if let Some(ref docs) = fn_.doc() {
        try!(write_lines(w, &fix_param_names(docs, &self_name), &tabs, symbols));
    };
    if let Some(ref docs) = fn_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &fix_param_names(docs, &self_name), &tabs, symbols));
    };

    if fn_.parameters.iter().any(|x| {
           x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
       }) {
        try!(write_header(w, &tabs, "Parameters"));
    }
    for parameter in fn_.parameters.iter() {
        if parameter.instance_parameter || parameter.name.is_empty() {
            continue
        }
        if let Some(ref parameter_doc) = parameter.doc() {
            try!(writeln!(w, "{}/// ## {}:", tabs, parameter.name));
            try!(write_lines(w, &fix_param_names(parameter_doc, &self_name), &tabs, symbols));
        }
    }

    if let Some(ref doc) = fn_.ret.doc() {
        try!(write_header(w, &tabs, "Returns"));
        try!(write_lines(w, &fix_param_names(doc, &self_name), &tabs, symbols));
    }
    Ok(())
}

fn write_lines(w: &mut Write, lines: &str, tabs: &str, symbols: &symbols::Info) -> Result<()> {
    write_verbatim(w, &format::reformat_doc(&lines, symbols), tabs)
}

fn write_verbatim(w: &mut Write, lines: &str, tabs: &str) -> Result<()> {
    for line in lines.split("\n") {
        try!(writeln!(w, "{}/// {}", tabs, line));
    }
    Ok(())
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T, symbols: &symbols::Info) -> Result<()> {
    let tabs = "";
    let sub_ty = ty.convert();

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
    }

    if let Some(doc) = ty.doc() {
        try!(write_lines(w, &doc, &tabs, symbols));
    }
    if let Some(doc) = ty.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &doc, &tabs, symbols));
    }
    Ok(())
}

fn compute_indent(e: &Option<Box<TypeStruct>>) -> usize {
    match *e {
        Some(ref e) if e.parent.is_some() => compute_indent(&e.parent) + 1,
        _ => 0,
    }
}

fn write_header(w: &mut Write, tabs: &str, header: &str) -> Result<()> {
    writeln!(w, "{0}///\n{0}/// # {1}\n{0}///", tabs, header)
}
<commit_msg>Change parameter heading formatting<commit_after>use std::io::{Result, Write};

use analysis;
use analysis::symbols;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use writer::primitives;

use stripper_interface as stripper;
use stripper_interface::Type as SType;
use stripper_interface::TypeStruct;
use stripper_interface::{FILE, /*FILE_COMMENT, */MOD_COMMENT};

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> stripper::TypeStruct;
    fn doc(&self) -> Option<String>;
    fn doc_deprecated(&self) -> Option<String>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<String> {
                self.doc.clone()
            }

            fn doc_deprecated(&self) -> Option<String> {
                self.doc_deprecated.clone()
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Type);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("doc.cmts");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(writeln!(w, "{}*", FILE));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        if let Some(info) = info {
            try!(create_object_doc(w, env, &info));
        }
    }

    let symbols = env.symbols.borrow();
    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, &symbols));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, symbols: &symbols::Info) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, symbols),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, symbols),
        LType::Function(ref f) => create_fn_doc(w, &f, None, symbols),
        _ => Ok(()),
    }
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let tabs = "";
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &format!("{}Ext", info.name));
    let has_trait = info.has_children;
    let class: &ToStripperType;
    let functions: &[Function];
    let implements: Vec<TypeId>;

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            class = cl;
            functions = &cl.functions;
            implements = cl.parents.iter()
                .chain(cl.implements.iter())
                .map(|&tid| tid)
                .collect();
        }
        Type::Interface(ref iface) => {
            class = iface;
            functions = &iface.functions;
            implements = iface.prereq_parents.clone();
        }
        _ => unreachable!(),
    }

    try!(writeln!(w, "{}{}", MOD_COMMENT, ty));

    if let Some(ref class_doc) = class.doc() {
        try!(write_lines(w, &class_doc, &tabs, &symbols));
    }

    try!(write_header(w, &tabs, "Implements"));
    let implements = implements.iter()
        .filter(|&tid| !env.type_status(&tid.full_name(&env.library)).ignored())
        .map(|&tid| format!("`{}Ext`", env.library.type_(tid).get_name()))
        .collect::<Vec<_>>();
    try!(write_verbatim(w, &implements.join(", "), &tabs));

    if let Some(ref class_doc) = class.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &class_doc, &tabs, &symbols));
    }

    if has_trait {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty_ext));
        try!(write_verbatim(w, &format!("Trait containing all `{}` methods.", ty.name), &tabs));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), &symbols));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration, symbols: &symbols::Info) -> Result<()> {
    let ty = enum_.convert();
    let tabs = "";

    if enum_.doc().is_some() || enum_.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty));
    }

    if let Some(ref enum_doc) = enum_.doc() {
        try!(write_lines(w, &enum_doc, &tabs, symbols));
    }
    if let Some(ref enum_doc) = enum_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &enum_doc, &tabs, symbols));
    }

    let tabs = "\t";
    for member_doc in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member_doc.convert();

        if member_doc.doc().is_some() || member_doc.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
        }
        if let Some(ref m_doc) = member_doc.doc() {
            try!(write_lines(w, &m_doc, &tabs, symbols));
        }
        if let Some(ref m_doc) = member_doc.doc_deprecated() {
            try!(write_header(w, &tabs, "Deprecated"));
            try!(write_lines(w, &m_doc, &tabs, symbols));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names(doc: &str, self_name: &Option<String>) -> String {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into()
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 symbols: &symbols::Info) -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent) + 1);

    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;

    let self_name: Option<String> = fn_.parameters.iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));

    if let Some(ref docs) = fn_.doc() {
        try!(write_lines(w, &fix_param_names(docs, &self_name), &tabs, symbols));
    };
    if let Some(ref docs) = fn_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &fix_param_names(docs, &self_name), &tabs, symbols));
    };

    if fn_.parameters.iter().any(|x| {
           x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
       }) {
        try!(write_header(w, &tabs, "Parameters"));
    }
    for parameter in fn_.parameters.iter() {
        if parameter.instance_parameter || parameter.name.is_empty() {
            continue
        }
        if let Some(ref parameter_doc) = parameter.doc() {
            try!(writeln!(w, "{}/// ## `{}`", tabs,
                          nameutil::mangle_keywords(&parameter.name[..])));
            try!(write_lines(w, &fix_param_names(parameter_doc, &self_name), &tabs, symbols));
        }
    }

    if let Some(ref doc) = fn_.ret.doc() {
        try!(write_header(w, &tabs, "Returns"));
        try!(write_lines(w, &fix_param_names(doc, &self_name), &tabs, symbols));
    }
    Ok(())
}

fn write_lines(w: &mut Write, lines: &str, tabs: &str, symbols: &symbols::Info) -> Result<()> {
    write_verbatim(w, &format::reformat_doc(&lines, symbols), tabs)
}

fn write_verbatim(w: &mut Write, lines: &str, tabs: &str) -> Result<()> {
    for line in lines.split("\n") {
        try!(writeln!(w, "{}/// {}", tabs, line));
    }
    Ok(())
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T, symbols: &symbols::Info) -> Result<()> {
    let tabs = "";
    let sub_ty = ty.convert();

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
    }

    if let Some(doc) = ty.doc() {
        try!(write_lines(w, &doc, &tabs, symbols));
    }
    if let Some(doc) = ty.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &doc, &tabs, symbols));
    }
    Ok(())
}

fn compute_indent(e: &Option<Box<TypeStruct>>) -> usize {
    match *e {
        Some(ref e) if e.parent.is_some() => compute_indent(&e.parent) + 1,
        _ => 0,
    }
}

fn write_header(w: &mut Write, tabs: &str, header: &str) -> Result<()> {
    writeln!(w, "{0}///\n{0}/// # {1}\n{0}///", tabs, header)
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use time::Timespec;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use diesel::pg::PgConnection;
use diesel::prelude::*;
use diesel;
use pg::rows::Row;

use {Model, Crate};
use db::RequestTransaction;
use pagination::Paginate;
use schema::*;
use util::{RequestUtils, CargoResult};

#[derive(Clone, Identifiable, Queryable, Debug)]
pub struct Keyword {
    pub id: i32,
    pub keyword: String,
    pub crates_cnt: i32,
    pub created_at: Timespec,
}

#[derive(Associations, Insertable, Identifiable, Debug, Clone, Copy)]
#[belongs_to(Keyword)]
#[belongs_to(Crate)]
#[table_name = "crates_keywords"]
#[primary_key(crate_id, keyword_id)]
pub struct CrateKeyword {
    crate_id: i32,
    keyword_id: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableKeyword {
    pub id: String,
    pub keyword: String,
    pub created_at: String,
    pub crates_cnt: i32,
}

impl Keyword {
    pub fn find_by_keyword(conn: &PgConnection, name: &str) -> QueryResult<Keyword> {
        keywords::table
            .filter(keywords::keyword.eq(::lower(name)))
            .first(&*conn)
    }

    pub fn find_or_create_all(conn: &PgConnection, names: &[&str]) -> QueryResult<Vec<Keyword>> {
        use diesel::pg::upsert::*;
        use diesel::expression::dsl::any;

        #[derive(Insertable, Debug)]
        #[table_name = "keywords"]
        struct NewKeyword<'a> {
            keyword: &'a str,
        }

        let lowercase_names: Vec<_> = names.iter().map(|s| s.to_lowercase()).collect();

        let new_keywords: Vec<_> = lowercase_names
            .iter()
            .map(|s| NewKeyword { keyword: s })
            .collect();

        // https://github.com/diesel-rs/diesel/issues/797
        if !new_keywords.is_empty() {
            diesel::insert(&new_keywords.on_conflict_do_nothing())
                .into(keywords::table)
                .execute(conn)?;
        }
        keywords::table
            .filter(keywords::keyword.eq(any(&lowercase_names)))
            .load(conn)
    }

    pub fn valid_name(name: &str) -> bool {
        if name.is_empty() {
            return false;
        }
        name.chars().next().unwrap().is_alphanumeric() &&
            name.chars().all(
                |c| c.is_alphanumeric() || c == '_' || c == '-',
            ) && name.chars().all(|c| c.is_ascii())
    }

    pub fn encodable(self) -> EncodableKeyword {
        let Keyword {
            crates_cnt,
            keyword,
            created_at,
            ..
        } = self;
        EncodableKeyword {
            id: keyword.clone(),
            created_at: ::encode_time(created_at),
            crates_cnt: crates_cnt,
            keyword: keyword,
        }
    }

    pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> {
        conn.transaction(|| {
            let keywords = Keyword::find_or_create_all(conn, keywords)?;
            diesel::delete(CrateKeyword::belonging_to(krate)).execute(
                conn,
            )?;
            let crate_keywords = keywords
                .into_iter()
                .map(|kw| {
                    CrateKeyword {
                        crate_id: krate.id,
                        keyword_id: kw.id,
                    }
                })
                .collect::<Vec<_>>();
            diesel::insert(&crate_keywords)
                .into(crates_keywords::table)
                .execute(conn)?;
            Ok(())
        })
    }
}

impl Model for Keyword {
    fn from_row(row: &Row) -> Keyword {
        Keyword {
            id: row.get("id"),
            created_at: row.get("created_at"),
            crates_cnt: row.get("crates_cnt"),
            keyword: row.get("keyword"),
        }
    }
    fn table_name(_: Option<Keyword>) -> &'static str {
        "keywords"
    }
}

/// Handles the `GET /keywords` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    use schema::keywords;

    let conn = req.db_conn()?;
    let (offset, limit) = req.pagination(10, 100)?;
    let query = req.query();
    let sort = query.get("sort").map(|s| &s[..]).unwrap_or("alpha");

    let mut query = keywords::table.into_boxed();

    if sort == "crates" {
        query = query.order(keywords::crates_cnt.desc());
    } else {
        query = query.order(keywords::keyword.asc());
    }

    let data = query.paginate(limit, offset).load::<(Keyword, i64)>(&*conn)?;
    let total = data.get(0).map(|&(_, t)| t).unwrap_or(0);
    let kws = data.into_iter()
        .map(|(k, _)| k.encodable())
        .collect::<Vec<_>>();

    #[derive(Serialize)]
    struct R {
        keywords: Vec<EncodableKeyword>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        total: i64,
    }

    Ok(req.json(&R {
        keywords: kws,
        meta: Meta { total: total },
    }))
}

/// Handles the `GET /keywords/:keyword_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let name = &req.params()["keyword_id"];
    let conn = req.db_conn()?;

    let kw = Keyword::find_by_keyword(&conn, name)?;

    #[derive(Serialize)]
    struct R {
        keyword: EncodableKeyword,
    }
    Ok(req.json(&R { keyword: kw.encodable() }))
}

#[cfg(test)]
mod tests {
    use super::*;
    use dotenv::dotenv;
    use std::env;
    use diesel;
    use diesel::connection::SimpleConnection;

    #[derive(Insertable)]
    #[table_name = "keywords"]
    struct NewKeyword<'a> {
        keyword: &'a str,
    }

    fn pg_connection() -> PgConnection {
        let _ = dotenv();
        let database_url =
            env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
        let conn = PgConnection::establish(&database_url).unwrap();
        // These tests deadlock if run concurrently
        conn.batch_execute("BEGIN;").unwrap();
        conn
    }

    #[test]
    fn dont_associate_with_non_lowercased_keywords() {
        let conn = pg_connection();
        // The code should be preventing lowercased keywords from existing,
        // but if one happens to sneak in there, don't associate crates with it.
        let bad_keyword = NewKeyword { keyword: "NO" };

        diesel::insert(&bad_keyword)
            .into(keywords::table)
            .execute(&conn)
            .unwrap();

        let associated = Keyword::find_or_create_all(&conn, &["no"]).unwrap();
        assert_eq!(associated.len(), 1);
        assert_eq!(associated.first().unwrap().keyword, "no");
    }
}
<commit_msg>Derive Debug and Copy for NewKeyword<commit_after>use std::ascii::AsciiExt;
use time::Timespec;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use diesel::pg::PgConnection;
use diesel::prelude::*;
use diesel;
use pg::rows::Row;

use {Model, Crate};
use db::RequestTransaction;
use pagination::Paginate;
use schema::*;
use util::{RequestUtils, CargoResult};

#[derive(Clone, Identifiable, Queryable, Debug)]
pub struct Keyword {
    pub id: i32,
    pub keyword: String,
    pub crates_cnt: i32,
    pub created_at: Timespec,
}

#[derive(Associations, Insertable, Identifiable, Debug, Clone, Copy)]
#[belongs_to(Keyword)]
#[belongs_to(Crate)]
#[table_name = "crates_keywords"]
#[primary_key(crate_id, keyword_id)]
pub struct CrateKeyword {
    crate_id: i32,
    keyword_id: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableKeyword {
    pub id: String,
    pub keyword: String,
    pub created_at: String,
    pub crates_cnt: i32,
}

impl Keyword {
    pub fn find_by_keyword(conn: &PgConnection, name: &str) -> QueryResult<Keyword> {
        keywords::table
            .filter(keywords::keyword.eq(::lower(name)))
            .first(&*conn)
    }

    pub fn find_or_create_all(conn: &PgConnection, names: &[&str]) -> QueryResult<Vec<Keyword>> {
        use diesel::pg::upsert::*;
        use diesel::expression::dsl::any;

        #[derive(Insertable, Debug, Clone, Copy)]
        #[table_name = "keywords"]
        struct NewKeyword<'a> {
            keyword: &'a str,
        }

        let lowercase_names: Vec<_> = names.iter().map(|s| s.to_lowercase()).collect();

        let new_keywords: Vec<_> = lowercase_names
            .iter()
            .map(|s| NewKeyword { keyword: s })
            .collect();

        // https://github.com/diesel-rs/diesel/issues/797
        if !new_keywords.is_empty() {
            diesel::insert(&new_keywords.on_conflict_do_nothing())
                .into(keywords::table)
                .execute(conn)?;
        }
        keywords::table
            .filter(keywords::keyword.eq(any(&lowercase_names)))
            .load(conn)
    }

    pub fn valid_name(name: &str) -> bool {
        if name.is_empty() {
            return false;
        }
        name.chars().next().unwrap().is_alphanumeric() &&
            name.chars().all(
                |c| c.is_alphanumeric() || c == '_' || c == '-',
            ) && name.chars().all(|c| c.is_ascii())
    }

    pub fn encodable(self) -> EncodableKeyword {
        let Keyword {
            crates_cnt,
            keyword,
            created_at,
            ..
        } = self;
        EncodableKeyword {
            id: keyword.clone(),
            created_at: ::encode_time(created_at),
            crates_cnt: crates_cnt,
            keyword: keyword,
        }
    }

    pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> {
        conn.transaction(|| {
            let keywords = Keyword::find_or_create_all(conn, keywords)?;
            diesel::delete(CrateKeyword::belonging_to(krate)).execute(
                conn,
            )?;
            let crate_keywords = keywords
                .into_iter()
                .map(|kw| {
                    CrateKeyword {
                        crate_id: krate.id,
                        keyword_id: kw.id,
                    }
                })
                .collect::<Vec<_>>();
            diesel::insert(&crate_keywords)
                .into(crates_keywords::table)
                .execute(conn)?;
            Ok(())
        })
    }
}

impl Model for Keyword {
    fn from_row(row: &Row) -> Keyword {
        Keyword {
            id: row.get("id"),
            created_at: row.get("created_at"),
            crates_cnt: row.get("crates_cnt"),
            keyword: row.get("keyword"),
        }
    }
    fn table_name(_: Option<Keyword>) -> &'static str {
        "keywords"
    }
}

/// Handles the `GET /keywords` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    use schema::keywords;

    let conn = req.db_conn()?;
    let (offset, limit) = req.pagination(10, 100)?;
    let query = req.query();
    let sort = query.get("sort").map(|s| &s[..]).unwrap_or("alpha");

    let mut query = keywords::table.into_boxed();

    if sort == "crates" {
        query = query.order(keywords::crates_cnt.desc());
    } else {
        query = query.order(keywords::keyword.asc());
    }

    let data = query.paginate(limit, offset).load::<(Keyword, i64)>(&*conn)?;
    let total = data.get(0).map(|&(_, t)| t).unwrap_or(0);
    let kws = data.into_iter()
        .map(|(k, _)| k.encodable())
        .collect::<Vec<_>>();

    #[derive(Serialize)]
    struct R {
        keywords: Vec<EncodableKeyword>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        total: i64,
    }

    Ok(req.json(&R {
        keywords: kws,
        meta: Meta { total: total },
    }))
}

/// Handles the `GET /keywords/:keyword_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let name = &req.params()["keyword_id"];
    let conn = req.db_conn()?;

    let kw = Keyword::find_by_keyword(&conn, name)?;

    #[derive(Serialize)]
    struct R {
        keyword: EncodableKeyword,
    }
    Ok(req.json(&R { keyword: kw.encodable() }))
}

#[cfg(test)]
mod tests {
    use super::*;
    use dotenv::dotenv;
    use std::env;
    use diesel;
    use diesel::connection::SimpleConnection;

    #[derive(Insertable, Debug, Clone, Copy)]
    #[table_name = "keywords"]
    struct NewKeyword<'a> {
        keyword: &'a str,
    }

    fn pg_connection() -> PgConnection {
        let _ = dotenv();
        let database_url =
            env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
        let conn = PgConnection::establish(&database_url).unwrap();
        // These tests deadlock if run concurrently
        conn.batch_execute("BEGIN;").unwrap();
        conn
    }

    #[test]
    fn dont_associate_with_non_lowercased_keywords() {
        let conn = pg_connection();
        // The code should be preventing lowercased keywords from existing,
        // but if one happens to sneak in there, don't associate crates with it.
        let bad_keyword = NewKeyword { keyword: "NO" };

        diesel::insert(&bad_keyword)
            .into(keywords::table)
            .execute(&conn)
            .unwrap();

        let associated = Keyword::find_or_create_all(&conn, &["no"]).unwrap();
        assert_eq!(associated.len(), 1);
        assert_eq!(associated.first().unwrap().keyword, "no");
    }
}
<|endoftext|>


<commit_before>extern crate tabwriter;

use std::fmt;
use std::io::Write;
use std::str::FromStr;
use self::tabwriter::TabWriter;

use super::tree::FSNode;

pub fn print_tree(tree: &FSNode, max_depth: i64, max_dir_entries: i64, size_format: SizeFormat) {
    let mut tw = TabWriter::new(Vec::new());

    print_tree_impl(tree, &mut tw, "", 0, max_depth, max_dir_entries, size_format);

    tw.flush().unwrap();
    let bytes = tw.into_inner().unwrap();
    let tabulated = String::from_utf8_lossy(&bytes);

	print!("{}", tabulated);
}

const SUM: &'static str = "(Σ)";
const BRANCH: &'static str = "├── ";
const LAST_BRANCH: &'static str = "└── ";
const INDENT: &'static str = "    ";
const NESTED_INDENT: &'static str = "│   ";

fn print_tree_impl<T: Write>(node: &FSNode, mut tw: &mut TabWriter<T>, prefix: &str, depth: i64, max_depth: i64, max_dir_entries: i64, size_format: SizeFormat) {
    let sum_suffix = if node.is_dir() {
        SUM
    } else {
        ""
    };

    writeln!(&mut tw,
             "{}\t{}\t{}",
             node.name(),
             size_format.human_readable_byte_size(node.size()),
             sum_suffix,
             )
        .unwrap();

    if max_depth < 0 || max_depth >= depth {
        let mut size_not_shown: u64 = 0;
        for (idx, item) in node.children().enumerate() {
            let last = idx == (node.children().count() - 1);
            let (branch, nested) = if last {
                (LAST_BRANCH, INDENT)
            } else {
                (BRANCH, NESTED_INDENT)
            };

            if max_dir_entries < 0 || (idx as i64) < max_dir_entries {
                write!(&mut tw, "{}{}", prefix, branch).unwrap();

                let nested_prefix = format!("{}{}", prefix, nested);
                print_tree_impl(item, &mut tw, &nested_prefix, depth + 1, max_depth, max_dir_entries, size_format);
            } else {
                size_not_shown += item.size();

                if last {
                    let _ = writeln!(&mut tw, "{}{}...\t{}\t{}", prefix, branch, size_format.human_readable_byte_size(size_not_shown), SUM);
                }
            }

        }
    }
}

#[derive(Copy, Clone)]
pub enum SizeFormat {
    Human,
    Si,
    Raw,
}

impl FromStr for SizeFormat {
    type Err = ();

    fn from_str(s: &str) -> Result<SizeFormat, ()> {
        match s {
            "h" | "human" => Ok(SizeFormat::Human),
            "H" | "si" => Ok(SizeFormat::Si),
            "r" | "raw" => Ok(SizeFormat::Raw),
            _ => Err(()),
        }
    }
}

impl SizeFormat {
    pub const VALUES: &'static [&'static str] = &["h", "human", "H", "si", "r", "raw"];

    pub fn human_readable_byte_size(self, bytes: u64) -> SizeFormatter {
        SizeFormatter(self, bytes)
    }
}

pub struct SizeFormatter(SizeFormat, u64);

impl fmt::Display for SizeFormatter {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        static HUMAN_PREFIX: &[&str] = &["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
        static SI_PREFIX: &[&str] = &["B", "KB", "MB", "GB", "TB", "PB", "EB"];

        let (power, prefix) = match self.0 {
            SizeFormat::Human => (1024, HUMAN_PREFIX),
            SizeFormat::Si => (1000, SI_PREFIX),
            SizeFormat::Raw => return self.fmt_raw(f),
        };

        if self.1 < power {
            return self.fmt_raw(f);
        }

        let which = log2(self.1) / 10;
        let decimal = self.1 as f64 / (power as f64).powf(which as f64);
        write!(f, "{:.1}\t{}", decimal, prefix[which as usize])
    }
}

impl SizeFormatter {
    fn fmt_raw(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}\tB", self.1)
    }
}

fn log2(mut x: u64) -> u64 {
    let mut n: u64 = 0;

    while (x >> 1) > 0 {
        x >>= 1;
        n += 1;
    }
    n
}
<commit_msg>Fix prefix choice for SI format<commit_after>extern crate tabwriter;

use std::fmt;
use std::io::Write;
use std::str::FromStr;
use self::tabwriter::TabWriter;

use super::tree::FSNode;

pub fn print_tree(tree: &FSNode, max_depth: i64, max_dir_entries: i64, size_format: SizeFormat) {
    let mut tw = TabWriter::new(Vec::new());

    print_tree_impl(tree, &mut tw, "", 0, max_depth, max_dir_entries, size_format);

    tw.flush().unwrap();
    let bytes = tw.into_inner().unwrap();
    let tabulated = String::from_utf8_lossy(&bytes);

	print!("{}", tabulated);
}

const SUM: &'static str = "(Σ)";
const BRANCH: &'static str = "├── ";
const LAST_BRANCH: &'static str = "└── ";
const INDENT: &'static str = "    ";
const NESTED_INDENT: &'static str = "│   ";

fn print_tree_impl<T: Write>(node: &FSNode, mut tw: &mut TabWriter<T>, prefix: &str, depth: i64, max_depth: i64, max_dir_entries: i64, size_format: SizeFormat) {
    let sum_suffix = if node.is_dir() {
        SUM
    } else {
        ""
    };

    writeln!(&mut tw,
             "{}\t{}\t{}",
             node.name(),
             size_format.human_readable_byte_size(node.size()),
             sum_suffix,
             )
        .unwrap();

    if max_depth < 0 || max_depth >= depth {
        let mut size_not_shown: u64 = 0;
        for (idx, item) in node.children().enumerate() {
            let last = idx == (node.children().count() - 1);
            let (branch, nested) = if last {
                (LAST_BRANCH, INDENT)
            } else {
                (BRANCH, NESTED_INDENT)
            };

            if max_dir_entries < 0 || (idx as i64) < max_dir_entries {
                write!(&mut tw, "{}{}", prefix, branch).unwrap();

                let nested_prefix = format!("{}{}", prefix, nested);
                print_tree_impl(item, &mut tw, &nested_prefix, depth + 1, max_depth, max_dir_entries, size_format);
            } else {
                size_not_shown += item.size();

                if last {
                    let _ = writeln!(&mut tw, "{}{}...\t{}\t{}", prefix, branch, size_format.human_readable_byte_size(size_not_shown), SUM);
                }
            }

        }
    }
}

#[derive(Copy, Clone)]
pub enum SizeFormat {
    Human,
    Si,
    Raw,
}

impl FromStr for SizeFormat {
    type Err = ();

    fn from_str(s: &str) -> Result<SizeFormat, ()> {
        match s {
            "h" | "human" => Ok(SizeFormat::Human),
            "H" | "si" => Ok(SizeFormat::Si),
            "r" | "raw" => Ok(SizeFormat::Raw),
            _ => Err(()),
        }
    }
}

impl SizeFormat {
    pub const VALUES: &'static [&'static str] = &["h", "human", "H", "si", "r", "raw"];

    pub fn human_readable_byte_size(self, bytes: u64) -> SizeFormatter {
        SizeFormatter(self, bytes)
    }
}

pub struct SizeFormatter(SizeFormat, u64);

impl fmt::Display for SizeFormatter {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        static HUMAN_PREFIX: &[&str] = &["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
        static SI_PREFIX: &[&str] = &["B", "KB", "MB", "GB", "TB", "PB", "EB"];

        let (power, prefix, which) = match self.0 {
            SizeFormat::Human => (1024, HUMAN_PREFIX, log2(self.1) / 10),
            SizeFormat::Si => (1000, SI_PREFIX, log10(self.1) / 3),
            SizeFormat::Raw => return self.fmt_raw(f),
        };

        if which == 0 {
            return self.fmt_raw(f);
        }

        let decimal = self.1 as f64 / (power as f64).powf(which as f64);
        write!(f, "{:.1}\t{}", decimal, prefix[which as usize])
    }
}

impl SizeFormatter {
    fn fmt_raw(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}\tB", self.1)
    }
}

fn log2(mut x: u64) -> u64 {
    let mut n: u64 = 0;

    while (x >> 1) > 0 {
        x >>= 1;
        n += 1;
    }
    n
}

fn log10(mut x: u64) -> u64 {
    let mut n: u64 = 0;

    while (x / 10) > 0 {
        x /= 10;
        n += 1;
    }
    n
}
<|endoftext|>


<commit_before>use common::take_cell::TakeCell;
use process::{AppId, AppSlice, Container, Callback, Shared};
use hil::Driver;
use hil::uart::{UART, Client};

pub struct App {
    read_callback: Option<Callback>,
    write_callback: Option<Callback>,
    read_buffer: Option<AppSlice<Shared, u8>>,
    write_buffer: Option<AppSlice<Shared, u8>>,
    write_len: usize,
    pending_write: bool,
    read_idx: usize
}

impl Default for App {
    fn default() -> App {
        App {
            read_callback: None,
            write_callback: None,
            read_buffer: None,
            write_buffer: None,
            write_len: 0,
            pending_write: false,
            read_idx: 0
        }
    }
}

pub static mut WRITE_BUF : [u8; 64] = [0; 64];

pub struct Console<'a, U: UART + 'a> {
    uart: &'a U,
    apps: Container<App>,
    in_progress: TakeCell<AppId>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, U: UART> Console<'a, U> {
    pub const fn new(uart: &'a U, buffer: &'static mut [u8],
                     container: Container<App>) -> Console<'a, U> {
        Console {
            uart: uart,
            apps: container,
            in_progress: TakeCell::empty(),
            buffer: TakeCell::new(buffer)
        }
    }

    pub fn initialize(&self) {
        self.uart.enable_tx();
        self.uart.enable_rx();
    }
}

impl<'a, U: UART> Driver for Console<'a, U> {
    fn allow(&self, appid: AppId,
             allow_num: usize, slice: AppSlice<Shared, u8>) -> isize {
        match allow_num {
            0 => {
                self.apps.enter(appid, |app, _| {
                    app.read_buffer = Some(slice);
                    app.read_idx = 0;
                    0
                }).unwrap_or(-1)
            },
            1 => {
                self.apps.enter(appid, |app, _| {
                    app.write_buffer = Some(slice);
                    0
                }).unwrap_or(-1)
            }
            _ => -1
        }
    }

    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            0 /* read line */ => {
                self.apps.enter(callback.app_id(), |app, _| {
                    app.read_callback = Some(callback);
                    0
                }).unwrap_or(-1)
            },
            1 /* putstr/write_done */ => {
                self.apps.enter(callback.app_id(), |app, _| {
                    match app.write_buffer.take() {
                        Some(slice) => {
                            app.write_callback = Some(callback);
                            app.write_len = slice.len();
                            if self.in_progress.is_none() {
                                self.in_progress.replace(callback.app_id());
                                self.buffer.take().map(|buffer| {
                                    for (i, c) in slice.as_ref().iter().enumerate() {
                                        if buffer.len() <= i {
                                            break;
                                        }
                                        buffer[i] = *c;
                                    }
                                    self.uart.send_bytes(buffer, app.write_len);
                                });
                            } else {
                                app.pending_write = true;
                                app.write_buffer = Some(slice);
                            }
                            0
                        },
                        None => -1
                    }
                }).unwrap_or(-1)
            },
            _ => -1
        }
    }

    fn command(&self, cmd_num: usize, arg1: usize, _: AppId) -> isize {
        match cmd_num {
            0 /* putc */ => { self.uart.send_byte(arg1 as u8); 1 },
            _ => -1
        }
    }
}

impl<'a, U: UART> Client for Console<'a, U> {
    fn write_done(&self, buffer: &'static mut [u8]) {
        // Write TX is done, notify appropriate app and start another
        // transaction if pending
        self.buffer.replace(buffer);
        self.in_progress.take().map(|appid| {
            self.apps.enter(appid, |app, _| {
                app.write_callback.map(|mut cb| {
                    cb.schedule(app.write_len, 0, 0);
                });
                app.write_len = 0;
            })
        });

        for cntr in self.apps.iter() {
            let started_tx = cntr.enter(|app, _| {
                if app.pending_write {
                    app.write_buffer.take().map(|slice| {
                        app.pending_write = false;
                        self.buffer.take().map(|buffer| {
                            for (i, c) in slice.as_ref().iter().enumerate() {
                                if buffer.len() <= i {
                                    break;
                                }
                                buffer[i] = *c;
                            }
                            self.uart.send_bytes(buffer, app.write_len);
                        });
                        self.in_progress.replace(app.appid());
                        true
                    }).unwrap_or(false)
                } else {
                    false
                }
            });
            if started_tx {
                break;
            }
        }
    }

    fn read_done(&self, c: u8) {
        match c as char {
            '\r' => {},
            '\n' => {
                self.apps.each(|app| {
                    let idx = app.read_idx;
                    app.read_buffer = app.read_buffer.take().map(|mut rb| {
                        use core::raw::Repr;
                        app.read_callback.as_mut().map(|cb| {
                            let buf = rb.as_mut();
                            cb.schedule(idx, (buf.repr().data as usize), 0);
                        });
                        rb
                    });
                    app.read_idx = 0;
                });
            },
            _ => {
                self.apps.each(|app| {
                    let idx = app.read_idx;
                    if app.read_buffer.is_some() &&
                        app.read_idx < app.read_buffer.as_ref().unwrap().len() {

                        app.read_buffer.as_mut().map(|buf| {
                            buf.as_mut()[idx] = c;
                        });
                        app.read_idx += 1;
                    }
                });
            }
        }
    }
}

<commit_msg>Correctly write to console from multiple apps<commit_after>use common::take_cell::TakeCell;
use process::{AppId, AppSlice, Container, Callback, Shared};
use hil::Driver;
use hil::uart::{UART, Client};

pub struct App {
    read_callback: Option<Callback>,
    write_callback: Option<Callback>,
    read_buffer: Option<AppSlice<Shared, u8>>,
    write_buffer: Option<AppSlice<Shared, u8>>,
    write_len: usize,
    pending_write: bool,
    read_idx: usize
}

impl Default for App {
    fn default() -> App {
        App {
            read_callback: None,
            write_callback: None,
            read_buffer: None,
            write_buffer: None,
            write_len: 0,
            pending_write: false,
            read_idx: 0
        }
    }
}

pub static mut WRITE_BUF : [u8; 64] = [0; 64];

pub struct Console<'a, U: UART + 'a> {
    uart: &'a U,
    apps: Container<App>,
    in_progress: TakeCell<AppId>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, U: UART> Console<'a, U> {
    pub const fn new(uart: &'a U, buffer: &'static mut [u8],
                     container: Container<App>) -> Console<'a, U> {
        Console {
            uart: uart,
            apps: container,
            in_progress: TakeCell::empty(),
            buffer: TakeCell::new(buffer)
        }
    }

    pub fn initialize(&self) {
        self.uart.enable_tx();
        self.uart.enable_rx();
    }
}

impl<'a, U: UART> Driver for Console<'a, U> {
    fn allow(&self, appid: AppId,
             allow_num: usize, slice: AppSlice<Shared, u8>) -> isize {
        match allow_num {
            0 => {
                self.apps.enter(appid, |app, _| {
                    app.read_buffer = Some(slice);
                    app.read_idx = 0;
                    0
                }).unwrap_or(-1)
            },
            1 => {
                self.apps.enter(appid, |app, _| {
                    app.write_buffer = Some(slice);
                    0
                }).unwrap_or(-1)
            }
            _ => -1
        }
    }

    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            0 /* read line */ => {
                self.apps.enter(callback.app_id(), |app, _| {
                    app.read_callback = Some(callback);
                    0
                }).unwrap_or(-1)
            },
            1 /* putstr/write_done */ => {
                self.apps.enter(callback.app_id(), |app, _| {
                    match app.write_buffer.take() {
                        Some(slice) => {
                            app.write_callback = Some(callback);
                            app.write_len = slice.len();
                            if self.in_progress.is_none() {
                                self.in_progress.replace(callback.app_id());
                                self.buffer.take().map(|buffer| {
                                    for (i, c) in slice.as_ref().iter().enumerate() {
                                        if buffer.len() <= i {
                                            break;
                                        }
                                        buffer[i] = *c;
                                    }
                                    self.uart.send_bytes(buffer, app.write_len);
                                });
                            } else {
                                app.pending_write = true;
                                app.write_buffer = Some(slice);
                            }
                            0
                        },
                        None => -1
                    }
                }).unwrap_or(-1)
            },
            _ => -1
        }
    }

    fn command(&self, cmd_num: usize, arg1: usize, _: AppId) -> isize {
        match cmd_num {
            0 /* putc */ => { self.uart.send_byte(arg1 as u8); 1 },
            _ => -1
        }
    }
}

impl<'a, U: UART> Client for Console<'a, U> {
    fn write_done(&self, buffer: &'static mut [u8]) {
        // Write TX is done, notify appropriate app and start another
        // transaction if pending
        self.buffer.replace(buffer);
        self.in_progress.take().map(|appid| {
            self.apps.enter(appid, |app, _| {
                app.write_callback.map(|mut cb| {
                    cb.schedule(app.write_len, 0, 0);
                });
                app.write_len = 0;
            })
        });

        for cntr in self.apps.iter() {
            let started_tx = cntr.enter(|app, _| {
                if app.pending_write {
                    app.pending_write = false;
                    app.write_buffer.as_ref().map(|slice| {
                        self.buffer.take().map(|buffer| {
                            for (i, c) in slice.as_ref().iter().enumerate() {
                                if buffer.len() <= i {
                                    break;
                                }
                                buffer[i] = *c;
                            }
                            self.uart.send_bytes(buffer, app.write_len);
                        });
                        self.in_progress.replace(app.appid());
                        true
                    }).unwrap_or(false)
                } else {
                    false
                }
            });
            if started_tx {
                break;
            }
        }
    }

    fn read_done(&self, c: u8) {
        match c as char {
            '\r' => {},
            '\n' => {
                self.apps.each(|app| {
                    let idx = app.read_idx;
                    app.read_buffer = app.read_buffer.take().map(|mut rb| {
                        use core::raw::Repr;
                        app.read_callback.as_mut().map(|cb| {
                            let buf = rb.as_mut();
                            cb.schedule(idx, (buf.repr().data as usize), 0);
                        });
                        rb
                    });
                    app.read_idx = 0;
                });
            },
            _ => {
                self.apps.each(|app| {
                    let idx = app.read_idx;
                    if app.read_buffer.is_some() &&
                        app.read_idx < app.read_buffer.as_ref().unwrap().len() {

                        app.read_buffer.as_mut().map(|buf| {
                            buf.as_mut()[idx] = c;
                        });
                        app.read_idx += 1;
                    }
                });
            }
        }
    }
}

<|endoftext|>


<commit_before>use super::{Function, Parameterised, Linear};

use ndarray::{Array1, Array2};

#[link(name="tiles")]
extern {
    fn tiles(tile_indices: *mut i32, nt: i32, memory: i32,
             floats: *const f64, nf: i32, h1: i32);
}

pub struct SuttonTiles {
    weights: Array2<f64>,

    n_tilings: i32,
    memory_size: i32,
}

impl SuttonTiles {
    pub fn new(n_tilings: i32, memory_size: i32, n_outputs: usize) -> Self {
        SuttonTiles {
            weights: Array2::<f64>::zeros((memory_size as usize, n_outputs)),

            n_tilings: n_tilings,
            memory_size: memory_size,
        }
    }

    fn load_tiles(&self, input: &[f64], h: i32) -> Vec<i32> {
        let mut ti = vec![0; self.n_tilings as usize];

        unsafe {
            tiles(ti.as_mut_ptr(), self.n_tilings, self.memory_size,
                  input.as_ptr(), input.len() as i32, h);
        }

        ti
    }
}

impl Function<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        let evaluate_column = |c| {
            self.load_tiles(input, c as i32).iter().fold(0.0, |acc, &i| {
                acc + self.weights[[i as usize, c]]
            }) / self.n_tilings as f64
        };

        (0..self.weights.cols()).map(|c| evaluate_column(c)).collect()
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        for c in 0..self.weights.cols() {
            for r in self.load_tiles(input, c as i32) {
                self.weights[[r as usize, c]] += errors[c];
            }
        }
    }
}

// impl Linear<[f64]> for SuttonTiles {
    // fn phi(&self, input: &[f64]) -> Array1<f64> {
    // }
// }

// add_vec_support!(SuttonTiles, Linear);
<commit_msg>SuttonTiles FFI now in place and working (no SEGF)<commit_after>extern crate libc;
use self::libc::{c_int, c_double};

use super::{Function, Parameterised, Linear, VFunction, QFunction};

use ndarray::{Array1, Array2};
use geometry::{Space, RegularSpace};
use geometry::dimensions::Continuous;

#[link(name="tiles", kind="static")]
extern {
    fn tiles(tile_indices: *mut c_int, nt: c_int, memory: c_int,
             floats: *const c_double, nf: c_int,
             ints: *const c_int, ni: c_int);
}

pub struct SuttonTiles {
    weights: Array2<c_double>,

    n_tilings: i32,
    memory_size: i32,

    int_array: [c_int; 1]
}

impl SuttonTiles {
    pub fn new(n_tilings: i32, memory_size: i32, n_outputs: usize) -> Self {
        SuttonTiles {
            weights: Array2::<c_double>::zeros((memory_size as usize, n_outputs)),

            n_tilings: n_tilings,
            memory_size: memory_size,

            int_array: [0],
        }
    }

    fn load_tiles(&self, floats: &[c_double], ints: &[c_int]) -> Vec<i32> {
        let mut ti = vec![0; self.n_tilings as usize];

        unsafe {
            tiles(ti.as_mut_ptr(), self.n_tilings, self.memory_size,
                  floats.as_ptr(), floats.len() as c_int,
                  ints.as_ptr(), ints.len() as c_int);
        }

        ti
    }

    fn evaluate_column(&self, input: &Vec<f64>, column: usize) -> f64 {
        self.load_tiles(input, &[column as c_int]).iter().fold(0.0, |acc, &i| {
            acc + self.weights[[i as usize, column]]
        }) / self.n_tilings as f64
    }
}

impl Function<Vec<f64>, f64> for SuttonTiles
{
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        self.evaluate_column(input, 0)
    }
}

impl Function<Vec<f64>, Vec<f64>> for SuttonTiles
{
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        (0..self.weights.cols()).map(|c| self.evaluate_column(input, c)).collect()
    }
}

impl Parameterised<Vec<f64>, f64> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        self.int_array[0] = 0;

        for r in self.load_tiles(input, &self.int_array) {
            self.weights[[r as usize, 0]] += error;
        }
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for SuttonTiles
{
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        for c in 0..self.weights.cols() {
            self.int_array[0] = c as c_int;

            for r in self.load_tiles(input, &self.int_array) {
                self.weights[[r as usize, c]] += errors[c];
            }
        }
    }
}

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

    use fa::{Function, Parameterised};
    use geometry::RegularSpace;
    use geometry::dimensions::Partition;

    #[test]
    fn test_simple() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }
}
<|endoftext|>


<commit_before>use super::Span;
use super::dimensions::{self, Dimension, Partitioned};
use rand::ThreadRng;
use std::iter::FromIterator;
use std::slice::Iter;

pub trait Space {
    type Repr: Clone;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr;

    fn dim(&self) -> usize;
    fn span(&self) -> Span;
}

pub type ActionSpace = UnitarySpace<dimensions::Discrete>;

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct NullSpace;

impl Space for NullSpace {
    type Repr = ();

    fn sample(&self, _: &mut ThreadRng) -> Self::Repr {
        ()
    }

    fn dim(&self) -> usize {
        0
    }

    fn span(&self) -> Span {
        Span::Null
    }
}

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct UnitarySpace<D: Dimension>(D);

impl<D: Dimension> UnitarySpace<D> {
    pub fn new(d: D) -> Self {
        UnitarySpace(d)
    }
}

impl UnitarySpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> UnitarySpace<Partitioned> {
        UnitarySpace(Partitioned::from_continuous(self.0, density))
    }
}

impl<D: Dimension> Space for UnitarySpace<D> {
    type Repr = D::Value;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.0.sample(rng)
    }

    fn dim(&self) -> usize {
        1
    }

    fn span(&self) -> Span {
        self.0.span()
    }
}

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct PairSpace<D1, D2>((D1, D2))
    where D1: Dimension,
          D2: Dimension;

impl<D1: Dimension, D2: Dimension> PairSpace<D1, D2> {
    pub fn new(d1: D1, d2: D2) -> Self {
        PairSpace((d1, d2))
    }
}

impl PairSpace<dimensions::Continuous, dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> PairSpace<Partitioned, Partitioned> {
        PairSpace((Partitioned::from_continuous((self.0).0, density),
                   Partitioned::from_continuous((self.0).1, density)))
    }
}

impl<D1: Dimension, D2: Dimension> Space for PairSpace<D1, D2> {
    type Repr = (D1::Value, D2::Value);

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        ((self.0).0.sample(rng), (self.0).1.sample(rng))
    }

    fn dim(&self) -> usize {
        2
    }

    fn span(&self) -> Span {
        (self.0).0.span()*(self.0).1.span()
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct RegularSpace<D: Dimension> {
    dimensions: Vec<D>,
    span: Span,
}

impl<D: Dimension> RegularSpace<D> {
    pub fn new(dimensions: Vec<D>) -> Self {
        let mut s = Self::empty();

        for d in dimensions {
            s = s.push(d);
        }

        s
    }

    pub fn empty() -> Self {
        RegularSpace {
            dimensions: vec![],
            span: Span::Null,
        }
    }

    pub fn push(mut self, d: D) -> Self {
        self.span = self.span * d.span();
        self.dimensions.push(d);
        self
    }

    pub fn iter(&self) -> Iter<D> {
        self.dimensions.iter()
    }
}

impl RegularSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> RegularSpace<Partitioned> {
        self.into_iter()
            .map(|d| Partitioned::from_continuous(d, density))
            .collect()
    }
}

impl RegularSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .iter()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for RegularSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|d| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<D> for RegularSpace<D> {
    fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
        let mut s = Self::empty();

        for i in iter {
            s = s.push(i);
        }

        s
    }
}

impl<D: Dimension> IntoIterator for RegularSpace<D> {
    type Item = D;
    type IntoIter = ::std::vec::IntoIter<D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

// pub struct HeterogeneousSpace {
// dimensions: Vec<Dimension>,
// span: Span
// }

// impl HeterogeneousSpace {
// pub fn new() -> Self {
// HeterogeneousSpace {
// dimensions: vec![],
// span: Span::Null
// }
// }

// pub fn push(mut self, d: D) -> Self {
// self.span = self.span * d.span();
// self.dimensions.push(d);
// self
// }

// pub fn iter(&self) -> Iter<Dimension> {
// self.dimensions.iter()
// }
// }

// impl<D: Dimension> Space for HeterogeneousSpace<D> {
// type Repr = Vec<D::Value>;

// fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
// self.dimensions.iter().map(|d| d.sample(rng)).collect()
// }

// fn dim(&self) -> usize {
// self.dimensions.len()
// }

// fn span(&self) -> Span {
// self.span
// }
// }

#[cfg(test)]
mod tests {
    use super::{Space, NullSpace, UnitarySpace, PairSpace, RegularSpace};
    use geometry::Span;
    use geometry::dimensions::*;
    use ndarray::arr1;
    use rand::thread_rng;

    #[test]
    fn test_null_space() {
        let ns = NullSpace;
        let mut rng = thread_rng();

        assert_eq!(ns.sample(&mut rng), ());
        assert_eq!(ns.dim(), 0);
        assert_eq!(ns.span(), Span::Null);
    }

    #[test]
    fn test_unitary_space() {
        let us = UnitarySpace::new(Discrete::new(2));
        let mut rng = thread_rng();

        let mut counts = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = us.sample(&mut rng);
            counts[sample] += 1.0;

            assert!(sample == 0 || sample == 1);
        }

        assert!((counts/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert_eq!(us.dim(), 1);
        assert_eq!(us.span(), Span::Finite(2));
    }

    #[test]
    fn test_pair_space() {
        let ps = PairSpace::new(Discrete::new(2), Discrete::new(2));

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = ps.sample(&mut rng);

            c1[sample.0] += 1.0;
            c2[sample.1] += 1.0;

            assert!(sample.0 == 0 || sample.0 == 1);
            assert!(sample.1 == 0 || sample.1 == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(ps.dim(), 2);
        assert_eq!(ps.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space() {
        let space = RegularSpace::new(vec![Discrete::new(2); 2]);

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = space.sample(&mut rng);

            c1[sample[0]] += 1.0;
            c2[sample[1]] += 1.0;

            assert!(sample[0] == 0 || sample[0] == 1);
            assert!(sample[1] == 0 || sample[1] == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(space.dim(), 2);
        assert_eq!(space.span(), Span::Finite(4));
    }
}
<commit_msg>refactor(geometry): rename NullSpace to EmptySpace<commit_after>use super::Span;
use super::dimensions::{self, Dimension, Partitioned};
use rand::ThreadRng;
use std::iter::FromIterator;
use std::slice::Iter;

pub trait Space {
    type Repr: Clone;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr;

    fn dim(&self) -> usize;
    fn span(&self) -> Span;
}

pub type ActionSpace = UnitarySpace<dimensions::Discrete>;

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct EmptySpace;

impl Space for EmptySpace {
    type Repr = ();

    fn sample(&self, _: &mut ThreadRng) -> Self::Repr {
        ()
    }

    fn dim(&self) -> usize {
        0
    }

    fn span(&self) -> Span {
        Span::Null
    }
}

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct UnitarySpace<D: Dimension>(D);

impl<D: Dimension> UnitarySpace<D> {
    pub fn new(d: D) -> Self {
        UnitarySpace(d)
    }
}

impl UnitarySpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> UnitarySpace<Partitioned> {
        UnitarySpace(Partitioned::from_continuous(self.0, density))
    }
}

impl<D: Dimension> Space for UnitarySpace<D> {
    type Repr = D::Value;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.0.sample(rng)
    }

    fn dim(&self) -> usize {
        1
    }

    fn span(&self) -> Span {
        self.0.span()
    }
}

#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct PairSpace<D1, D2>((D1, D2))
    where D1: Dimension,
          D2: Dimension;

impl<D1: Dimension, D2: Dimension> PairSpace<D1, D2> {
    pub fn new(d1: D1, d2: D2) -> Self {
        PairSpace((d1, d2))
    }
}

impl PairSpace<dimensions::Continuous, dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> PairSpace<Partitioned, Partitioned> {
        PairSpace((Partitioned::from_continuous((self.0).0, density),
                   Partitioned::from_continuous((self.0).1, density)))
    }
}

impl<D1: Dimension, D2: Dimension> Space for PairSpace<D1, D2> {
    type Repr = (D1::Value, D2::Value);

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        ((self.0).0.sample(rng), (self.0).1.sample(rng))
    }

    fn dim(&self) -> usize {
        2
    }

    fn span(&self) -> Span {
        (self.0).0.span()*(self.0).1.span()
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct RegularSpace<D: Dimension> {
    dimensions: Vec<D>,
    span: Span,
}

impl<D: Dimension> RegularSpace<D> {
    pub fn new(dimensions: Vec<D>) -> Self {
        let mut s = Self::empty();

        for d in dimensions {
            s = s.push(d);
        }

        s
    }

    pub fn empty() -> Self {
        RegularSpace {
            dimensions: vec![],
            span: Span::Null,
        }
    }

    pub fn push(mut self, d: D) -> Self {
        self.span = self.span * d.span();
        self.dimensions.push(d);
        self
    }

    pub fn iter(&self) -> Iter<D> {
        self.dimensions.iter()
    }
}

impl RegularSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> RegularSpace<Partitioned> {
        self.into_iter()
            .map(|d| Partitioned::from_continuous(d, density))
            .collect()
    }
}

impl RegularSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .iter()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for RegularSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|d| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<D> for RegularSpace<D> {
    fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
        let mut s = Self::empty();

        for i in iter {
            s = s.push(i);
        }

        s
    }
}

impl<D: Dimension> IntoIterator for RegularSpace<D> {
    type Item = D;
    type IntoIter = ::std::vec::IntoIter<D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

// pub struct HeterogeneousSpace {
// dimensions: Vec<Dimension>,
// span: Span
// }

// impl HeterogeneousSpace {
// pub fn new() -> Self {
// HeterogeneousSpace {
// dimensions: vec![],
// span: Span::Null
// }
// }

// pub fn push(mut self, d: D) -> Self {
// self.span = self.span * d.span();
// self.dimensions.push(d);
// self
// }

// pub fn iter(&self) -> Iter<Dimension> {
// self.dimensions.iter()
// }
// }

// impl<D: Dimension> Space for HeterogeneousSpace<D> {
// type Repr = Vec<D::Value>;

// fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
// self.dimensions.iter().map(|d| d.sample(rng)).collect()
// }

// fn dim(&self) -> usize {
// self.dimensions.len()
// }

// fn span(&self) -> Span {
// self.span
// }
// }

#[cfg(test)]
mod tests {
    use super::{Space, EmptySpace, UnitarySpace, PairSpace, RegularSpace};
    use geometry::Span;
    use geometry::dimensions::*;
    use ndarray::arr1;
    use rand::thread_rng;

    #[test]
    fn test_null_space() {
        let ns = EmptySpace;
        let mut rng = thread_rng();

        assert_eq!(ns.sample(&mut rng), ());
        assert_eq!(ns.dim(), 0);
        assert_eq!(ns.span(), Span::Null);
    }

    #[test]
    fn test_unitary_space() {
        let us = UnitarySpace::new(Discrete::new(2));
        let mut rng = thread_rng();

        let mut counts = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = us.sample(&mut rng);
            counts[sample] += 1.0;

            assert!(sample == 0 || sample == 1);
        }

        assert!((counts/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert_eq!(us.dim(), 1);
        assert_eq!(us.span(), Span::Finite(2));
    }

    #[test]
    fn test_pair_space() {
        let ps = PairSpace::new(Discrete::new(2), Discrete::new(2));

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = ps.sample(&mut rng);

            c1[sample.0] += 1.0;
            c2[sample.1] += 1.0;

            assert!(sample.0 == 0 || sample.0 == 1);
            assert!(sample.1 == 0 || sample.1 == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(ps.dim(), 2);
        assert_eq!(ps.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space() {
        let space = RegularSpace::new(vec![Discrete::new(2); 2]);

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = space.sample(&mut rng);

            c1[sample[0]] += 1.0;
            c2[sample[1]] += 1.0;

            assert!(sample[0] == 0 || sample[0] == 1);
            assert!(sample[1] == 0 || sample[1] == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(space.dim(), 2);
        assert_eq!(space.span(), Span::Finite(4));
    }
}
<|endoftext|>


<commit_before>use gl;
use glutin;
use glutin::GlContext;
use nanovg;

use gui;

const INITIAL_WINDOW_SIZE: (u32, u32) = (1280, 720);

/// Chorus Studio's main window.
pub struct MainWindow {
    events_loop: glutin::EventsLoop,
    gl_window: glutin::GlWindow,
    pub was_closed: bool,
}

impl MainWindow {
    pub fn new() -> Result<Self, CreateMainWindowError> {
        let events_loop = glutin::EventsLoop::new();
        let window_builder = glutin::WindowBuilder::new()
            .with_dimensions(INITIAL_WINDOW_SIZE.0, INITIAL_WINDOW_SIZE.1)
            .with_title("Chorus Studio");
        let context_builder = glutin::ContextBuilder::new()
            .with_gl(glutin::GlRequest::Latest)
            .with_gl_profile(glutin::GlProfile::Core)
            .with_multisampling(4)
            .with_vsync(true);
        let gl_window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)?;

        unsafe {
            gl_window.make_current()?;
            gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
            gl::ClearColor(0.2, 0.4, 0.8, 1.0);
        }

        Ok(MainWindow {
            events_loop,
            gl_window,
            was_closed: false,
        })
    }

    /// Update and draw the window for one frame.
    pub fn update_draw(&mut self, view: &mut gui::View, context: &nanovg::Context) {
        let mut was_closed = self.was_closed;
        self.events_loop.poll_events(|event| match event {
           glutin::Event::WindowEvent { event, .. } => match event {
               glutin::WindowEvent::Closed => was_closed = true,
               _ => {}
           },
            _ => {}
        });
        self.was_closed = was_closed;

        let (w, h) = self.gl_window.get_inner_size().unwrap_or(INITIAL_WINDOW_SIZE);
        let (w, h) = (w as i32, h as i32);
        unsafe {
            gl::Viewport(0, 0, w, h);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
        }

        view.set_bbox(gui::Bbox::with_size(gui::Point::new(0, 0), gui::Point::new(w, h)));
        context.frame((w, h), self.gl_window.hidpi_factor(), |frame| {
            view.draw(&frame);
        });

        let _ = self.gl_window.swap_buffers();
    }
}

#[derive(Debug)]
pub enum CreateMainWindowError {
    CreationError(glutin::CreationError),
    ContextError(glutin::ContextError),
}

impl From<glutin::CreationError> for CreateMainWindowError {
    fn from(e: glutin::CreationError) -> Self {
        CreateMainWindowError::CreationError(e)
    }
}

impl From<glutin::ContextError> for CreateMainWindowError {
    fn from(e: glutin::ContextError) -> Self {
        CreateMainWindowError::ContextError(e)
    }
}<commit_msg>Animate background for no reason; forward window resizing to gl_window<commit_after>use gl;
use glutin;
use glutin::GlContext;
use nanovg;

use std::time::Instant;

use gui;

const INITIAL_WINDOW_SIZE: (u32, u32) = (1280, 720);
const RED: gui::Color = gui::Color {
    r: 0xff as f32 / 255.0,
    g: 0xca as f32 / 255.0,
    b: 0x77 as f32 / 255.0,
    a: 1.0,
};
//const BLUE: gui::Color = gui::Color {
//    r: 0x2e as f32 / 255.0,
//    g: 0x50 as f32 / 255.0,
//    b: 0x77 as f32 / 255.0,
//    a: 1.0,
//};
const BLUE: gui::Color = gui::Color {
    r: 112 as f32 / 255.0,
    g: 48 as f32 / 255.0,
    b: 160 as f32 / 255.0,
    a: 1.0,
};

/// Chorus Studio's main window.
pub struct MainWindow {
    events_loop: glutin::EventsLoop,
    gl_window: glutin::GlWindow,
    pub was_closed: bool,
    start_time: Instant,
}

impl MainWindow {
    pub fn new() -> Result<Self, CreateMainWindowError> {
        let events_loop = glutin::EventsLoop::new();
        let window_builder = glutin::WindowBuilder::new()
            .with_dimensions(INITIAL_WINDOW_SIZE.0, INITIAL_WINDOW_SIZE.1)
            .with_title("Chorus Studio");
        let context_builder = glutin::ContextBuilder::new()
            .with_gl(glutin::GlRequest::Latest)
            .with_gl_profile(glutin::GlProfile::Core)
            .with_multisampling(4)
            .with_vsync(true);
        let gl_window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)?;

        unsafe {
            gl_window.make_current()?;
            gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
            gl::ClearColor(0.2, 0.4, 0.8, 1.0);
        }

        Ok(MainWindow {
            events_loop,
            gl_window,
            was_closed: false,
            start_time: Instant::now(),
        })
    }

    /// Update and draw the window for one frame.
    pub fn update_draw(&mut self, view: &mut gui::View, context: &nanovg::Context) {
        let mut was_closed = self.was_closed;
        let gl_window = &self.gl_window;
        self.events_loop.poll_events(|event| match event {
           glutin::Event::WindowEvent { event, .. } => match event {
               glutin::WindowEvent::Closed => was_closed = true,
               glutin::WindowEvent::Resized(w, h) => gl_window.resize(w, h),
               _ => {}
           },
            _ => {}
        });
        self.was_closed = was_closed;

        let (w, h) = self.gl_window.get_inner_size().unwrap_or(INITIAL_WINDOW_SIZE);
        let (w, h) = (w as i32, h as i32);

        unsafe {
            let elapsed = self.start_time.elapsed();
            let elapsed = (elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9) as f32;
            let color = nanovg::Color::lerp(RED.into(), BLUE.into(), (elapsed / 2.0).cos() * 0.5 + 0.5);
            gl::ClearColor(color.red(), color.green(), color.blue(), color.alpha());
            gl::Viewport(0, 0, w, h);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
        }

        view.set_bbox(gui::Bbox::with_size(gui::Point::new(0, 0), gui::Point::new(w, h)));
        context.frame((w, h), self.gl_window.hidpi_factor(), |frame| {
            view.draw(&frame);
        });

        let _ = self.gl_window.swap_buffers();
    }
}

#[derive(Debug)]
pub enum CreateMainWindowError {
    CreationError(glutin::CreationError),
    ContextError(glutin::ContextError),
}

impl From<glutin::CreationError> for CreateMainWindowError {
    fn from(e: glutin::CreationError) -> Self {
        CreateMainWindowError::CreationError(e)
    }
}

impl From<glutin::ContextError> for CreateMainWindowError {
    fn from(e: glutin::ContextError) -> Self {
        CreateMainWindowError::ContextError(e)
    }
}<|endoftext|>


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

pub struct Keeper {
    subscribers: HashMap<String, RefCell<Vec<String>>>
}

impl Keeper {
    pub fn new() -> Self {
        Keeper { subscribers: HashMap::new() }
    }

    pub fn subscribe(&mut self, event_name: String, target_url: String) -> Result<(), &str> {
        if !self.subscribers.contains_key(&event_name) {
            self.subscribers.insert(event_name.to_string(), RefCell::new(Vec::new()));
        }

        if self.subscribers[&event_name].borrow().contains(&target_url) {
            return Result::Err("already exists");
        }

        self.subscribers[&event_name].borrow_mut().push(target_url);
        return Result::Ok(());
    }
}

#[cfg(test)]
mod tests {
    use keeper::registry::Keeper;

    #[test]
    fn test_keeper_add() {
        let test_event_name = "test_event";
        let test_url = "test_url";
        let mut kpr = Keeper::new();

        assert_eq!(kpr.subscribers.len(), 0);

        assert!(kpr.subscribe(test_event_name.to_string(), test_url.to_string()).is_ok());
        assert_eq!(kpr.subscribers.len(), 1);
        assert_eq!(kpr.subscribers[test_event_name].borrow().len(), 1);
        assert_eq!(kpr.subscribers[test_event_name].borrow()[0], test_url);

        assert!(kpr.subscribe(test_event_name.to_string(), test_url.to_string()).is_err());
        assert_eq!(kpr.subscribers[test_event_name].borrow().len(), 1);
    }
}<commit_msg>keeper<commit_after>use std::collections::HashMap;
use std::cell::RefCell;

pub struct Keeper {
    subscribers: HashMap<String, RefCell<Vec<String>>>
}

impl Keeper {
    pub fn new() -> Self {
        Keeper { subscribers: HashMap::new() }
    }

    pub fn subscribe(&mut self, event_name: String, target_url: String) -> Result<(), &str> {
        if !self.subscribers.contains_key(&event_name) {
            self.subscribers.insert(event_name.to_string(), RefCell::new(Vec::new()));
        }

        if self.subscribers[&event_name].borrow().contains(&target_url) {
            return Result::Err("already exists");
        }

        self.subscribers[&event_name].borrow_mut().push(target_url);
        return Result::Ok(());
    }

    pub fn unsubscribe(&mut self, event_name: String, target_url: String) -> Result<(), &str> {
        if !self.subscribers.contains_key(&event_name) {
            return Result::Ok(());
        }

        self.subscribers[&event_name].borrow_mut().retain(|ref x| target_url != **x);

        if self.subscribers[&event_name].borrow().len() == 0 {
            self.subscribers.remove(&event_name);
        }

        return Result::Ok(());
    }

    pub fn get_subscribers(&self, event_name: String) -> Vec<String> {
        if self.subscribers.contains_key(&event_name) {
            return self.subscribers[&event_name].borrow().clone();
        }

        return Vec::new();
    }
}

#[cfg(test)]
mod tests {
    use keeper::registry::Keeper;

    #[test]
    fn add() {
        let test_event_name = "test_event";
        let test_url = "test_url";
        let mut kpr = Keeper::new();

        assert_eq!(kpr.subscribers.len(), 0);

        assert!(kpr.subscribe(test_event_name.to_string(), test_url.to_string()).is_ok());
        assert_eq!(kpr.subscribers.len(), 1);
        assert_eq!(kpr.subscribers[test_event_name].borrow().len(), 1);
        assert_eq!(kpr.subscribers[test_event_name].borrow()[0], test_url);

        assert!(kpr.subscribe(test_event_name.to_string(), test_url.to_string()).is_err());
        assert_eq!(kpr.subscribers[test_event_name].borrow().len(), 1);
    }

    #[test]
    fn remove() {
        let test_event_name = "test_event";
        let test_url = "test_url";
        let mut kpr = Keeper::new();
        assert_eq!(kpr.subscribers.len(), 0);
        assert!(kpr.subscribe(test_event_name.to_string(), test_url.to_string()).is_ok());
        assert_eq!(kpr.subscribers.len(), 1);
        assert!(kpr.unsubscribe(test_event_name.to_string(), test_url.to_string()).is_ok());
        assert_eq!(kpr.subscribers.len(), 0);
    }

    #[test]
    fn get_blank() {
        let test_event_name = "test_event";
        let test_url = "test_url";
        let mut kpr = Keeper::new();

        assert_eq!(kpr.get_subscribers("no_event".to_string()).len(), 0);
        assert!(kpr.subscribe(test_event_name.to_string(), test_url.to_string()).is_ok());
        assert_eq!(kpr.get_subscribers(test_event_name.to_string()).len(), 1);
    }
}<|endoftext|>


<commit_before>/// Given a list of entries `items` and the query string, filter out the
/// matched entries using fuzzy search algorithm.

extern crate num_cpus;
extern crate crossbeam;

use std::sync::{Arc, RwLock};

use std::sync::mpsc::channel;
use std::collections::HashMap;
use event::Event;
use item::{Item, MatchedItem, MatchedRange};
use util::eventbox::EventBox;
use score;
use orderedvec::OrderedVec;
use std::cmp::min;
use std::time::{Instant};

pub struct Matcher {
    pub eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Arc<RwLock<Vec<Item>>>,
    new_items: Arc<RwLock<Vec<Item>>>,
    query: String,
    cache: HashMap<String, MatcherCache>,
    partitions: usize,
}

impl<'a> Matcher {
    pub fn new(items: Arc<RwLock<Vec<Item>>>,
               new_items: Arc<RwLock<Vec<Item>>>,
               eb_notify: Arc<EventBox<Event>>) -> Self {

        let mut cache = HashMap::new();
        cache.entry("".to_string()).or_insert(MatcherCache::new());

        Matcher {
            eb_req: Arc::new(EventBox::new()),
            eb_notify: eb_notify,
            items: items,
            new_items: new_items,
            query: String::new(),
            cache: cache,
            partitions: num_cpus::get(),
        }
    }

    pub fn process(&mut self) {
        let ref mut cache = self.cache.get_mut(&self.query).unwrap();
        let timer = Instant::now();

        let item_pos = cache.item_pos;
        let items = self.items.read().unwrap();
        let slices = slice_items(&items, item_pos, self.partitions);
        let mut guards = vec![];
        let query = self.query.clone();
        let (tx, rx) = channel();
        let eb_req = self.eb_req.clone();
        let eb_notify = self.eb_notify.clone();

        crossbeam::scope(|scope| {
            for (start, slice) in slices {
                let query = query.clone();
                let tx = tx.clone();
                let guard = scope.spawn(move || {
                    let mut ret = vec![];
                    let mut last = start;
                    for (item, index) in slice.iter().zip(start..) {
                        if let Some(matched) = match_item(index, &item.text, &query) {
                            ret.push(matched.clone());
                        }

                        if index > last + 1000 {
                            tx.send(index - last);
                            last = index;
                        }
                    }
                    tx.send(slice.len() + start - last);
                    ret
                });
                guards.push(guard);
            }

            let mut processed_num = 0;
            while let Ok(num) = rx.recv() {
                processed_num += num;

                if processed_num >= items.len() - item_pos {
                    break;
                }

                if eb_req.peek(Event::EvMatcherResetQuery) {
                    // wait for process to exit and clean
                    while let Ok(num) = rx.try_recv() {}
                }

                // update process
                let time = timer.elapsed();
                let mills = (time.as_secs()*1000) as u32 + time.subsec_nanos()/1000/1000;
                if mills > 200 {
                    eb_notify.set(Event::EvMatcherUpdateProcess, Box::new((processed_num*100/items.len()) as u64));
                }
            }
        });

        if !eb_req.peek(Event::EvMatcherResetQuery) {

            cache.matched_items.clear();
            for guard in guards {
                let mut matched_items = guard.join();
                while let Some(item) = matched_items.pop() {
                    cache.matched_items.push(item);
                }
            }
            cache.item_pos = items.len();
        }
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.cache.entry(query.to_string()).or_insert(MatcherCache::new());
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in self.eb_req.wait() {
                match e {
                    Event::EvMatcherNewItem => {}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            // insert new items
            {
                let mut buffer = self.new_items.write().unwrap();
                if buffer.len() > 0 {
                    let mut items = self.items.write().unwrap();
                    items.append(&mut buffer);
                }
            }

            self.process();
            let ref mut cache = self.cache.get_mut(&self.query).unwrap();
            self.eb_notify.set(Event::EvMatcherEnd, Box::new(cache.matched_items.clone()));
        }
    }
}

fn slice_items<'a>(items: &'a[Item], start_pos: usize, partitions: usize) -> Vec<(usize, &'a[Item])>{
    let step = (items.len() - start_pos)/partitions + 1;
    let mut ret = Vec::new();
    let mut start = start_pos;
    let mut end;
    while start < items.len() {
        end = min(start + step, items.len());
        ret.push((start, &items[start..end]));
        start = end;
    }
    ret
}

fn match_item(index: usize, item: &str, query: &str) -> Option<MatchedItem> {
    let matched_result = score::fuzzy_match(item, query);
    if matched_result == None {
        return None;
    }

    let (score, matched_range) = matched_result.unwrap();

    let mut item = MatchedItem::new(index);
    item.set_matched_range(MatchedRange::Chars(matched_range));
    item.set_score(score);
    Some(item)
}

struct MatcherCache {
    pub matched_items: OrderedVec<MatchedItem>,
    pub item_pos: usize,
}

impl MatcherCache {
    pub fn new() -> Self {
        MatcherCache {
            item_pos: 0,
            matched_items: OrderedVec::new(),
        }
    }
}
<commit_msg>[matcher] use multiple thread for matching.<commit_after>/// Given a list of entries `items` and the query string, filter out the
/// matched entries using fuzzy search algorithm.

extern crate num_cpus;
extern crate crossbeam;

use std::sync::{Arc, RwLock, Mutex};

use std::sync::mpsc::channel;
use std::collections::HashMap;
use event::Event;
use item::{Item, MatchedItem, MatchedRange};
use util::eventbox::EventBox;
use score;
use orderedvec::OrderedVec;
use std::cmp::min;
use std::time::{Instant};
use std::thread;

const MATCHER_CHUNK_SIZE: usize = 100;
const PROCESS_UPDATE_DURATION: u32 = 200; // milliseconds

pub struct Matcher {
    pub eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Arc<RwLock<Vec<Item>>>,
    new_items: Arc<RwLock<Vec<Item>>>,
    query: String,
    cache: HashMap<String, MatcherCache>,
    partitions: usize,
}

impl<'a> Matcher {
    pub fn new(items: Arc<RwLock<Vec<Item>>>,
               new_items: Arc<RwLock<Vec<Item>>>,
               eb_notify: Arc<EventBox<Event>>) -> Self {

        let mut cache = HashMap::new();
        cache.entry("".to_string()).or_insert(MatcherCache::new());

        Matcher {
            eb_req: Arc::new(EventBox::new()),
            eb_notify: eb_notify,
            items: items,
            new_items: new_items,
            query: String::new(),
            cache: cache,
            partitions: num_cpus::get(),
        }
    }

    pub fn process(&mut self) {
        let ref mut cache = self.cache.get_mut(&self.query).unwrap();
        let timer = Instant::now();

        let query = Arc::new(self.query.clone());
        let (tx, rx) = channel();
        let mut guards = vec![];

        let start_pos = Arc::new(Mutex::new(cache.item_pos));
        for i in 0..self.partitions {
            let items = self.items.clone();
            let start_pos = start_pos.clone();
            let query = query.clone();
            let tx = tx.clone();
            let eb_req = self.eb_req.clone();

            let guard = thread::spawn(move || {
                let items = items.read().unwrap();
                loop {
                    let mut start_idx = start_pos.lock().unwrap();
                    if *start_idx >= items.len() {
                        break;
                    }

                    let start = *start_idx;
                    let end = min(start + MATCHER_CHUNK_SIZE, items.len());
                    *start_idx = end;

                    for i in start..end {
                        let ref item = items[i];
                        if let Some(matched) = match_item(i, &item.text, &query) {
                            tx.send(Some(matched));
                        }
                    }

                    if eb_req.peek(Event::EvMatcherResetQuery) {
                        break;
                    }
                }
                tx.send(None); // to notify match process end
            });
            guards.push(guard);
        }

        let items_len = self.items.read().unwrap().len();
        while let Ok(result) = rx.recv() {
            if let Some(matched) = result {
                cache.matched_items.push(matched);
            }

            let start_idx = *start_pos.lock().unwrap();
            // update process
            let time = timer.elapsed();
            let mills = (time.as_secs()*1000) as u32 + time.subsec_nanos()/1000/1000;
            if mills > PROCESS_UPDATE_DURATION {
                self.eb_notify.set(Event::EvMatcherUpdateProcess, Box::new((start_idx *100/items_len) as u64));
            }

            if start_idx >= items_len {
                break;
            }

            if self.eb_req.peek(Event::EvMatcherResetQuery) {
                break;
            }
        }

        // wait for all threads to exit
        for guard in guards {
            let _ = guard.join();
        }

        // consume remaining results.
        while let Ok(Some(matched)) = rx.try_recv() {
            cache.matched_items.push(matched);
        }
        cache.item_pos = *start_pos.lock().unwrap();
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.cache.entry(query.to_string()).or_insert(MatcherCache::new());
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in self.eb_req.wait() {
                match e {
                    Event::EvMatcherNewItem => {}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            // insert new items
            {
                let mut buffer = self.new_items.write().unwrap();
                if buffer.len() > 0 {
                    let mut items = self.items.write().unwrap();
                    items.append(&mut buffer);
                }
            }

            self.process();
            let ref mut cache = self.cache.get_mut(&self.query).unwrap();
            self.eb_notify.set(Event::EvMatcherEnd, Box::new(cache.matched_items.clone()));
        }
    }
}

fn slice_items<'a>(items: &'a[Item], start_pos: usize, partitions: usize) -> Vec<(usize, &'a[Item])>{
    let step = (items.len() - start_pos)/partitions + 1;
    let mut ret = Vec::new();
    let mut start = start_pos;
    let mut end;
    while start < items.len() {
        end = min(start + step, items.len());
        ret.push((start, &items[start..end]));
        start = end;
    }
    ret
}

fn match_item(index: usize, item: &str, query: &str) -> Option<MatchedItem> {
    let matched_result = score::fuzzy_match(item, query);
    if matched_result == None {
        return None;
    }

    let (score, matched_range) = matched_result.unwrap();

    let mut item = MatchedItem::new(index);
    item.set_matched_range(MatchedRange::Chars(matched_range));
    item.set_score(score);
    Some(item)
}

struct MatcherCache {
    pub matched_items: OrderedVec<MatchedItem>,
    pub item_pos: usize,
}

impl MatcherCache {
    pub fn new() -> Self {
        MatcherCache {
            item_pos: 0,
            matched_items: OrderedVec::new(),
        }
    }
}
<|endoftext|>