<commit_before>use analysis::bounds::Bound;
use analysis::imports::Imports;
use analysis::ref_mode::RefMode;
use analysis::rust_type::*;
use analysis::signals;
use analysis::signatures::{Signature, Signatures};
use analysis::trampolines;
use config::{self, GObject, PropertyGenerateFlags};
use env::Env;
use library;
use nameutil;
use traits::*;
use version::Version;

#[derive(Debug)]
pub struct Property {
    pub name: String,
    pub var_name: String,
    pub typ: library::TypeId,
    pub is_get: bool,
    pub func_name: String,
    pub nullable: library::Nullable,
    pub get_out_ref_mode: RefMode,
    pub set_in_ref_mode: RefMode,
    pub version: Option<Version>,
    pub deprecated_version: Option<Version>,
    pub bound: Option<Bound>,
}

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Vec<Property>, Vec<signals::Info>) {
    let mut properties = Vec::new();
    let mut notify_signals = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if configured_properties.iter().any(|f| f.ignore) {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }

        let (getter, setter, notify_signal) = analyze_property(
            env,
            prop,
            type_tid,
            &configured_properties,
            generate_trait,
            trampolines,
            obj,
            imports,
            signatures,
            deps,
        );

        if let Some(notify_signal) = notify_signal {
            notify_signals.push(notify_signal);
        }

        if getter.is_none() && setter.is_none() {
            continue;
        }

        let type_string = rust_type(env, prop.typ);
        let used_type_string = used_rust_type(env, prop.typ);
        if let Some(prop) = getter {
            if let Ok(ref s) = used_type_string {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
                imports.add("glib::StaticType", prop.version);
            }

            properties.push(prop);
        }
        if let Some(prop) = setter {
            if let Ok(ref s) = used_type_string {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
            }

            if prop.bound.is_some() {
                imports.add("glib", prop.version);
                imports.add("glib::object::IsA", prop.version);
            }

            properties.push(prop);
        }
    }

    (properties, notify_signals)
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    type_tid: library::TypeId,
    configured_properties: &[&config::properties::Property],
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Option<Property>, Option<Property>, Option<signals::Info>) {
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or_else(|| Some(env.config.min_cfg_version));
    let generate = configured_properties
        .iter()
        .filter_map(|f| f.generate)
        .next()
        .unwrap_or_else(PropertyGenerateFlags::all);
    let name_for_func = nameutil::signal_to_snake(&name);
    let var_name = nameutil::mangle_keywords(&*name_for_func).into_owned();
    let get_func_name = format!("get_property_{}", name_for_func);
    let set_func_name = format!("set_property_{}", name_for_func);
    let check_get_func_name = format!("get_{}", name_for_func);
    let check_set_func_name = format!("set_{}", name_for_func);

    let mut readable = prop.readable && generate.contains(PropertyGenerateFlags::GET);
    let mut writable = if prop.construct_only {
        false
    } else {
        prop.writable && generate.contains(PropertyGenerateFlags::SET)
    };
    let notifable = generate.contains(PropertyGenerateFlags::NOTIFY);

    if readable {
        let (has, version) = Signature::has_for_property(env, &check_get_func_name,
                                                         true, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            readable = false;
        }
    }
    if writable {
        let (has, version) = Signature::has_for_property(env, &check_set_func_name,
                                                         false, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            writable = false;
        }
    }

    let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return);
    let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In);
    if set_in_ref_mode == RefMode::ByRefMut {
        set_in_ref_mode = RefMode::ByRef;
    }
    let nullable = library::Nullable(set_in_ref_mode.is_ref());
    let getter = if readable {
        Some(Property {
            name: name.clone(),
            var_name: String::new(),
            typ: prop.typ,
            is_get: true,
            func_name: get_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound: None,
        })
    } else {
        None
    };

    let setter = if writable {
        let bound = Bound::get_for_property_setter(env, &var_name, prop.typ, nullable);
        Some(Property {
            name: name.clone(),
            var_name,
            typ: prop.typ,
            is_get: false,
            func_name: set_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound,
        })
    } else {
        None
    };

    let mut used_types: Vec<String> = Vec::with_capacity(4);
    let trampoline_name = trampolines::analyze(
        env,
        &library::Signal {
            name: format!("notify::{}", name),
            parameters: Vec::new(),
            ret: library::Parameter {
                name: "".into(),
                typ: env.library
                    .find_type(library::INTERNAL_NAMESPACE, "none")
                    .unwrap(),
                c_type: "none".into(),
                instance_parameter: false,
                direction: library::ParameterDirection::Return,
                transfer: library::Transfer::None,
                caller_allocates: false,
                nullable: library::Nullable(false),
                allow_none: false,
                array_length: None,
                is_error: false,
                doc: None,
                scope: library::ParameterScope::None,
                closure: None,
                destroy: None,
            },
            is_action: false,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            doc: None,
            doc_deprecated: None,
        },
        type_tid,
        generate_trait,
        &[],
        trampolines,
        obj,
        &mut used_types,
        prop_version,
    );

    let notify_signal = if notifable && trampoline_name.is_ok() {
        imports.add_used_types(&used_types, prop_version);
        if generate_trait {
            imports.add("glib", prop_version);
            imports.add("glib::object::Downcast", prop_version);
        }
        imports.add("glib::signal::connect", prop_version);
        imports.add("glib::signal::SignalHandlerId", prop_version);
        imports.add("std::mem::transmute", prop_version);
        imports.add("std::boxed::Box as Box_", prop_version);
        imports.add("glib_ffi", prop_version);

        Some(signals::Info {
            connect_name: format!("connect_property_{}_notify", name_for_func),
            signal_name: format!("notify::{}", name),
            trampoline_name,
            action_emit_name: None,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            doc_hidden: false,
        })
    } else {
        None
    };

    (getter, setter, notify_signal)
}
<commit_msg>Add warning for configure generating getter/setter for notreadable/notwritable property<commit_after>use analysis::bounds::Bound;
use analysis::imports::Imports;
use analysis::ref_mode::RefMode;
use analysis::rust_type::*;
use analysis::signals;
use analysis::signatures::{Signature, Signatures};
use analysis::trampolines;
use config::{self, GObject, PropertyGenerateFlags};
use env::Env;
use library;
use nameutil;
use traits::*;
use version::Version;

#[derive(Debug)]
pub struct Property {
    pub name: String,
    pub var_name: String,
    pub typ: library::TypeId,
    pub is_get: bool,
    pub func_name: String,
    pub nullable: library::Nullable,
    pub get_out_ref_mode: RefMode,
    pub set_in_ref_mode: RefMode,
    pub version: Option<Version>,
    pub deprecated_version: Option<Version>,
    pub bound: Option<Bound>,
}

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Vec<Property>, Vec<signals::Info>) {
    let mut properties = Vec::new();
    let mut notify_signals = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if configured_properties.iter().any(|f| f.ignore) {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }

        let (getter, setter, notify_signal) = analyze_property(
            env,
            prop,
            type_tid,
            &configured_properties,
            generate_trait,
            trampolines,
            obj,
            imports,
            signatures,
            deps,
        );

        if let Some(notify_signal) = notify_signal {
            notify_signals.push(notify_signal);
        }

        if getter.is_none() && setter.is_none() {
            continue;
        }

        let type_string = rust_type(env, prop.typ);
        let used_type_string = used_rust_type(env, prop.typ);
        if let Some(prop) = getter {
            if let Ok(ref s) = used_type_string {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
                imports.add("glib::StaticType", prop.version);
            }

            properties.push(prop);
        }
        if let Some(prop) = setter {
            if let Ok(ref s) = used_type_string {
                imports.add_used_type(s, prop.version);
            }
            if type_string.is_ok() {
                imports.add("gobject_ffi", prop.version);
                imports.add("glib::Value", prop.version);
            }

            if prop.bound.is_some() {
                imports.add("glib", prop.version);
                imports.add("glib::object::IsA", prop.version);
            }

            properties.push(prop);
        }
    }

    (properties, notify_signals)
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    type_tid: library::TypeId,
    configured_properties: &[&config::properties::Property],
    generate_trait: bool,
    trampolines: &mut trampolines::Trampolines,
    obj: &GObject,
    imports: &mut Imports,
    signatures: &Signatures,
    deps: &[library::TypeId],
) -> (Option<Property>, Option<Property>, Option<signals::Info>) {
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or_else(|| Some(env.config.min_cfg_version));
    let generate = configured_properties
        .iter()
        .filter_map(|f| f.generate)
        .next();
    let generate_set = generate.is_some();
    let generate = generate.unwrap_or_else(PropertyGenerateFlags::all);

    let name_for_func = nameutil::signal_to_snake(&name);
    let var_name = nameutil::mangle_keywords(&*name_for_func).into_owned();
    let get_func_name = format!("get_property_{}", name_for_func);
    let set_func_name = format!("set_property_{}", name_for_func);
    let check_get_func_name = format!("get_{}", name_for_func);
    let check_set_func_name = format!("set_{}", name_for_func);

    let mut readable = prop.readable;
    let mut writable = if prop.construct_only {
        false
    } else {
        prop.writable
    };
    if generate_set && generate.contains(PropertyGenerateFlags::GET) && !readable {
        warn!(
            "Attempt to generate getter for notreadable property \"{}\"",
            name
        );
    }
    if generate_set && generate.contains(PropertyGenerateFlags::SET) && !writable {
        warn!(
            "Attempt to generate setter for nonwritable property \"{}\"",
            name
        );
    }
    readable &= generate.contains(PropertyGenerateFlags::GET);
    writable &= generate.contains(PropertyGenerateFlags::SET);
    let notifable = generate.contains(PropertyGenerateFlags::NOTIFY);

    if readable {
        let (has, version) = Signature::has_for_property(env, &check_get_func_name,
                                                         true, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            readable = false;
        }
    }
    if writable {
        let (has, version) = Signature::has_for_property(env, &check_set_func_name,
                                                         false, prop.typ, signatures, deps);
        if has && (env.is_totally_deprecated(version) || version <= prop_version) {
            writable = false;
        }
    }

    let get_out_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::Return);
    let mut set_in_ref_mode = RefMode::of(env, prop.typ, library::ParameterDirection::In);
    if set_in_ref_mode == RefMode::ByRefMut {
        set_in_ref_mode = RefMode::ByRef;
    }
    let nullable = library::Nullable(set_in_ref_mode.is_ref());
    let getter = if readable {
        Some(Property {
            name: name.clone(),
            var_name: String::new(),
            typ: prop.typ,
            is_get: true,
            func_name: get_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound: None,
        })
    } else {
        None
    };

    let setter = if writable {
        let bound = Bound::get_for_property_setter(env, &var_name, prop.typ, nullable);
        Some(Property {
            name: name.clone(),
            var_name,
            typ: prop.typ,
            is_get: false,
            func_name: set_func_name,
            nullable,
            get_out_ref_mode,
            set_in_ref_mode,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            bound,
        })
    } else {
        None
    };

    let mut used_types: Vec<String> = Vec::with_capacity(4);
    let trampoline_name = trampolines::analyze(
        env,
        &library::Signal {
            name: format!("notify::{}", name),
            parameters: Vec::new(),
            ret: library::Parameter {
                name: "".into(),
                typ: env.library
                    .find_type(library::INTERNAL_NAMESPACE, "none")
                    .unwrap(),
                c_type: "none".into(),
                instance_parameter: false,
                direction: library::ParameterDirection::Return,
                transfer: library::Transfer::None,
                caller_allocates: false,
                nullable: library::Nullable(false),
                allow_none: false,
                array_length: None,
                is_error: false,
                doc: None,
                scope: library::ParameterScope::None,
                closure: None,
                destroy: None,
            },
            is_action: false,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            doc: None,
            doc_deprecated: None,
        },
        type_tid,
        generate_trait,
        &[],
        trampolines,
        obj,
        &mut used_types,
        prop_version,
    );

    let notify_signal = if notifable && trampoline_name.is_ok() {
        imports.add_used_types(&used_types, prop_version);
        if generate_trait {
            imports.add("glib", prop_version);
            imports.add("glib::object::Downcast", prop_version);
        }
        imports.add("glib::signal::connect", prop_version);
        imports.add("glib::signal::SignalHandlerId", prop_version);
        imports.add("std::mem::transmute", prop_version);
        imports.add("std::boxed::Box as Box_", prop_version);
        imports.add("glib_ffi", prop_version);

        Some(signals::Info {
            connect_name: format!("connect_property_{}_notify", name_for_func),
            signal_name: format!("notify::{}", name),
            trampoline_name,
            action_emit_name: None,
            version: prop_version,
            deprecated_version: prop.deprecated_version,
            doc_hidden: false,
        })
    } else {
        None
    };

    (getter, setter, notify_signal)
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::ty::TypeVariants;
use rustc::hir::*;
use syntax::codemap::Span;
use utils::{higher, snippet, span_lint_and_then};

/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible.
///
/// **Why is this bad?** This is less efficient.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// foo(&vec![1, 2])
/// ```
declare_lint! {
    pub USELESS_VEC,
    Warn,
    "useless `vec!`"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(USELESS_VEC)
    }
}

impl LateLintPass for Pass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
        if_let_chain!{[
            let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty,
            let TypeVariants::TySlice(..) = ty.ty.sty,
            let ExprAddrOf(_, ref addressee) = expr.node,
        ], {
            check_vec_macro(cx, addressee, expr.span);
        }}

        // search for `for _ in vec![…]`
        if let Some((_, arg, _)) = higher::for_loop(expr) {
            // report the error around the `vec!` not inside `<std macros>:`
            let span = cx.sess().codemap().source_callsite(arg.span);
            check_vec_macro(cx, arg, span);
        }
    }
}

fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) {
    if let Some(vec_args) = higher::vec_macro(cx, vec) {
        let snippet = match vec_args {
            higher::VecArgs::Repeat(elem, len) => {
                format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
            }
            higher::VecArgs::Vec(args) => {
                if let Some(last) = args.iter().last() {
                    let span = Span {
                        lo: args[0].span.lo,
                        hi: last.span.hi,
                        expn_id: args[0].span.expn_id,
                    };

                    format!("&[{}]", snippet(cx, span, "..")).into()
                } else {
                    "&[]".into()
                }
            }
        };

        span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| {
            db.span_suggestion(span, "you can use a slice directly", snippet);
        });
    }
}

<commit_msg>Only build suggestion if necessary in `USELESS_VEC`<commit_after>use rustc::lint::*;
use rustc::ty::TypeVariants;
use rustc::hir::*;
use syntax::codemap::Span;
use utils::{higher, snippet, span_lint_and_then};

/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible.
///
/// **Why is this bad?** This is less efficient.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// foo(&vec![1, 2])
/// ```
declare_lint! {
    pub USELESS_VEC,
    Warn,
    "useless `vec!`"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(USELESS_VEC)
    }
}

impl LateLintPass for Pass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
        if_let_chain!{[
            let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty,
            let TypeVariants::TySlice(..) = ty.ty.sty,
            let ExprAddrOf(_, ref addressee) = expr.node,
        ], {
            check_vec_macro(cx, addressee, expr.span);
        }}

        // search for `for _ in vec![…]`
        if let Some((_, arg, _)) = higher::for_loop(expr) {
            // report the error around the `vec!` not inside `<std macros>:`
            let span = cx.sess().codemap().source_callsite(arg.span);
            check_vec_macro(cx, arg, span);
        }
    }
}

fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) {
    if let Some(vec_args) = higher::vec_macro(cx, vec) {
        span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| {
            let snippet = match vec_args {
                higher::VecArgs::Repeat(elem, len) => {
                    format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
                }
                higher::VecArgs::Vec(args) => {
                    if let Some(last) = args.iter().last() {
                        let span = Span {
                            lo: args[0].span.lo,
                            hi: last.span.hi,
                            expn_id: args[0].span.expn_id,
                        };

                        format!("&[{}]", snippet(cx, span, "..")).into()
                    } else {
                        "&[]".into()
                    }
                }
            };

            db.span_suggestion(span, "you can use a slice directly", snippet);
        });
    }
}

<|endoftext|>


<commit_before>//! TODO Fill in

use render;
use gdk_pixbuf::Pixbuf;
use glib::translate::ToGlibPtr;
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::class::{self, Class, ClassBuilder};

#[derive(Clone, Debug)]
pub struct AwesomeState {
    // TODO Fill in
    dummy: i32
}

pub struct Awesome<'lua>(Table<'lua>);

impl Default for AwesomeState {
    fn default() -> Self {
        AwesomeState {
            dummy: 0
        }
    }
}

impl <'lua> Awesome<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        // TODO FIXME
        let class = class::button_class(lua)?;
        Ok(Awesome::allocate(lua, class)?.build())
    }
}

impl Display for AwesomeState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Awesome: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Awesome<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for AwesomeState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Awesome::new)), None, None)?)?)?
        .save_class("awesome")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("register_xproperty".into(), lua.create_function(register_xproperty))?
           .method("xkb_get_group_names".into(), lua.create_function(xkb_get_group_names))?
           .method("restart".into(), lua.create_function(restart))?
           .method("load_image".into(), lua.create_function(load_image))?
           .method("quit".into(), lua.create_function(quit))
}

/// Registers a new X property
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
    warn!("register_xproperty not supported");
    Ok(())
}

/// Get layout short names
fn xkb_get_group_names<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    warn!("xkb_get_group_names not supported");
    Ok(())
}

/// Restart Awesome by restarting the Lua thread
fn restart<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    use lua::{self, LuaQuery};
    if let Err(err) = lua::send(LuaQuery::Restart) {
        warn!("Could not restart Lua thread {:#?}", err);
    }
    Ok(())
}

/// Load an image from the given path
/// Returns either a cairo surface as light user data, nil and an error message
fn load_image<'lua>(lua: &'lua Lua, file_path: String) -> rlua::Result<Value<'lua>> {
    // TODO Move to render module
    let pixbuf = Pixbuf::new_from_file(file_path.as_str())
        .map_err(|err| rlua::Error::RuntimeError(format!("{}", err)))?;
    let surface = render::load_surface_from_pixbuf(pixbuf);
    // UGH, I wanted to do to_glib_full, but that isn't defined apparently
    // So now I have to ignore the lifetime completely and just forget about the surface.
    let surface_ptr = surface.to_glib_none().0;
    ::std::mem::forget(surface);
    rlua::LightUserData(surface_ptr as _).to_lua(lua)
}

fn quit<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    ::rustwlc::terminate();
    Ok(())
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    builder.dummy_property("version".into(), "0".to_lua(lua)?)?
           .dummy_property("themes_path".into(), "/usr/share/awesome/themes".to_lua(lua)?)?
           .dummy_property("conffile".into(), "".to_lua(lua)?)
}

impl_objectable!(Awesome, AwesomeState);
<commit_msg>TODO comment removal<commit_after>//! TODO Fill in

use render;
use gdk_pixbuf::Pixbuf;
use glib::translate::ToGlibPtr;
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::class::{self, Class, ClassBuilder};

#[derive(Clone, Debug)]
pub struct AwesomeState {
    // TODO Fill in
    dummy: i32
}

pub struct Awesome<'lua>(Table<'lua>);

impl Default for AwesomeState {
    fn default() -> Self {
        AwesomeState {
            dummy: 0
        }
    }
}

impl <'lua> Awesome<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        // TODO FIXME
        let class = class::button_class(lua)?;
        Ok(Awesome::allocate(lua, class)?.build())
    }
}

impl Display for AwesomeState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Awesome: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Awesome<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for AwesomeState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Awesome::new)), None, None)?)?)?
        .save_class("awesome")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("register_xproperty".into(), lua.create_function(register_xproperty))?
           .method("xkb_get_group_names".into(), lua.create_function(xkb_get_group_names))?
           .method("restart".into(), lua.create_function(restart))?
           .method("load_image".into(), lua.create_function(load_image))?
           .method("quit".into(), lua.create_function(quit))
}

/// Registers a new X property
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
    warn!("register_xproperty not supported");
    Ok(())
}

/// Get layout short names
fn xkb_get_group_names<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    warn!("xkb_get_group_names not supported");
    Ok(())
}

/// Restart Awesome by restarting the Lua thread
fn restart<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    use lua::{self, LuaQuery};
    if let Err(err) = lua::send(LuaQuery::Restart) {
        warn!("Could not restart Lua thread {:#?}", err);
    }
    Ok(())
}

/// Load an image from the given path
/// Returns either a cairo surface as light user data, nil and an error message
fn load_image<'lua>(lua: &'lua Lua, file_path: String) -> rlua::Result<Value<'lua>> {
    let pixbuf = Pixbuf::new_from_file(file_path.as_str())
        .map_err(|err| rlua::Error::RuntimeError(format!("{}", err)))?;
    let surface = render::load_surface_from_pixbuf(pixbuf);
    // UGH, I wanted to do to_glib_full, but that isn't defined apparently
    // So now I have to ignore the lifetime completely and just forget about the surface.
    let surface_ptr = surface.to_glib_none().0;
    ::std::mem::forget(surface);
    rlua::LightUserData(surface_ptr as _).to_lua(lua)
}

fn quit<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    ::rustwlc::terminate();
    Ok(())
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    builder.dummy_property("version".into(), "0".to_lua(lua)?)?
           .dummy_property("themes_path".into(), "/usr/share/awesome/themes".to_lua(lua)?)?
           .dummy_property("conffile".into(), "".to_lua(lua)?)
}

impl_objectable!(Awesome, AwesomeState);
<|endoftext|>


<commit_before>//! # TreeView Sample
//!
//! This sample demonstrates how to create a StatusIcon.

extern crate gdk_pixbuf;
extern crate gio;
extern crate glib;
extern crate gtk;

use gdk_pixbuf::Pixbuf;
use gio::MemoryInputStream;
use glib::Bytes;
use gtk::{
    ButtonsType, DialogExt, DialogFlags, Menu, MenuExt, MenuExtManual, MenuItem,
    MenuItemExt, MenuShellExt, MessageDialog, MessageType, StatusIcon, StatusIconExt, WidgetExt,
};

use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    gtk::init().expect("gtk initialization failed");

    let menu = Menu::new();
    let dialog_item = MenuItem::new_with_label("Show notification");
    let close_item = MenuItem::new_with_label("Close app");

    menu.append(&dialog_item);
    menu.append(&close_item);

    let is_shown = Rc::new(RefCell::new(false));

    let c_is_shown = is_shown.clone();
    dialog_item.connect_activate(move |_| {
        *c_is_shown.borrow_mut() = false;
        let parent: Option<&gtk::Window> = None; // stupid hack to avoid rustc error
        let diag = MessageDialog::new(parent,
                                      DialogFlags::MODAL,
                                      MessageType::Error,
                                      ButtonsType::Ok,
                                      "What about the Kirin Tor?");
        diag.run();
        diag.destroy();
    });
    close_item.connect_activate(|_| {
        println!("time to quit!");
        gtk::main_quit();
    });

    let memory_stream = MemoryInputStream::new_from_bytes(
                            &Bytes::from_static(include_bytes!("../../resources/menu.png")));
    let logo = Pixbuf::new_from_stream(&memory_stream, None);
    let logo = match logo {
        Ok(l) => l,
        Err(e) => {
            println!("Got an error: {:?}", e);
            return
        }
    };
    let status_icon = StatusIcon::new_from_pixbuf(&logo);

    status_icon.connect_popup_menu(move |_, _, _| {
        let new_shown = if *is_shown.borrow() == true {
            menu.popdown();
            false
        } else {
            menu.show_all();
            // Why 1? Well, any button is accepted so why not?
            menu.popup_easy(1, gtk::get_current_event_time());
            true
        };
        *is_shown.borrow_mut() = new_shown;
    });
    status_icon.connect_activate(|_| {
        let parent: Option<&gtk::Window> = None; // stupid hack to avoid rustc error
        let diag = MessageDialog::new(parent,
                                      DialogFlags::MODAL,
                                      MessageType::Info,
                                      ButtonsType::Ok,
                                      "Right click on the status icon!");
        diag.run();
        diag.destroy();
    });

    status_icon.set_visible(true);
    status_icon.set_has_tooltip(true);

    gtk::main();
}
<commit_msg>Allow deprecated for status icon<commit_after>//! # TreeView Sample
//!
//! This sample demonstrates how to create a StatusIcon.

#![allow(deprecated)]

extern crate gdk_pixbuf;
extern crate gio;
extern crate glib;
extern crate gtk;

use gdk_pixbuf::Pixbuf;
use gio::MemoryInputStream;
use glib::Bytes;
use gtk::{
    ButtonsType, DialogExt, DialogFlags, Menu, MenuExt, MenuExtManual, MenuItem,
    MenuItemExt, MenuShellExt, MessageDialog, MessageType, StatusIcon, StatusIconExt, WidgetExt,
};

use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    gtk::init().expect("gtk initialization failed");

    let menu = Menu::new();
    let dialog_item = MenuItem::new_with_label("Show notification");
    let close_item = MenuItem::new_with_label("Close app");

    menu.append(&dialog_item);
    menu.append(&close_item);

    let is_shown = Rc::new(RefCell::new(false));

    let c_is_shown = is_shown.clone();
    dialog_item.connect_activate(move |_| {
        *c_is_shown.borrow_mut() = false;
        let parent: Option<&gtk::Window> = None; // stupid hack to avoid rustc error
        let diag = MessageDialog::new(parent,
                                      DialogFlags::MODAL,
                                      MessageType::Error,
                                      ButtonsType::Ok,
                                      "What about the Kirin Tor?");
        diag.run();
        diag.destroy();
    });
    close_item.connect_activate(|_| {
        println!("time to quit!");
        gtk::main_quit();
    });

    let memory_stream = MemoryInputStream::new_from_bytes(
                            &Bytes::from_static(include_bytes!("../../resources/menu.png")));
    let logo = Pixbuf::new_from_stream(&memory_stream, None);
    let logo = match logo {
        Ok(l) => l,
        Err(e) => {
            println!("Got an error: {:?}", e);
            return
        }
    };
    let status_icon = StatusIcon::new_from_pixbuf(&logo);

    status_icon.connect_popup_menu(move |_, _, _| {
        let new_shown = if *is_shown.borrow() == true {
            menu.popdown();
            false
        } else {
            menu.show_all();
            // Why 1? Well, any button is accepted so why not?
            menu.popup_easy(1, gtk::get_current_event_time());
            true
        };
        *is_shown.borrow_mut() = new_shown;
    });
    status_icon.connect_activate(|_| {
        let parent: Option<&gtk::Window> = None; // stupid hack to avoid rustc error
        let diag = MessageDialog::new(parent,
                                      DialogFlags::MODAL,
                                      MessageType::Info,
                                      ButtonsType::Ok,
                                      "Right click on the status icon!");
        diag.run();
        diag.destroy();
    });

    status_icon.set_visible(true);
    status_icon.set_has_tooltip(true);

    gtk::main();
}
<|endoftext|>


<commit_before>extern crate orbtk;

use orbtk::{Button, Point, Rect, TextBox, Window};
use orbtk::callback::{Click, Enter};
use orbtk::place::Place;

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => panic!("Invalid operator")
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: input.len() too generous?
    let mut tokens = Vec::with_capacity(input.len());

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
#[cfg(not(target_os = "redox"))]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

#[cfg(target_os = "redox")]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                //TODO: g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens).map(|answer| answer.value.to_string())
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(_e) => "Syntax Error".to_string()
    }
}

fn main(){
    let mut window = Window::new(Rect::new(100, 100, 148, 200), "Calculator");

    {
        let text_box = TextBox::new()
            .position(0, 0)
            .size(300, 16)
            .on_enter(move |text_box: &TextBox| {
                let input = text_box.text.get();
                let result = eval(&input);
                println!("{}={}", input, result);
                text_box.text_i.set(result.len());
                text_box.text.set(result);
            })
            .place(&mut window);

        let mut col = 0;
        let mut row = 0;

        {
            let mut btn = |name| {
                let text_box_clone = text_box.clone();
                Button::new()
                    .position(col * 36 + 4, row * 36 + 20)
                    .size(32, 32)
                    .text(name)
                    .text_offset(12, 8)
                    .on_click(move |_button: &Button, _point: Point| {
                        let text_i = text_box_clone.text_i.get();

                        let text = text_box_clone.text.get();

                        let mut new_text = String::new();
                        new_text.push_str(&text[.. text_i]);
                        new_text.push_str(name);
                        new_text.push_str(&text[text_i ..]);

                        text_box_clone.text.set(new_text);

                        text_box_clone.text_i.set(text_i + name.len());
                    })
                    .place(&mut window);
                col += 1;
                if col >= 4 {
                    col = 0;
                    row += 1;
                }
            };

            btn("("); btn(")"); btn("^"); btn("/");
            btn("7"); btn("8"); btn("9"); btn("*");
            btn("4"); btn("5"); btn("6"); btn("-");
            btn("1"); btn("2"); btn("3"); btn("+");
            btn("0"); btn("0"); btn(".");
        }

        {
            let text_box_clone = text_box.clone();
            Button::new()
                .position(col * 36 + 4, row * 36 + 20)
                .size(32, 32)
                .text("=")
                .text_offset(12, 8)
                .on_click(move |_button: &Button, _point: Point| {
                    text_box_clone.emit_enter();
                })
                .place(&mut window);
        }
    }

    window.exec();
}
<commit_msg>Do not print calculator data<commit_after>extern crate orbtk;

use orbtk::{Button, Point, Rect, TextBox, Window};
use orbtk::callback::{Click, Enter};
use orbtk::place::Place;

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => panic!("Invalid operator")
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: input.len() too generous?
    let mut tokens = Vec::with_capacity(input.len());

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
#[cfg(not(target_os = "redox"))]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

#[cfg(target_os = "redox")]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                //TODO: g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens).map(|answer| answer.value.to_string())
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(_e) => "Syntax Error".to_string()
    }
}

fn main(){
    let mut window = Window::new(Rect::new(100, 100, 148, 200), "Calculator");

    {
        let text_box = TextBox::new()
            .position(0, 0)
            .size(300, 16)
            .on_enter(move |text_box: &TextBox| {
                let input = text_box.text.get();
                let result = eval(&input);
                text_box.text_i.set(result.len());
                text_box.text.set(result);
            })
            .place(&mut window);

        let mut col = 0;
        let mut row = 0;

        {
            let mut btn = |name| {
                let text_box_clone = text_box.clone();
                Button::new()
                    .position(col * 36 + 4, row * 36 + 20)
                    .size(32, 32)
                    .text(name)
                    .text_offset(12, 8)
                    .on_click(move |_button: &Button, _point: Point| {
                        let text_i = text_box_clone.text_i.get();

                        let text = text_box_clone.text.get();

                        let mut new_text = String::new();
                        new_text.push_str(&text[.. text_i]);
                        new_text.push_str(name);
                        new_text.push_str(&text[text_i ..]);

                        text_box_clone.text.set(new_text);

                        text_box_clone.text_i.set(text_i + name.len());
                    })
                    .place(&mut window);
                col += 1;
                if col >= 4 {
                    col = 0;
                    row += 1;
                }
            };

            btn("("); btn(")"); btn("^"); btn("/");
            btn("7"); btn("8"); btn("9"); btn("*");
            btn("4"); btn("5"); btn("6"); btn("-");
            btn("1"); btn("2"); btn("3"); btn("+");
            btn("0"); btn("0"); btn(".");
        }

        {
            let text_box_clone = text_box.clone();
            Button::new()
                .position(col * 36 + 4, row * 36 + 20)
                .size(32, 32)
                .text("=")
                .text_offset(12, 8)
                .on_click(move |_button: &Button, _point: Point| {
                    text_box_clone.emit_enter();
                })
                .place(&mut window);
        }
    }

    window.exec();
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::env;
use std::fs;
use std::io;
use std::process;

use clap::ArgMatches;
use hyper::{Client, Url};
use kuchiki;
use tempdir::TempDir;

use config::Config;
use downloader;
use extractor;
use profile;

pub fn init() {
    let config = Config::new();
    if config.install_dir.exists() || config.shim_dir.exists() {
        println!("Already initalized. Reinitializing....");
    }
    fs::create_dir_all(&config.install_dir).expect("Could not create installation directory.");
    fs::create_dir_all(&config.shim_dir).expect("Could not create shims directory.");
    fs::create_dir_all(&config.versions_dir).expect("Could not create versions directory.");
    if !env::home_dir()
        .unwrap_or_else(|| panic!("Cound not found homedir."))
        .join("Documents")
        .join("WindowsPowerShell")
        .join("profile.ps1")
        .exists()
    {
        println!(
            r#"Please create profile.ps1 in the following place:

$Env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1

And write the following thing:

. $Env:USERPROFILE\.groonga\shims\bin\source-groonga.ps1
"#
        )
    }
}

pub fn install(m: &ArgMatches) {
    extern crate env_proxy;

    const BASE_URL: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy = env_proxy::for_url(&Url::parse(BASE_URL).unwrap());
    let config = Config::from_matches(m);
    println!(
        "Value for architecture: {}",
        config.arch.clone().expect("unsupported platform")
    );
    println!(
        "Obtaining Groonga version: {}",
        config.version.clone().unwrap()
    );
    let groonga_dir = format!(
        "groonga-{}-{}",
        config.version.unwrap(),
        config.arch.unwrap()
    );
    let groonga_binary = format!("{}.zip", groonga_dir.clone());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Already installed. Ready to use it.");
        return ();
    }

    let download_dir = TempDir::new("grnenv-rs")
        .expect("Could not create temp dir.")
        .into_path();

    let client = match maybe_proxy {
        None => Client::new(),
        Some(host_port) => Client::with_http_proxy(host_port.0, host_port.1),
    };
    let filename = downloader::file_download(
        &client,
        &*format!("{}/{}", BASE_URL, groonga_binary),
        download_dir,
        "groonga.zip",
    ).expect("Failed to download");
    assert!(extractor::extract_zip(&filename, &config.versions_dir).is_ok());
}

pub fn switch(m: &ArgMatches) {
    let config = Config::from_matches(m);
    println!(
        "Value for architecture: {}",
        config.arch.clone().expect("unsupported platform")
    );
    println!("Using Groonga version: {}", config.version.clone().unwrap());
    let groonga_dir = format!(
        "groonga-{}-{}",
        config.version.unwrap(),
        config.arch.unwrap()
    );
    match config.version {
        Some("system") => {
            profile::windows::remove_grnenv_profile(&config.shim_dir).unwrap();
            return ();
        }
        Some(_) => profile::windows::create_profile_source(
            &config.shim_dir,
            &groonga_dir,
            &config.versions_dir,
        ).expect("Could not create source-groonga.ps1"),
        None => unreachable!(),
    }
}

pub fn uninstall(m: &ArgMatches) {
    let config = Config::from_matches(m);
    let mut choice = String::new();
    let arch = match config.arch.unwrap() {
        Cow::Borrowed(s) => s.to_owned(),
        Cow::Owned(s) => s,
    };
    let groonga_dir = format!("groonga-{}-{}", config.version.unwrap(), arch);
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!(
            "Uninstall Groonga version {}, arch {}? [y/N]",
            config.version.unwrap(),
            arch
        );
        io::stdin()
            .read_line(&mut choice)
            .expect("Failed to read line");
        if choice == "y".to_owned() || choice == "Y".to_owned() {
            println!("Removing {}....", groonga_dir.clone());
            fs::remove_dir_all(&config.versions_dir.join(groonga_dir))
                .expect("Could not remove specified directory.");
        }
    } else {
        println!("{} is not installed!", groonga_dir.clone());
        process::exit(1);
    }
}

pub fn list() {
    use command::common::MaybeProxyUrl;
    use kuchiki::traits::*;

    let base_url: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy_url = MaybeProxyUrl {
        url: Url::parse(base_url).unwrap(),
    };
    if let Ok(doc) = kuchiki::parse_html().from_http(maybe_proxy_url) {
        let docs = doc.select("tr").unwrap().collect::<Vec<_>>();
        println!("Installable Groonga:");
        for handle in &docs {
            let texts = handle
                .as_node()
                .descendants()
                .text_nodes()
                .collect::<Vec<_>>();
            if let Some(text) = texts.first() {
                let package = text.as_node().text_contents();
                if package.contains("groonga")
                    && package.contains("zip")
                    && (package.contains("x86") || package.contains("x64"))
                {
                    let package = package.split(".zip").collect::<Vec<_>>();
                    let pkg = package
                        .first()
                        .unwrap_or(&"")
                        .to_owned()
                        .split("-")
                        .collect::<Vec<_>>();
                    println!(
                        "\t{} --arch {}",
                        pkg.get(1).unwrap_or(&""),
                        pkg.get(2).unwrap_or(&"")
                    );
                }
            }
        }
    } else {
        println!("{}", "The page couldn't be fetched");
    }
}
<commit_msg>windows: Use reqwest instead of hyper<commit_after>use std::borrow::Cow;
use std::env;
use std::fs;
use std::io;
use std::process;

use clap::ArgMatches;
use kuchiki;
use tempdir::TempDir;

use config::Config;
use downloader;
use extractor;
use profile;
use reqwest::{Client, Proxy, Url};

pub fn init() {
    let config = Config::new();
    if config.install_dir.exists() || config.shim_dir.exists() {
        println!("Already initalized. Reinitializing....");
    }
    fs::create_dir_all(&config.install_dir).expect("Could not create installation directory.");
    fs::create_dir_all(&config.shim_dir).expect("Could not create shims directory.");
    fs::create_dir_all(&config.versions_dir).expect("Could not create versions directory.");
    if !env::home_dir()
        .unwrap_or_else(|| panic!("Cound not found homedir."))
        .join("Documents")
        .join("WindowsPowerShell")
        .join("profile.ps1")
        .exists()
    {
        println!(
            r#"Please create profile.ps1 in the following place:

$Env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1

And write the following thing:

. $Env:USERPROFILE\.groonga\shims\bin\source-groonga.ps1
"#
        )
    }
}

pub fn install(m: &ArgMatches) {
    extern crate env_proxy;

    const BASE_URL: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy = env_proxy::for_url(&Url::parse(BASE_URL).unwrap());
    let config = Config::from_matches(m);
    println!(
        "Value for architecture: {}",
        config.arch.clone().expect("unsupported platform")
    );
    println!(
        "Obtaining Groonga version: {}",
        config.version.clone().unwrap()
    );
    let groonga_dir = format!(
        "groonga-{}-{}",
        config.version.unwrap(),
        config.arch.unwrap()
    );
    let groonga_binary = format!("{}.zip", groonga_dir.clone());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Already installed. Ready to use it.");
        return ();
    }

    let download_dir = TempDir::new("grnenv-rs")
        .expect("Could not create temp dir.")
        .into_path();

    let client = match maybe_proxy {
        None => Client::new(),
        Some(_) => Client::builder()
            .proxy(Proxy::http(BASE_URL).unwrap())
            .build()
            .expect("Could not create proxy."),
    };
    let filename = downloader::file_download(
        &client,
        &*format!("{}/{}", BASE_URL, groonga_binary),
        download_dir,
        "groonga.zip",
    ).expect("Failed to download");
    assert!(extractor::extract_zip(&filename, &config.versions_dir).is_ok());
}

pub fn switch(m: &ArgMatches) {
    let config = Config::from_matches(m);
    println!(
        "Value for architecture: {}",
        config.arch.clone().expect("unsupported platform")
    );
    println!("Using Groonga version: {}", config.version.clone().unwrap());
    let groonga_dir = format!(
        "groonga-{}-{}",
        config.version.unwrap(),
        config.arch.unwrap()
    );
    match config.version {
        Some("system") => {
            profile::windows::remove_grnenv_profile(&config.shim_dir).unwrap();
            return ();
        }
        Some(_) => profile::windows::create_profile_source(
            &config.shim_dir,
            &groonga_dir,
            &config.versions_dir,
        ).expect("Could not create source-groonga.ps1"),
        None => unreachable!(),
    }
}

pub fn uninstall(m: &ArgMatches) {
    let config = Config::from_matches(m);
    let mut choice = String::new();
    let arch = match config.arch.unwrap() {
        Cow::Borrowed(s) => s.to_owned(),
        Cow::Owned(s) => s,
    };
    let groonga_dir = format!("groonga-{}-{}", config.version.unwrap(), arch);
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!(
            "Uninstall Groonga version {}, arch {}? [y/N]",
            config.version.unwrap(),
            arch
        );
        io::stdin()
            .read_line(&mut choice)
            .expect("Failed to read line");
        if choice == "y".to_owned() || choice == "Y".to_owned() {
            println!("Removing {}....", groonga_dir.clone());
            fs::remove_dir_all(&config.versions_dir.join(groonga_dir))
                .expect("Could not remove specified directory.");
        }
    } else {
        println!("{} is not installed!", groonga_dir.clone());
        process::exit(1);
    }
}

pub fn list() {
    extern crate env_proxy;
    use kuchiki::traits::*;

    let base_url: &'static str = "http://packages.groonga.org/windows/groonga";
    let maybe_proxy = env_proxy::for_url(&Url::parse(base_url).unwrap());
    let client = match maybe_proxy {
        None => Client::new(),
        Some(_) => Client::builder()
            .proxy(Proxy::http(base_url).unwrap())
            .build()
            .expect("Could not create proxy."),
    };
    let page = downloader::page_download(&client, &*format!("{}", base_url))
        .expect("Failed to download page");
    let doc = kuchiki::parse_html().one(page);
    let docs = doc.select("tr").unwrap().collect::<Vec<_>>();
    println!("Installable Groonga:");
    for handle in &docs {
        let texts = handle
            .as_node()
            .descendants()
            .text_nodes()
            .collect::<Vec<_>>();
        if let Some(text) = texts.first() {
            let package = text.as_node().text_contents();
            if package.contains("groonga")
                && package.contains("zip")
                && (package.contains("x86") || package.contains("x64"))
            {
                let package = package.split(".zip").collect::<Vec<_>>();
                let pkg = package
                    .first()
                    .unwrap_or(&"")
                    .to_owned()
                    .split("-")
                    .collect::<Vec<_>>();
                println!(
                    "\t{} --arch {}",
                    pkg.get(1).unwrap_or(&""),
                    pkg.get(2).unwrap_or(&"")
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! decode_op(
	($op:ident $handler:ident $data:ident) => (
		match $op {
			0x20 => $handler.add($data),
			0x30 => $handler.addc($data),
			0x28 => $handler.and($data),
			0x38 => $handler.andc($data),
			0x1C => $handler.beq($data),
			0x1D => $handler.bne($data),
			0x24 => $handler.cmpeq($data),
			0x34 => $handler.cmpeqc($data),
			0x26 => $handler.cmple($data),
			0x36 => $handler.cmplec($data),
			0x25 => $handler.cmplt($data),
			0x35 => $handler.cmpltc($data),
			0x23 => $handler.div($data),
			0x33 => $handler.divc($data),
			0x1B => $handler.jmp($data),
			0x18 => $handler.ld($data),
			0x1F => $handler.ldr($data),
			0x22 => $handler.mul($data),
			0x32 => $handler.mulc($data),
			0x29 => $handler.or($data),
			0x39 => $handler.orc($data),
			0x2C => $handler.shl($data),
			0x3C => $handler.shlc($data),
			0x2D => $handler.shr($data),
			0x3D => $handler.shrc($data),
			0x2E => $handler.sra($data),
			0x3E => $handler.srac($data),
			0x21 => $handler.sub($data),
			0x31 => $handler.subc($data),
			0x19 => $handler.st($data),
			0x2A => $handler.xor($data),
			0x3A => $handler.xorc($data),
			0x2B => $handler.xnor($data),
			0x3B => $handler.xnorc($data),
			_ => fail!("Unrecognized opcode.")
		}
)
)

fn each(v: &mut [u32], op: &fn(v: &mut u32)) {
	let mut n = 0;
	while n < v.len() {
		op(&mut v[n]);
		n += 1;
	}
}

pub struct Mem {
	data:	[u8, ..4096]
}

impl Mem {
	fn read(&self, addr: u32) -> u8 {
		self.data[addr]
	}

	fn read_u32(&self, addr: u32) -> u32 {
		let b1 = self.read(addr) as u32;
		let b2 = self.read(addr + 1) as u32;
		let b3 = self.read(addr + 2) as u32;
		let b4 = self.read(addr + 3) as u32;

		(b1 << 24) | (b2 << 16) | (b3 << 8) | b4
	}

	pub fn write(&mut self, addr: u32, val: u8) {
		self.data[addr] = val;
	}

	fn write_u32(&mut self, addr: u32, val: u32) {
		self.data[addr]		= (val >> 24 & 0xFF) as u8;
		self.data[addr + 1]	= (val >> 16 & 0xFF) as u8;
		self.data[addr + 2]	= (val >> 8 & 0xFF) as u8;
		self.data[addr + 3]	= (val & 0xFF) as u8;
	}
}

pub struct Beta {
	pc:			u32,
	register:	[u32, ..31],
	mem:		Mem
}

impl Beta {
	pub fn reset(&mut self) {
		self.pc = 0;
		do each(self.register) |r| { *r = 0; }

		//println(fmt!("reset. pc at %d", self.pc as int));
	}

	pub fn tick(&mut self) {
		let instruction: u32 = self.mem.read_u32(self.pc);

		// decode invariant part of instruction format
		let op = instruction >> 26;
		let data = instruction & 0x3FFFFFFF;

		println(fmt!("op: 0x%x", op as uint));

		decode_op!(op self data)

		self.pc += 4;
		//println(fmt!("tick. pc at %d", self.pc as int));
	}

	fn dump(&self) {
		for i in range(0, self.mem.data.len()) {
			print(fmt!("%x, ", self.mem.data[i] as uint));
		}
	}

	fn read_reg(&self, reg: uint) -> u32 {
		match reg {
			0..30	=> self.register[reg],
			31		=> 0,
			_		=> fail!(fmt!("tried to read from nonexistant register %d (0x%x)", reg as int, reg as uint))
		}
	}

	fn write_reg(&mut self, reg: uint, val: u32) {
		match reg {
			0..30	=> self.register[reg] = val,
			31		=> {},
			_		=> fail!(fmt!("tried to write to nonexistant register %d", reg as int))
		};
	}

	fn args(data: u32) -> (u32, u32, u32) {
		(data >> 21 & 0x1F, data >> 16 & 0x1F, data >> 11)
	}

	fn args_literal(data: u32) -> (u32, u32, u32) {
		(data >> 21 & 0x1F, data >> 16 & 0x1F, data & 0xFFFF)
	}

	fn exec_op(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, r_b) = Beta::args(data);
		let a = self.read_reg(r_a as uint);
		let b = self.read_reg(r_b as uint);
		self.write_reg(r_c as uint, exp(a, b));
		println(fmt!("fn \"%?\"", exp));
	}

	fn exec_op_lit(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);
		self.write_reg(r_c as uint, exp(a, lit));
		println(fmt!("fn \"%?\"", exp));
	}

	/* INSTRUCTION SET */

	fn add(&mut self, data: u32) {
		self.exec_op(data, |a, b| a + b);
	}

	fn addc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a + b);
	}

	fn and(&mut self, data: u32) {
		self.exec_op(data, |a, b| a & b);
	}

	fn andc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a & b);
	}

	fn beq(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = (lit as i16 as u32)*4;
		let target = self.pc + 4 + displacement;

		if(a == 0) { self.pc = target; }
	}

	fn bne(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = (lit as i16 as u32)*4;
		let target = self.pc + 4 + displacement;

		if(a != 0) { self.pc = target; }
	}

	fn cmpeq(&mut self, data: u32) {
		self.exec_op(data, |a, b| if(a == b) {1} else {0});
	}

	fn cmpeqc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| if(a == b) {1} else {0});
	}

	fn cmple(&mut self, data: u32) {
		self.exec_op(data, |a, b| if(a <= b) {1} else {0});
	}

	fn cmplec(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| if(a <= b) {1} else {0});
	}

	fn cmplt(&mut self, data: u32) {
		self.exec_op(data, |a, b| if(a < b) {1} else {0});
	}

	fn cmpltc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| if(a < b) {1} else {0});
	}

	fn div(&mut self, data: u32) {
		self.exec_op(data, |a, b| a / b);
	}

	fn divc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a / b);
	}

	fn jmp(&mut self, data: u32) {
		let (r_c, r_a, _lit) = Beta::args_literal(data);

		self.write_reg(r_c as uint, self.pc + 4);
		self.pc = self.read_reg(r_a as uint) & 0xFFFFFFFC;
	}

	fn ld(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		let ea = a + (lit as i16 as u32);
		let val = self.mem.read_u32(ea as u32);

		self.write_reg(r_c as uint, val)
	}

	fn ldr(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		let ea = (self.pc & 0x7FFFFFFF) + 4 + (lit as i16 as u32)*4;
		let memval = self.mem.read_u32(ea);

		self.write_reg(r_c as uint, memval);

		if(a != 0b11111) { warn!("\"The Ra field is ignored and should be 11111.\" It is not."); }
	}

	fn mul(&mut self, data: u32) {
		self.exec_op(data, |a, b| a*b)
	}

	fn mulc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a*b)
	}

	fn or(&mut self, data: u32) {
		self.exec_op(data, |a, b| a|b)
	}

	fn orc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a|b)
	}

	fn shl(&mut self, data: u32) {
		self.exec_op(data, |a, b| a << b)
	}

	fn shlc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a << b)
	}

	fn shr(&mut self, data: u32) {
		self.exec_op(data, |a, b| a >> b)
	}

	fn shrc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a >> b)
	}

	fn sra(&mut self, data: u32) {
		self.exec_op(data, |a, b| ((a as i32) >> b) as u32)
	}

	fn srac(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| ((a as i32) >> b) as u32)
	}

	fn sub(&mut self, data: u32) {
		self.exec_op(data, |a, b| a - b)
	}

	fn subc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a - b)
	}

	fn st(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);
		let c = self.read_reg(r_c as uint);

		let ea = a + (lit as i16 as u32);

		self.mem.write_u32(ea, c)
	}

	fn xor(&mut self, data: u32) {
		self.exec_op(data, |a, b| a^b);
	}

	fn xorc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a^b);
	}

	fn xnor(&mut self, data: u32) {
		self.exec_op(data, |a, b| !(a^b));
	}

	fn xnorc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| !(a^b));
	}
}

<commit_msg>Per-instruction debugging information.<commit_after>macro_rules! decode_op(
	($op:ident $handler:ident $data:ident) => (
		match $op {
			0x20 => $handler.add($data),
			0x30 => $handler.addc($data),
			0x28 => $handler.and($data),
			0x38 => $handler.andc($data),
			0x1C => $handler.beq($data),
			0x1D => $handler.bne($data),
			0x24 => $handler.cmpeq($data),
			0x34 => $handler.cmpeqc($data),
			0x26 => $handler.cmple($data),
			0x36 => $handler.cmplec($data),
			0x25 => $handler.cmplt($data),
			0x35 => $handler.cmpltc($data),
			0x23 => $handler.div($data),
			0x33 => $handler.divc($data),
			0x1B => $handler.jmp($data),
			0x18 => $handler.ld($data),
			0x1F => $handler.ldr($data),
			0x22 => $handler.mul($data),
			0x32 => $handler.mulc($data),
			0x29 => $handler.or($data),
			0x39 => $handler.orc($data),
			0x2C => $handler.shl($data),
			0x3C => $handler.shlc($data),
			0x2D => $handler.shr($data),
			0x3D => $handler.shrc($data),
			0x2E => $handler.sra($data),
			0x3E => $handler.srac($data),
			0x21 => $handler.sub($data),
			0x31 => $handler.subc($data),
			0x19 => $handler.st($data),
			0x2A => $handler.xor($data),
			0x3A => $handler.xorc($data),
			0x2B => $handler.xnor($data),
			0x3B => $handler.xnorc($data),
			_ => fail!("Unrecognized opcode.")
		}
)
)

fn each(v: &mut [u32], op: &fn(v: &mut u32)) {
	let mut n = 0;
	while n < v.len() {
		op(&mut v[n]);
		n += 1;
	}
}

pub struct Mem {
	data:	[u8, ..4096]
}

impl Mem {
	fn read(&self, addr: u32) -> u8 {
		self.data[addr]
	}

	fn read_u32(&self, addr: u32) -> u32 {
		let b1 = self.read(addr) as u32;
		let b2 = self.read(addr + 1) as u32;
		let b3 = self.read(addr + 2) as u32;
		let b4 = self.read(addr + 3) as u32;

		(b1 << 24) | (b2 << 16) | (b3 << 8) | b4
	}

	pub fn write(&mut self, addr: u32, val: u8) {
		self.data[addr] = val;
	}

	fn write_u32(&mut self, addr: u32, val: u32) {
		self.data[addr]		= (val >> 24 & 0xFF) as u8;
		self.data[addr + 1]	= (val >> 16 & 0xFF) as u8;
		self.data[addr + 2]	= (val >> 8 & 0xFF) as u8;
		self.data[addr + 3]	= (val & 0xFF) as u8;
	}
}

pub struct Beta {
	pc:			u32,
	register:	[u32, ..31],
	mem:		Mem
}

impl Beta {
	pub fn reset(&mut self) {
		self.pc = 0;
		do each(self.register) |r| { *r = 0; }

		//println(fmt!("reset. pc at %d", self.pc as int));
	}

	pub fn tick(&mut self) {
		let instruction: u32 = self.mem.read_u32(self.pc);

		// decode invariant part of instruction format
		let op = instruction >> 26;
		let data = instruction & 0x3FFFFFFF;

		//println(fmt!("op: 0x%x", op as uint));

		print(fmt!("%x: ", instruction as uint));
		decode_op!(op self data)

		self.pc += 4;
		//println(fmt!("tick. pc at %d", self.pc as int));
	}

	pub fn dump_registers(&self) {
		for i in range(0, self.register.len()) {
			println(fmt!("r%d = %x", i as int, self.register[i] as uint));
		}
	}

	fn dump(&self) {
		for i in range(0, self.mem.data.len()) {
			print(fmt!("%x, ", self.mem.data[i] as uint));
		}
	}

	fn read_reg(&self, reg: uint) -> u32 {
		match reg {
			0..30	=> self.register[reg],
			31		=> 0,
			_		=> fail!(fmt!("tried to read from nonexistant register %d (0x%x)", reg as int, reg as uint))
		}
	}

	fn write_reg(&mut self, reg: uint, val: u32) {
		match reg {
			0..30	=> self.register[reg] = val,
			31		=> {},
			_		=> fail!(fmt!("tried to write to nonexistant register %d", reg as int))
		};
	}

	fn args(data: u32) -> (u32, u32, u32) {
		(data >> 21 & 0x1F, data >> 16 & 0x1F, data >> 11)
	}

	fn args_literal(data: u32) -> (u32, u32, u32) {
		(data >> 21 & 0x1F, data >> 16 & 0x1F, data & 0xFFFF)
	}

	fn exec_op(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, r_b) = Beta::args(data);
		println(fmt!("%x, %x, %x", r_c as uint, r_a as uint, r_b as uint));
		let a = self.read_reg(r_a as uint);
		let b = self.read_reg(r_b as uint);
		self.write_reg(r_c as uint, exp(a, b));
	}

	fn exec_op_lit(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		println(fmt!("%x, %x, %x", r_c as uint, r_a as uint, lit as uint));
		let a = self.read_reg(r_a as uint);
		self.write_reg(r_c as uint, exp(a, lit));
	}

	/* INSTRUCTION SET */

	fn add(&mut self, data: u32) {
		print("add ");
		self.exec_op(data, |a, b| a + b);
	}

	fn addc(&mut self, data: u32) {
		print("addc ");
		self.exec_op_lit(data, |a, b| a + b);
	}

	fn and(&mut self, data: u32) {
		print("and ");
		self.exec_op(data, |a, b| a & b);
	}

	fn andc(&mut self, data: u32) {
		print("andc ");
		self.exec_op_lit(data, |a, b| a & b);
	}

	fn beq(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		println(fmt!("beq %x, %x, %x", r_c as uint, r_a as uint, lit as uint));
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = (lit as i16 as u32)*4;
		let target = self.pc + 4 + displacement;

		if(a == 0) { self.pc = target; }
	}

	fn bne(&mut self, data: u32) {
		print("bne ");
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = (lit as i16 as u32)*4;
		let target = self.pc + 4 + displacement;

		if(a != 0) { self.pc = target; }
	}

	fn cmpeq(&mut self, data: u32) {
		print("cmpeq ");
		self.exec_op(data, |a, b| if(a == b) {1} else {0});
	}

	fn cmpeqc(&mut self, data: u32) {
		print("cmpeqc ");
		self.exec_op_lit(data, |a, b| if(a == b) {1} else {0});
	}

	fn cmple(&mut self, data: u32) {
		print("cmple ");
		self.exec_op(data, |a, b| if(a <= b) {1} else {0});
	}

	fn cmplec(&mut self, data: u32) {
		print("cmplec ");
		self.exec_op_lit(data, |a, b| if(a <= b) {1} else {0});
	}

	fn cmplt(&mut self, data: u32) {
		print("cmplt ");
		self.exec_op(data, |a, b| if(a < b) {1} else {0});
	}

	fn cmpltc(&mut self, data: u32) {
		print("cmpltc ");
		self.exec_op_lit(data, |a, b| if(a < b) {1} else {0});
	}

	fn div(&mut self, data: u32) {
		print("div ");
		self.exec_op(data, |a, b| a / b);
	}

	fn divc(&mut self, data: u32) {
		print("divc ");
		self.exec_op_lit(data, |a, b| a / b);
	}

	fn jmp(&mut self, data: u32) {
		let (r_c, r_a, _lit) = Beta::args_literal(data);
		println(fmt!("jmp %x, %x", r_c as uint, r_a as uint));

		self.write_reg(r_c as uint, self.pc + 4);
		self.pc = self.read_reg(r_a as uint) & 0xFFFFFFFC;
	}

	fn ld(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);

		println(fmt!("ld %x, %x, %x", r_c as uint, r_a as uint, lit as uint));

		let a = self.read_reg(r_a as uint);

		let ea = a + (lit as i16 as u32);
		let val = self.mem.read_u32(ea as u32);

		self.write_reg(r_c as uint, val)
	}

	fn ldr(&mut self, data: u32) {
		print("ldr ");
		let (r_c, r_a, lit) = Beta::args_literal(data);
		println(fmt!("ldr %x, %x, %x", r_c as uint, r_a as uint, lit as uint));
		let a = self.read_reg(r_a as uint);

		let ea = (self.pc & 0x7FFFFFFF) + 4 + (lit as i16 as u32)*4;
		let memval = self.mem.read_u32(ea);

		self.write_reg(r_c as uint, memval);

		if(a != 0b11111) { warn!("\"The Ra field is ignored and should be 11111.\" It is not."); }
	}

	fn mul(&mut self, data: u32) {
		print("mul ");
		self.exec_op(data, |a, b| a*b)
	}

	fn mulc(&mut self, data: u32) {
		print("mulc ");
		self.exec_op_lit(data, |a, b| a*b)
	}

	fn or(&mut self, data: u32) {
		print("or ");
		self.exec_op(data, |a, b| a|b)
	}

	fn orc(&mut self, data: u32) {
		print("orc ");
		self.exec_op_lit(data, |a, b| a|b)
	}

	fn shl(&mut self, data: u32) {
		print("shl ");
		self.exec_op(data, |a, b| a << b)
	}

	fn shlc(&mut self, data: u32) {
		print("shlc ");
		self.exec_op_lit(data, |a, b| a << b)
	}

	fn shr(&mut self, data: u32) {
		print("shr ");
		self.exec_op(data, |a, b| a >> b)
	}

	fn shrc(&mut self, data: u32) {
		print("shrc ");
		self.exec_op_lit(data, |a, b| a >> b)
	}

	fn sra(&mut self, data: u32) {
		print("sra ");
		self.exec_op(data, |a, b| ((a as i32) >> b) as u32)
	}

	fn srac(&mut self, data: u32) {
		print("srac ");
		self.exec_op_lit(data, |a, b| ((a as i32) >> b) as u32)
	}

	fn sub(&mut self, data: u32) {
		print("sub ");
		self.exec_op(data, |a, b| a - b)
	}

	fn subc(&mut self, data: u32) {
		print("subc ");
		self.exec_op_lit(data, |a, b| a - b)
	}

	fn st(&mut self, data: u32) {
		print("st ");
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);
		let c = self.read_reg(r_c as uint);

		let ea = a + (lit as i16 as u32);

		self.mem.write_u32(ea, c)
	}

	fn xor(&mut self, data: u32) {
		print("xor ");
		self.exec_op(data, |a, b| a^b);
	}

	fn xorc(&mut self, data: u32) {
		print("xorc ");
		self.exec_op_lit(data, |a, b| a^b);
	}

	fn xnor(&mut self, data: u32) {
		print("xnor ");
		self.exec_op(data, |a, b| !(a^b));
	}

	fn xnorc(&mut self, data: u32) {
		print("xnorc ");
		self.exec_op_lit(data, |a, b| !(a^b));
	}
}

<|endoftext|>


<commit_before>use core::hashmap::linear::LinearMap;
use core::str::raw::from_c_str;

// trait Result {
//   fn is_error(&self) -> bool;
// }

// trait DocumentResult : Result {
// }

// struct ParseError {
//   error: bool
// }

// impl Result for ParseError {
//   fn is_error(&self) -> bool {
//     true
//   }
// }

// struct Document {
//   map: @mut LinearMap<~str, ~BsonElement>
// }

// impl Document {
//   fn new() -> @Document {
//     @Document {map: @mut LinearMap::new()}
//   }
// }

// impl Result for Document {
//   fn is_error(&self) -> bool {
//     false
//   }
// }

// impl DocumentResult for Document {
// }

// Available Result values
enum Result {
  Document(@mut LinearMap<~str, ~BsonElement>),
  ParseError(bool)
}

// Available Bson Element types
enum BsonElement {
  Int32(i32),
  Int64(i64)
}

struct BsonParser;
struct ParserState {
  index: u32,
  size: u32,
  document: @Result
}

// //
// // Int 32 element
// struct Int32Element {
//   number: i32
// }

// impl BsonElement for Int32Element {
//   fn typeof() -> BsonType {
//     Int32
//   }
// }

// //
// // Int 64 element
// struct Int64Element {
//   number: i64
// }

// impl BsonElement for Int64Element {
//   fn typeof() -> BsonType {
//     Int64
//   }
// }

impl BsonParser {
  fn deserialize(&self, data: &[i8]) -> @Result {
    // Get the initial state of the parsing
    let size = data[0] as u32;
    // Return an error if we the sizes of the message are not the same
    if size != data.len() as u32 {
      // return @ParseError {error: true} as @Result;
      return @ParseError(true);
    }

    // If we have zero elements (special case)
    if(size == 5) {
      return @Document(@mut LinearMap::new());
    }

    // Create a document
    let document = @Document(@mut LinearMap::new());
    // Create a parser state
    let state = @mut ParserState {index: 4, size: size, document: document};

    while(state.index < state.size - 1) {
      // Let's go, Match on the type
      match data[state.index] as u8 {
        0x02 => io::println("string"),
        0x10 => BsonParser::parseInt32(state, data),
        0x12 => BsonParser::parseInt64(state, data),
        _ => io::println("unknown type")
      }
    }

    // return the document
    document
  }

  fn parseInt32(state:&mut ParserState, data: &[i8]) {
    state.index = state.index + 1;

    // Unpack the cstring
    unsafe {
      // Unpack the name of the field
      let name:~str = from_c_str(&data[state.index]);
      // Adjust the index
      state.index += name.len() as u32 + 1;
      // Unpack the i32 value
      let value = ~Int32(data[state.index] as i32);
      // Adjust index
      state.index += 4;
      // Add to the map
      match *state.document {
        Document(map) => map.insert(name, value),
        _ => false
      };
    }
  }

  fn parseInt64(state:&mut ParserState, data: &[i8]) {
    state.index = state.index + 1;

    // Unpack the cstring
    unsafe {
      // Unpack the name of the field
      let name:~str = from_c_str(&data[state.index]);
      // Adjust the index
      state.index += name.len() as u32 + 1;
      // Unpack the i64 value
      let value = ~Int64(data[state.index] as i64);
      // Adjust index
      state.index += 8;
      // Add to the map
      match *state.document {
        Document(map) => map.insert(name, value),
        _ => false
      };
    }
  }
}

#[test]
fn simple_int32_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(map) => process_map(map),
    @ParseError(_) => ()
  }
}

#[test]
fn two_value_document_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x17, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
    match map.find(&~"a") {
      Some(&~Int64(number)) => assert_eq!(number, 2),
      _ => ()
    }

    match map.find(&~"b") {
      Some(&~Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(map) => process_map(map),
    @ParseError(_) => ()
  }
}

// fn process_map(map: @mut LinearMap<~str, ~BsonElement>) {
//   for map.each_key |key| {
//     let value = map.find(key);
//     io::println(fmt!(" %?", value));

//     match map.find(key) {
//       Some(&~Int64(number)) => assert_eq!(2, number),
//       _ => io::println("found nothing"),
//     }
//   }
// }
<commit_msg>Refactored deserialization code<commit_after>use core::hashmap::linear::LinearMap;
use core::str::raw::from_c_str;

// Available Result values
enum Result {
  Document(@BsonElement),
  ParseError(bool)
}

// Available Bson Element types
enum BsonElement {
  Int32(i32),
  Int64(i64),
  Object(@mut LinearMap<~str, @BsonElement>),
}

struct BsonParser;
struct ParserState {
  index: u32,
  document: @BsonElement
}

impl BsonParser {
  fn deserialize(&self, data: &[i8]) -> @Result {
    // Get the initial state of the parsing
    let size = data[0] as u32;
    // Return an error if we the sizes of the message are not the same
    if size != data.len() as u32 {
      // return @ParseError {error: true} as @Result;
      return @ParseError(true);
    }

    // If we have zero elements (special case)
    if(size == 5) {
      return @Document(@Object(@mut LinearMap::new()));
    }

    // // Parse the document
    // let object = @Object(@mut LinearMap::new());
    // // Create a parser state
    // let state = @mut ParserState {index: 4, document: object};

    // Parse the document
    let object = BsonParser::deserialize_loop(data, @mut 0i64);
    // return the document
    @Document(object)
  }

  fn deserialize_loop(data: &[i8], index: &mut i64) -> @BsonElement {
    // io::println("======= deserialize_loop");
    // Create an empty object
    let object: @BsonElement = @Object(@mut LinearMap::new());
    // Decode the document size
    let size = data[*index] as u32;
    // Adjust the location of the index
    *index = *index + 4;

    // // Get the top level object
    // let object = @Object(@mut LinearMap::new());
    // Loop until we are done
    loop {
      // Get bson type
      let bson_type = data[*index];
      // Adjust to name of the field
      *index += 1;
      // Decode the name from the cstring
      let name = BsonParser::extract_string(*index, data);
      // Adjust the index to point to the data
      *index += name.len() as i64 + 1;

      // Access the internal map
      match object {
        @Object(map) => {
          match bson_type as u8 {
            0x02 => io::println("string"),
            0x10 => {
                map.insert(name, BsonParser::parseInt32(index, data));
              },
            0x12 => {
                map.insert(name, BsonParser::parseInt64(index, data));
              },
            0x03 => {
                // Create a new object
                let new_object = BsonParser::deserialize_loop(data, index);
                // Add to the map
                map.insert(name, new_object);
              }
            _ => ()
          }
        }
        _ => ()
      };
      break;
    }

    object
  }

  fn extract_string(index:i64, data: &[i8]) -> ~str {
    unsafe {
      // Unpack the name of the field
      from_c_str(&data[index])
    }
  }

  fn parseInt32(index: &mut i64, data: &[i8]) -> @BsonElement {
    // Unpack the i32 value
    let value = @Int32(data[*index] as i32);
    // Adjust index
    *index += 4;
    // Return the value
    value
  }

  fn parseInt64(index: &mut i64, data: &[i8]) -> @BsonElement {
    // Unpack the i32 value
    let value = @Int64(data[*index] as i64);
    // Adjust index
    *index += 8;
    // Return the value
    value
  }
}

/**
 * Tests
 */
#[test]
fn simple_int32_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x0c, 0x00, 0x00, 0x00, 0x10, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, @BsonElement>) {
    match map.find(&~"a") {
      Some(&@Int32(number)) => {
        assert_eq!(number, 1);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(@Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn simple_int64_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x10, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, @BsonElement>) {
    match map.find(&~"a") {
      Some(&@Int64(number)) => {
        assert_eq!(number, 2);
      },
      _ => fail!()
    }
  }

  match result {
    @Document(@Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn two_value_document_test() {
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x17, 0x00, 0x00, 0x00, 0x12, 0x61, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);

  fn process_map(map: @mut LinearMap<~str, @BsonElement>) {
    match map.find(&~"a") {
      Some(&@Int64(number)) => assert_eq!(number, 2),
      _ => ()
    }

    match map.find(&~"b") {
      Some(&@Int32(number)) => assert_eq!(number, 1),
      _ => ()
    }
  }

  match result {
    @Document(@Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}

#[test]
fn sub_document_test() {
  // {a:{b:1}}
  let parser:BsonParser = BsonParser;
  let result = parser.deserialize(@[0x1b, 0x00, 0x00, 0x00, 0x03, 0x61, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x62, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]);

  // Validate the result
  fn process_map(map: @mut LinearMap<~str, @BsonElement>) {
    match map.find(&~"a") {
      Some(&@Object(object_map)) => {

        // Locate the internal object
        match object_map.find(&~"b") {
          Some(&@Int32(number)) => {
            assert_eq!(number, 1);
          },
          _ => fail!()
        }
      }
      _ => fail!()
    }
  }

  match result {
    @Document(@Object(map)) => process_map(map),
    @Document(_) => (),
    @ParseError(_) => ()
  }
}<|endoftext|>