<commit_before>use std::collections::{BTreeMap, HashMap};

use chrono::prelude::*;
use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};

use crate::state::{GroupStatus, State};
use crate::task::Task;

/// This is the main message enum. \
/// Everything that's communicated in Pueue can be serialized as this enum.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum Message {
    Add(AddMessage),
    Remove(Vec<usize>),
    Switch(SwitchMessage),
    Stash(Vec<usize>),
    Enqueue(EnqueueMessage),

    Start(StartMessage),
    Restart(RestartMessage),
    Pause(PauseMessage),
    Kill(KillMessage),

    Send(SendMessage),
    EditRequest(usize),
    EditResponse(EditResponseMessage),
    Edit(EditMessage),
    Group(GroupMessage),
    GroupResponse(GroupResponseMessage),

    Status,
    StatusResponse(Box<State>),
    Log(LogRequestMessage),
    LogResponse(BTreeMap<usize, TaskLogMessage>),
    Stream(String),
    StreamRequest(StreamRequestMessage),
    /// The boolean decides, whether the children should be get a SIGTERM as well.
    Reset(ResetMessage),
    Clean(CleanMessage),
    DaemonShutdown,

    Success(String),
    Failure(String),

    Parallel(ParallelMessage),
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AddMessage {
    pub command: String,
    pub path: String,
    pub envs: HashMap<String, String>,
    pub start_immediately: bool,
    pub stashed: bool,
    pub group: String,
    pub enqueue_at: Option<DateTime<Local>>,
    pub dependencies: Vec<usize>,
    pub label: Option<String>,
    pub print_task_id: bool,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SwitchMessage {
    pub task_id_1: usize,
    pub task_id_2: usize,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EnqueueMessage {
    pub task_ids: Vec<usize>,
    pub enqueue_at: Option<DateTime<Local>>,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct StartMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub all: bool,
    pub children: bool,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RestartMessage {
    pub tasks: Vec<TasksToRestart>,
    pub start_immediately: bool,
    pub stashed: bool,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct TasksToRestart {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct PauseMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub wait: bool,
    pub all: bool,
    pub children: bool,
}

/// This is a small custom Enum for all currently supported unix signals.
/// Supporting all unix signals would be a mess, since there is a LOT of them.
///
/// This is also needed for usage in clap, since nix's Signal doesn't implement [Display] and
/// [std::str::FromStr].
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize, Display, EnumString)]
pub enum Signal {
    SigTerm,
    SigInt,
    SigKill,
    SigCont,
    SigStop,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct KillMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub all: bool,
    pub children: bool,
    pub signal: Option<Signal>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SendMessage {
    pub task_id: usize,
    pub input: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EditMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EditResponseMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GroupMessage {
    pub add: Option<String>,
    pub remove: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GroupResponseMessage {
    pub groups: BTreeMap<String, GroupStatus>,
    pub settings: BTreeMap<String, usize>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ResetMessage {
    pub children: bool,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CleanMessage {
    #[serde(default = "false_default")]
    pub successful_only: bool,
}
fn false_default() -> bool {
    false
}

/// `err` decides, whether you should stream stderr or stdout.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StreamRequestMessage {
    pub task_id: Option<usize>,
    pub err: bool,
}

/// Request logs for specific tasks.
///
/// `task_ids` specifies the requested tasks. If none are given, all tasks are selected.
/// `send_logs` Determines whether tasks should be sent at all.
/// `lines` Determines whether only a few lines of log should be returned.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LogRequestMessage {
    pub task_ids: Vec<usize>,
    pub send_logs: bool,
    pub lines: Option<usize>,
}

/// Helper struct for sending tasks and their log output to the client.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TaskLogMessage {
    pub task: Task,
    pub stdout: Option<Vec<u8>>,
    pub stderr: Option<Vec<u8>>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ParallelMessage {
    pub parallel_tasks: usize,
    pub group: String,
}

pub fn create_success_message<T: ToString>(text: T) -> Message {
    Message::Success(text.to_string())
}

pub fn create_failure_message<T: ToString>(text: T) -> Message {
    Message::Failure(text.to_string())
}
<commit_msg>Accept lowercase and number in cli for kill signal<commit_after>use std::collections::{BTreeMap, HashMap};

use chrono::prelude::*;
use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};

use crate::state::{GroupStatus, State};
use crate::task::Task;

/// This is the main message enum. \
/// Everything that's communicated in Pueue can be serialized as this enum.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum Message {
    Add(AddMessage),
    Remove(Vec<usize>),
    Switch(SwitchMessage),
    Stash(Vec<usize>),
    Enqueue(EnqueueMessage),

    Start(StartMessage),
    Restart(RestartMessage),
    Pause(PauseMessage),
    Kill(KillMessage),

    Send(SendMessage),
    EditRequest(usize),
    EditResponse(EditResponseMessage),
    Edit(EditMessage),
    Group(GroupMessage),
    GroupResponse(GroupResponseMessage),

    Status,
    StatusResponse(Box<State>),
    Log(LogRequestMessage),
    LogResponse(BTreeMap<usize, TaskLogMessage>),
    Stream(String),
    StreamRequest(StreamRequestMessage),
    /// The boolean decides, whether the children should be get a SIGTERM as well.
    Reset(ResetMessage),
    Clean(CleanMessage),
    DaemonShutdown,

    Success(String),
    Failure(String),

    Parallel(ParallelMessage),
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AddMessage {
    pub command: String,
    pub path: String,
    pub envs: HashMap<String, String>,
    pub start_immediately: bool,
    pub stashed: bool,
    pub group: String,
    pub enqueue_at: Option<DateTime<Local>>,
    pub dependencies: Vec<usize>,
    pub label: Option<String>,
    pub print_task_id: bool,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SwitchMessage {
    pub task_id_1: usize,
    pub task_id_2: usize,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EnqueueMessage {
    pub task_ids: Vec<usize>,
    pub enqueue_at: Option<DateTime<Local>>,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct StartMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub all: bool,
    pub children: bool,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RestartMessage {
    pub tasks: Vec<TasksToRestart>,
    pub start_immediately: bool,
    pub stashed: bool,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct TasksToRestart {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct PauseMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub wait: bool,
    pub all: bool,
    pub children: bool,
}

/// This is a small custom Enum for all currently supported unix signals.
/// Supporting all unix signals would be a mess, since there is a LOT of them.
///
/// This is also needed for usage in clap, since nix's Signal doesn't implement [Display] and
/// [std::str::FromStr].
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize, Display, EnumString)]
pub enum Signal {
    #[strum(serialize = "SigInt", serialize = "sigint", serialize = "2")]
    SigInt,
    #[strum(serialize = "SigKill", serialize = "sigkill", serialize = "9")]
    SigKill,
    #[strum(serialize = "SigTerm", serialize = "sigterm", serialize = "15")]
    SigTerm,
    #[strum(serialize = "SigCont", serialize = "sigcont", serialize = "18")]
    SigCont,
    #[strum(serialize = "SigStop", serialize = "sigstop", serialize = "19")]
    SigStop,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct KillMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub all: bool,
    pub children: bool,
    pub signal: Option<Signal>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SendMessage {
    pub task_id: usize,
    pub input: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EditMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EditResponseMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GroupMessage {
    pub add: Option<String>,
    pub remove: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GroupResponseMessage {
    pub groups: BTreeMap<String, GroupStatus>,
    pub settings: BTreeMap<String, usize>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ResetMessage {
    pub children: bool,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CleanMessage {
    #[serde(default = "false_default")]
    pub successful_only: bool,
}
fn false_default() -> bool {
    false
}

/// `err` decides, whether you should stream stderr or stdout.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StreamRequestMessage {
    pub task_id: Option<usize>,
    pub err: bool,
}

/// Request logs for specific tasks.
///
/// `task_ids` specifies the requested tasks. If none are given, all tasks are selected.
/// `send_logs` Determines whether tasks should be sent at all.
/// `lines` Determines whether only a few lines of log should be returned.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LogRequestMessage {
    pub task_ids: Vec<usize>,
    pub send_logs: bool,
    pub lines: Option<usize>,
}

/// Helper struct for sending tasks and their log output to the client.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TaskLogMessage {
    pub task: Task,
    pub stdout: Option<Vec<u8>>,
    pub stderr: Option<Vec<u8>>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ParallelMessage {
    pub parallel_tasks: usize,
    pub group: String,
}

pub fn create_success_message<T: ToString>(text: T) -> Message {
    Message::Success(text.to_string())
}

pub fn create_failure_message<T: ToString>(text: T) -> Message {
    Message::Failure(text.to_string())
}
<|endoftext|>


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

#![feature(box_syntax)]
use std::any::Any;

fn main()
{
    fn h(x:i32) -> i32 {3*x}
    let mut vfnfer:Vec<Box<Any>> = vec![];
    vfnfer.push(box h);
    println!("{:?}",(vfnfer[0] as Fn)(3));
    //~^ ERROR the precise format of `Fn`-family traits'
    //~| ERROR E0243
    //~| NOTE expected 1 type arguments, found 0
    //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`)
    //~| NOTE in this expansion of println!
    //~| NOTE in this expansion of println!
    //~| NOTE in this expansion of println!
    //~| NOTE in this expansion of println!
}
<commit_msg>Auto merge of #35492 - jonathandturner:fix_nightlies, r=arielb1<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(box_syntax)]
use std::any::Any;

fn main()
{
    fn h(x:i32) -> i32 {3*x}
    let mut vfnfer:Vec<Box<Any>> = vec![];
    vfnfer.push(box h);
    println!("{:?}",(vfnfer[0] as Fn)(3));
    //~^ ERROR the precise format of `Fn`-family traits'
    //~| ERROR E0243
    //~| ERROR the value of the associated type `Output` (from the trait `std::ops::FnOnce`)
}
<|endoftext|>


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

// Tests that compiling for a target which is not installed will result in a helpful
// error message.

// compile-flags: --target=s390x-unknown-linux-gnu
// ignore s390x

// error-pattern:target may not be installed
fn main() { }
<commit_msg>Use ARM instead of SystemZ for testing not installed targets<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Tests that compiling for a target which is not installed will result in a helpful
// error message.

// compile-flags: --target=thumbv6m-none-eabi
// ignore-arm

// error-pattern:target may not be installed
fn main() { }
<|endoftext|>


<commit_before>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage, DebugInfoBuilder,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let mut dibuilder = module.create_debug_info_builder(true);

    let compile_unit = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let ditype = dibuilder.create_basic_type("type_name", 0_u64, 0x00, DIFlags::Public);
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::Public,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::Public,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let builder = context.create_builder();
    let mut dibuilder = module.create_debug_info_builder(true);

    let compile_unit = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder.create_basic_type("i32", 32, 0x07, DIFlags::Public);
    let i64ty = dibuilder.create_basic_type("i64", 64, 0x07, DIFlags::Public);
    let f32ty = dibuilder.create_basic_type("f32", 32, 0x04, DIFlags::Public);
    let f64ty = dibuilder.create_basic_type("f64", 64, 0x04, DIFlags::Public);

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|ty| dibuilder.create_placeholder_derived_type(&context))
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::Public,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::Public,
            ty.as_type(),
        );
        dibuilder.replace_placeholder_derived_type(*placeholder, member);
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}
<commit_msg>Check that we correctly require exactly one compile unit.<commit_after>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage, DebugInfoBuilder,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let mut dibuilder = module.create_debug_info_builder(true);

    let compile_unit = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let ditype = dibuilder.create_basic_type("type_name", 0_u64, 0x00, DIFlags::Public);
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::Public,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::Public,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let builder = context.create_builder();
    let mut dibuilder = module.create_debug_info_builder(true);

    let compile_unit = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder.create_basic_type("i32", 32, 0x07, DIFlags::Public);
    let i64ty = dibuilder.create_basic_type("i64", 64, 0x07, DIFlags::Public);
    let f32ty = dibuilder.create_basic_type("f32", 32, 0x04, DIFlags::Public);
    let f64ty = dibuilder.create_basic_type("f64", 64, 0x04, DIFlags::Public);

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|ty| dibuilder.create_placeholder_derived_type(&context))
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::Public,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::Public,
            ty.as_type(),
        );
        dibuilder.replace_placeholder_derived_type(*placeholder, member);
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
#[should_panic]
fn test_zero_compile_units() {
    let context = Context::create();
    let module = context.create_module("");

    let _dibuilder = module.create_debug_info_builder(true);
}

#[test]
fn test_one_compile_unit() {
    let context = Context::create();
    let module = context.create_module("");

    let mut dibuilder = module.create_debug_info_builder(true);

    let _compile_unit = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // We don't call finalize here because we also don't module.verify().
    // finalize() is called from Drop.
}

#[test]
#[should_panic]
fn test_two_compile_units() {
    let context = Context::create();
    let module = context.create_module("");

    let mut dibuilder = module.create_debug_info_builder(true);

    let _compile_unit1 = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let _compile_unit2 = dibuilder.create_compile_unit(
        DWARFSourceLanguage::C,
        dibuilder.create_file("second_source_file", "."),
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );
}
<|endoftext|>


<commit_before>use crate::compiler::Code;
use crate::driver::cmd::AsmSyntax;
use crate::ty::TypeList;
use crate::vm::{Fct, FctSrc, VM};

pub fn supported() -> bool {
    false
}

pub fn disassemble<'ast>(
    _vm: &VM<'ast>,
    _fct: &Fct<'ast>,
    _cls_type_params: &TypeList,
    _fct_type_params: &TypeList,
    _code: &Code,
    _fct_src: Option<&FctSrc>,
    _asm_syntax: AsmSyntax,
) {
    unreachable!();
}
<commit_msg>fix build failure in disassembler/none.rs<commit_after>use crate::compiler::Code;
use crate::driver::cmd::AsmSyntax;
use crate::ty::TypeList;
use crate::vm::{Fct, FctSrc, VM};

pub fn supported() -> bool {
    false
}

pub fn disassemble<'ast>(
    _vm: &VM<'ast>,
    _fct: &Fct<'ast>,
    _type_params: &TypeList,
    _code: &Code,
    _fct_src: Option<&FctSrc>,
    _asm_syntax: AsmSyntax,
) {
    unreachable!();
}
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
    let name = &ast.ident;
    let gen = &ast.generics;
    let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
    let vis = &ast.vis;
    let type_properties = ast.get_type_properties()?;
    let strum_module_path = type_properties.crate_module_path();

    if gen.lifetimes().count() > 0 {
        return Err(syn::Error::new(
            Span::call_site(),
            "This macro doesn't support enums with lifetimes. \
             The resulting enums would be unbounded.",
        ));
    }

    let phantom_data = if gen.type_params().count() > 0 {
        let g = gen.type_params().map(|param| &param.ident);
        quote! { < ( #(#g),* ) > }
    } else {
        quote! { < () > }
    };

    let variants = match &ast.data {
        Data::Enum(v) => &v.variants,
        _ => return Err(non_enum_error()),
    };

    let mut arms = Vec::new();
    let mut idx = 0usize;
    for variant in variants {
        if variant.get_variant_properties()?.disabled.is_some() {
            continue;
        }

        let ident = &variant.ident;
        let params = match &variant.fields {
            Fields::Unit => quote! {},
            Fields::Unnamed(fields) => {
                let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
                    .take(fields.unnamed.len());
                quote! { (#(#defaults),*) }
            }
            Fields::Named(fields) => {
                let fields = fields
                    .named
                    .iter()
                    .map(|field| field.ident.as_ref().unwrap());
                quote! { {#(#fields: ::core::default::Default::default()),*} }
            }
        };

        arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
        idx += 1;
    }

    let variant_count = arms.len();
    arms.push(quote! { _ => ::core::option::Option::None });
    let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();

    Ok(quote! {
        #[doc = "An iterator over the variants of [Self]"]
        #vis struct #iter_name #ty_generics {
            idx: usize,
            back_idx: usize,
            marker: ::core::marker::PhantomData #phantom_data,
        }

        impl #impl_generics #iter_name #ty_generics #where_clause {
            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
                match idx {
                    #(#arms),*
                }
            }
        }

        impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
            type Iterator = #iter_name #ty_generics;
            fn iter() -> #iter_name #ty_generics {
                #iter_name {
                    idx: 0,
                    back_idx: 0,
                    marker: ::core::marker::PhantomData,
                }
            }
        }

        impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
            type Item = #name #ty_generics;

            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
                self.nth(0)
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                (t, Some(t))
            }

            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
                let idx = self.idx + n + 1;
                if idx + self.back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.idx = #variant_count;
                    None
                } else {
                    self.idx = idx;
                    self.get(idx - 1)
                }
            }
        }

        impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
            fn len(&self) -> usize {
                self.size_hint().0
            }
        }

        impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
                let back_idx = self.back_idx + 1;

                if self.idx + back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze back_idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.back_idx = #variant_count;
                    None
                } else {
                    self.back_idx = back_idx;
                    self.get(#variant_count - self.back_idx)
                }
            }
        }

        impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
            fn clone(&self) -> #iter_name #ty_generics {
                #iter_name {
                    idx: self.idx,
                    back_idx: self.back_idx,
                    marker: self.marker.clone(),
                }
            }
        }
    })
}
<commit_msg>Use full path for `None` in `EnumIter` (#214)<commit_after>use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
    let name = &ast.ident;
    let gen = &ast.generics;
    let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
    let vis = &ast.vis;
    let type_properties = ast.get_type_properties()?;
    let strum_module_path = type_properties.crate_module_path();

    if gen.lifetimes().count() > 0 {
        return Err(syn::Error::new(
            Span::call_site(),
            "This macro doesn't support enums with lifetimes. \
             The resulting enums would be unbounded.",
        ));
    }

    let phantom_data = if gen.type_params().count() > 0 {
        let g = gen.type_params().map(|param| &param.ident);
        quote! { < ( #(#g),* ) > }
    } else {
        quote! { < () > }
    };

    let variants = match &ast.data {
        Data::Enum(v) => &v.variants,
        _ => return Err(non_enum_error()),
    };

    let mut arms = Vec::new();
    let mut idx = 0usize;
    for variant in variants {
        if variant.get_variant_properties()?.disabled.is_some() {
            continue;
        }

        let ident = &variant.ident;
        let params = match &variant.fields {
            Fields::Unit => quote! {},
            Fields::Unnamed(fields) => {
                let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
                    .take(fields.unnamed.len());
                quote! { (#(#defaults),*) }
            }
            Fields::Named(fields) => {
                let fields = fields
                    .named
                    .iter()
                    .map(|field| field.ident.as_ref().unwrap());
                quote! { {#(#fields: ::core::default::Default::default()),*} }
            }
        };

        arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
        idx += 1;
    }

    let variant_count = arms.len();
    arms.push(quote! { _ => ::core::option::Option::None });
    let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();

    Ok(quote! {
        #[doc = "An iterator over the variants of [Self]"]
        #vis struct #iter_name #ty_generics {
            idx: usize,
            back_idx: usize,
            marker: ::core::marker::PhantomData #phantom_data,
        }

        impl #impl_generics #iter_name #ty_generics #where_clause {
            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
                match idx {
                    #(#arms),*
                }
            }
        }

        impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
            type Iterator = #iter_name #ty_generics;
            fn iter() -> #iter_name #ty_generics {
                #iter_name {
                    idx: 0,
                    back_idx: 0,
                    marker: ::core::marker::PhantomData,
                }
            }
        }

        impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
            type Item = #name #ty_generics;

            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
                self.nth(0)
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                (t, Some(t))
            }

            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
                let idx = self.idx + n + 1;
                if idx + self.back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.idx = idx;
                    self.get(idx - 1)
                }
            }
        }

        impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
            fn len(&self) -> usize {
                self.size_hint().0
            }
        }

        impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
                let back_idx = self.back_idx + 1;

                if self.idx + back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze back_idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.back_idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.back_idx = back_idx;
                    self.get(#variant_count - self.back_idx)
                }
            }
        }

        impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
            fn clone(&self) -> #iter_name #ty_generics {
                #iter_name {
                    idx: self.idx,
                    back_idx: self.back_idx,
                    marker: self.marker.clone(),
                }
            }
        }
    })
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::{Mutex, Arc};

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(50);

        println!("{} is done eating.", self.name);
    }
}

struct Table {
    forks: Vec<Mutex<()>>,
}

fn main() {
    let table = Arc::new(Table { forks: vec![
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
    ]});

    let philosophers = vec![
        Philosopher::new("[01] Judith Butler", 0, 1),
        Philosopher::new("[02] Gilles Deleuze", 1, 2),
        Philosopher::new("[03] Karl Marx", 2, 3),
        Philosopher::new("[04] Emma Goldman", 3, 4),
        Philosopher::new("[05] Michel Foucault", 0, 4),
    ];

    let handles: Vec<_> = philosophers.into_iter().map(|p| {
        let table = table.clone();

        thread::spawn(move || {
            p.eat(&table);
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}

<commit_msg>修复代码,有更新<commit_after>use std::thread;
use std::sync::{Mutex, Arc};
use std::time::Duration;

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        let duration = Duration::new(0, 5000);

        thread::sleep(duration);

        println!("{} is done eating.", self.name);
    }
}

struct Table {
    forks: Vec<Mutex<()>>,
}

fn main() {
    let table = Arc::new(Table { forks: vec![
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
    ]});

    let philosophers = vec![
        Philosopher::new("[01] Judith Butler", 0, 1),
        Philosopher::new("[02] Gilles Deleuze", 1, 2),
        Philosopher::new("[03] Karl Marx", 2, 3),
        Philosopher::new("[04] Emma Goldman", 3, 4),
        Philosopher::new("[05] Michel Foucault", 0, 4),
    ];

    let handles: Vec<_> = philosophers.into_iter().map(|p| {
        let table = table.clone();

        thread::spawn(move || {
            p.eat(&table);
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}

<|endoftext|>


<commit_before>// src/dao/account_dao.rs

/// Account DAO
/// Handle all database interaction for Accounts

// Import
extern crate mongodb;

// Import Modules
// Common Utilities
use ::bson::{Bson, Document};
use ::bson::oid::ObjectId;
use ::chrono::{Local};
use ::mongodb::coll::options::FindOptions;
use ::mongodb::db::ThreadedDatabase;
use ::common::mm_result::{MMResult, MMError, MMErrorKind};
// Models
use ::models::account_model::{AccountModel};

// Constants
static MONEY_MAP_COLLECTION: &'static str = "money_maps";

/// Account DAO
pub struct AccountDAO{
    db: mongodb::db::Database
}

// Account DAO Methods
impl AccountDAO{
    /// Create AccountDAO
    ///
    /// # Arguments
    /// db - mongodb::db::Database Cloned database connection
    ///
    /// # Returns
    /// `AccountDAO`
    pub fn new(db: mongodb::db::Database) -> AccountDAO{
        AccountDAO{
            db: db
        }
    }

    /// Find All Money Map accounts for filter
    ///
    /// # Arguments
    /// self
    /// user_id - ObjectId User ID
    /// mm_id - ObjectId Money Map ID
    ///
    /// # Returns
    /// `Option<Vec<AccountModel>>`
    pub fn find(self, user_id: ObjectId, mm_id: ObjectId) -> Option<Vec<AccountModel>>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);
        let mut accounts = Vec::new();

        let pipeline = vec![
            doc!{
                // Filter Money Map
                "$match" => {
                    "_id" => mm_id,
                    "users.user_id" => user_id,
                    "deleted" => {
                        "$ne" => true
                    }
                }
            },
            doc!{
                "$unwind" => "$accounts"
            },
            doc!{
                // Exclude deleted accounts
                "$match" => {
                    "accounts.deleted" => {
                        "$ne" => true
                    }
                }
            },
            doc!{
                "$project" => {
                    "_id" => "$accounts._id",
                    "name" => "$accounts.name",
                    "account_type" => "$accounts.account_type",
                    "created" => "$accounts.created"
                }
            }
        ];

        match coll.aggregate(pipeline, None){
            Ok(cursor) => {
                for result in cursor {
                    if let Ok(acc_doc) = result {
                        accounts.push(document_to_model(&acc_doc));
                    }
                }
            },
            Err(e) => {
                error!("Find All accounts failed: {}", e);
                return None;
            }
        }
        Some(accounts)
    }// end find

    /// Find One Account
    ///
    /// # Arguments
    /// self
    /// filter - Option<Document> The find filter
    ///
    /// # Returns
    /// `Option<AccountModel>`
    pub fn find_one(&self, filter: Option<Document>) -> Option<AccountModel>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let mut find_options = FindOptions::new();
        find_options.projection = Some(doc!{
            "_id" => 0,
            "accounts.$" => 1
        });

        match coll.find_one(filter, Some(find_options)){
            Ok(result) => {
                match result{
                    Some(document) => {
                        if let Some(raw_accounts) = document.get("accounts"){
                            if let &Bson::Array(ref raw_accounts_arr) = raw_accounts{
                                if raw_accounts_arr.len() == 1 {
                                    if let Bson::Document(ref acc_doc) = raw_accounts_arr[0]{
                                        return Some(document_to_model(acc_doc));
                                    }
                                }
                            }
                        }
                    },
                    None => {
                        //Could not find money map for user
                        return None
                    }
                }
            },
            Err(e) => {
                error!("Find All accounts failed: {}", e);
                return None;
            }
        }
        None
    }// end find_one

    /// Create Account
    /// Save account in specified money map
    ///
    /// # Arguments
    /// self
    /// mm_id - &str - Money Map ID
    /// account - &AccountModel The account
    ///
    /// # Returns
    /// `MMResult<AccountModel>`
    pub fn create(self, mm_id: ObjectId, account: &AccountModel) -> MMResult<AccountModel>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let filter = doc! {
            "_id" => ( mm_id )
        };

        // Build `$push` document to update money map and add account
        let id = ObjectId::new().unwrap();
        let timestamp = Local::now().timestamp();
        let update_doc = doc! {
            "$push" => {
                "accounts" => {
                    "_id" => (Bson::ObjectId(id.clone())),
                    "name" => (match account.get_name(){Some(val) => val, None => "".to_string()}),
                    "account_type" => (match account.get_account_type(){Some(val) => val, None => "".to_string()}),
                    "created" => (Bson::TimeStamp(timestamp.clone()))
                }
            }
        };

        // Update the money map and add account
        match coll.update_one(filter.clone(), update_doc.clone(), None){
            Ok(result) => {
                if result.acknowledged && result.modified_count > 0 {
                    let mut new_account = account.clone();
                    new_account.set_id(Some(id));
                    new_account.set_created(Some(timestamp));
                    Ok(new_account)
                }else{
                    Err(MMError::new("Unable to add account to money map.", MMErrorKind::DAO))
                }
            },
            Err(e) => {
                error!("{}", e);
                Err(MMError::new("Failed to add account to money map.", MMErrorKind::DAO))
            }
        }
    }// end create

    /// Update an existing acount
    ///
    /// # Arguments
    /// self
    /// mm_id ObjectId The Money Map ID
    /// &account - AccountModel
    ///
    /// # Returns
    /// `MMResult<AccountModel>` The updated money map if successful, None otherwise
    pub fn update(&self, mm_id: ObjectId, account: &AccountModel) -> MMResult<AccountModel>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let filter = doc! {
            //Money Map Information
            "_id" => mm_id,
            "deleted" => {
                "$ne" => true
            },
            //Account Information
            "accounts" => {
                "$elemMatch" => {
                    "_id" => ( account.get_id().unwrap() ),
                    "deleted" => {
                        "$ne" => true
                    }
                }
            }
        };

        // Build `$set` document to update document
        let mut set_doc = doc!{};
        let mut update = false;
        if let Some(name) = account.get_name(){
            update = true;
            set_doc.insert_bson("accounts.$.name".to_string(), Bson::String(name));
        }
        if let Some(account_type) = account.get_account_type(){
            update = true;
            set_doc.insert_bson("accounts.$.account_type".to_string(), Bson::String(account_type));
        }
        let update_doc = if update {
            doc! {"$set" => set_doc}
        }else{
            // No updates to account, return existing account details if found
            return match self.find_one(Some(filter)){
                Some(result) => Ok(result),
                None => Err(MMError::new("Unable to find account", MMErrorKind::DAO))
            };
        };

        // Update the money map
        match coll.update_one(filter.clone(), update_doc.clone(), None){
            Ok(result) => {
                match result.write_exception{
                    None => {
                        if result.matched_count > 0{
                            // Account found and updated
                            Ok(self.find_one(Some(filter)).unwrap())
                        }else{
                            Err(MMError::new("Unable to find account", MMErrorKind::DAO))
                        }
                    },
                    Some(_) => {
                        Err(MMError::new("Unable to save account", MMErrorKind::DAO))
                    }
                }

            },
            Err(e) => {
                error!("{}", e);
                Err(MMError::new("Failed to update money map.", MMErrorKind::DAO))
            }
        }
    }// end update

    /// Delete an Account
    /// Only allow deleting an account owned by the current user
    ///
    /// # Arguments
    /// self
    /// user_id - ObjectId User ID
    /// mm_id - ObjectId Money Map ID
    /// acc_id - ObjectId Account ID
    ///
    /// # Returns
    /// `MMResult<UpdateResult>`
    pub fn delete(self, user_id: ObjectId, mm_id: ObjectId, acc_id: ObjectId) -> MMResult<mongodb::coll::results::UpdateResult>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let filter = doc! {
            //Money Map Information
            "_id" => mm_id,
            "deleted" => {
                "$ne" => true
            },
            "users" => {
                "$elemMatch" => {
                    "user_id" => user_id
                }
            },
            "accounts" => {
                "$elemMatch" => {
                    "deleted" => {
                        "$ne" => true
                    }
                }
            },
            //Account Information
            "accounts._id" => acc_id
        };

        let update_doc = doc!{
            "$set" => {
                "accounts.$.deleted" => true
            }
        };

        // Soft delete money map
        match coll.update_one(filter.clone(), update_doc.clone(), None){
            Ok(result) => Ok(result),
            Err(e) => {
                error!("{}", e);
                Err(MMError::new("Failed to delete account.", MMErrorKind::DAO))
            }
        }
    }// end delete
}

/// Create AccountModel from Document
///
/// # Arguments
/// self
/// doc - Document
///
/// # Returns
/// `AccountModel`
pub fn document_to_model(doc: &Document) -> AccountModel{
    AccountModel{
        id: match doc.get("_id"){
            Some(obj_id) => match obj_id{ &Bson::ObjectId(ref id) => Some(id.clone()), _ => None},
            _ => None
        },
        name: match doc.get("name"){
            Some(&Bson::String(ref name)) => Some(name.clone()),
            _ => None
        },
        account_type: match doc.get("account_type"){
            Some(&Bson::String(ref account_type)) => Some(account_type.clone()),
            _ => None
        },
        created: match doc.get("created"){
            Some(&Bson::TimeStamp(ref timestamp)) => Some(timestamp.clone()),
            _ => None
        }
    }
}
<commit_msg>Generate initial statement upon account creation<commit_after>// src/dao/account_dao.rs

/// Account DAO
/// Handle all database interaction for Accounts

// Import
extern crate mongodb;

// Import Modules
// External
use ::bson::{Bson, Document};
use ::bson::oid::ObjectId;
use ::chrono::{Local};
use ::chrono::offset::utc::UTC;
use ::mongodb::coll::options::FindOptions;
use ::mongodb::db::ThreadedDatabase;
// Common Utilities
use ::common::mm_result::{MMResult, MMError, MMErrorKind};
// Models
use ::models::account_model::{AccountModel};

// Constants
static MONEY_MAP_COLLECTION: &'static str = "money_maps";

/// Account DAO
pub struct AccountDAO{
    db: mongodb::db::Database
}

// Account DAO Methods
impl AccountDAO{
    /// Create AccountDAO
    ///
    /// # Arguments
    /// db - mongodb::db::Database Cloned database connection
    ///
    /// # Returns
    /// `AccountDAO`
    pub fn new(db: mongodb::db::Database) -> AccountDAO{
        AccountDAO{
            db: db
        }
    }

    /// Find All Money Map accounts for filter
    ///
    /// # Arguments
    /// self
    /// user_id - ObjectId User ID
    /// mm_id - ObjectId Money Map ID
    ///
    /// # Returns
    /// `Option<Vec<AccountModel>>`
    pub fn find(self, user_id: ObjectId, mm_id: ObjectId) -> Option<Vec<AccountModel>>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);
        let mut accounts = Vec::new();

        let pipeline = vec![
            doc!{
                // Filter Money Map
                "$match" => {
                    "_id" => mm_id,
                    "users.user_id" => user_id,
                    "deleted" => {
                        "$ne" => true
                    }
                }
            },
            doc!{
                "$unwind" => "$accounts"
            },
            doc!{
                // Exclude deleted accounts
                "$match" => {
                    "accounts.deleted" => {
                        "$ne" => true
                    }
                }
            },
            doc!{
                "$project" => {
                    "_id" => "$accounts._id",
                    "name" => "$accounts.name",
                    "account_type" => "$accounts.account_type",
                    "created" => "$accounts.created"
                }
            }
        ];

        match coll.aggregate(pipeline, None){
            Ok(cursor) => {
                for result in cursor {
                    if let Ok(acc_doc) = result {
                        accounts.push(document_to_model(&acc_doc));
                    }
                }
            },
            Err(e) => {
                error!("Find All accounts failed: {}", e);
                return None;
            }
        }
        Some(accounts)
    }// end find

    /// Find One Account
    ///
    /// # Arguments
    /// self
    /// filter - Option<Document> The find filter
    ///
    /// # Returns
    /// `Option<AccountModel>`
    pub fn find_one(&self, filter: Option<Document>) -> Option<AccountModel>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let mut find_options = FindOptions::new();
        find_options.projection = Some(doc!{
            "_id" => 0,
            "accounts.$" => 1
        });

        match coll.find_one(filter, Some(find_options)){
            Ok(result) => {
                match result{
                    Some(document) => {
                        if let Some(raw_accounts) = document.get("accounts"){
                            if let &Bson::Array(ref raw_accounts_arr) = raw_accounts{
                                if raw_accounts_arr.len() == 1 {
                                    if let Bson::Document(ref acc_doc) = raw_accounts_arr[0]{
                                        return Some(document_to_model(acc_doc));
                                    }
                                }
                            }
                        }
                    },
                    None => {
                        //Could not find money map for user
                        return None
                    }
                }
            },
            Err(e) => {
                error!("Find All accounts failed: {}", e);
                return None;
            }
        }
        None
    }// end find_one

    /// Create Account
    /// Save account in specified money map
    ///
    /// # Arguments
    /// self
    /// mm_id - &str - Money Map ID
    /// account - &AccountModel The account
    ///
    /// # Returns
    /// `MMResult<AccountModel>`
    pub fn create(self, mm_id: ObjectId, account: &AccountModel) -> MMResult<AccountModel>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let filter = doc! {
            "_id" => ( mm_id )
        };

        // Build `$push` document to update money map and add account
        let id = ObjectId::new().unwrap();
        let timestamp = Local::now().timestamp();
        let initial_statement = doc!{
            "statement_date" => (Bson::UtcDatetime(UTC::now())),
            "ending_balance" => 0.0
        };
        let update_doc = doc! {
            "$push" => {
                "accounts" => {
                    "_id" => (Bson::ObjectId(id.clone())),
                    "name" => (match account.get_name(){Some(val) => val, None => "".to_string()}),
                    "account_type" => (match account.get_account_type(){Some(val) => val, None => "".to_string()}),
                    "created" => (Bson::TimeStamp(timestamp.clone())),
                    "statements" => (Bson::Array(vec![ Bson::Document(initial_statement) ]))
                }
            }
        };

        // Update the money map and add account
        match coll.update_one(filter.clone(), update_doc.clone(), None){
            Ok(result) => {
                if result.acknowledged && result.modified_count > 0 {
                    let mut new_account = account.clone();
                    new_account.set_id(Some(id));
                    new_account.set_created(Some(timestamp));
                    Ok(new_account)
                }else{
                    Err(MMError::new("Unable to add account to money map.", MMErrorKind::DAO))
                }
            },
            Err(e) => {
                error!("{}", e);
                Err(MMError::new("Failed to add account to money map.", MMErrorKind::DAO))
            }
        }
    }// end create

    /// Update an existing acount
    ///
    /// # Arguments
    /// self
    /// mm_id ObjectId The Money Map ID
    /// &account - AccountModel
    ///
    /// # Returns
    /// `MMResult<AccountModel>` The updated money map if successful, None otherwise
    pub fn update(&self, mm_id: ObjectId, account: &AccountModel) -> MMResult<AccountModel>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let filter = doc! {
            //Money Map Information
            "_id" => mm_id,
            "deleted" => {
                "$ne" => true
            },
            //Account Information
            "accounts" => {
                "$elemMatch" => {
                    "_id" => ( account.get_id().unwrap() ),
                    "deleted" => {
                        "$ne" => true
                    }
                }
            }
        };

        // Build `$set` document to update document
        let mut set_doc = doc!{};
        let mut update = false;
        if let Some(name) = account.get_name(){
            update = true;
            set_doc.insert_bson("accounts.$.name".to_string(), Bson::String(name));
        }
        if let Some(account_type) = account.get_account_type(){
            update = true;
            set_doc.insert_bson("accounts.$.account_type".to_string(), Bson::String(account_type));
        }
        let update_doc = if update {
            doc! {"$set" => set_doc}
        }else{
            // No updates to account, return existing account details if found
            return match self.find_one(Some(filter)){
                Some(result) => Ok(result),
                None => Err(MMError::new("Unable to find account", MMErrorKind::DAO))
            };
        };

        // Update the money map
        match coll.update_one(filter.clone(), update_doc.clone(), None){
            Ok(result) => {
                match result.write_exception{
                    None => {
                        if result.matched_count > 0{
                            // Account found and updated
                            Ok(self.find_one(Some(filter)).unwrap())
                        }else{
                            Err(MMError::new("Unable to find account", MMErrorKind::DAO))
                        }
                    },
                    Some(_) => {
                        Err(MMError::new("Unable to save account", MMErrorKind::DAO))
                    }
                }

            },
            Err(e) => {
                error!("{}", e);
                Err(MMError::new("Failed to update money map.", MMErrorKind::DAO))
            }
        }
    }// end update

    /// Delete an Account
    /// Only allow deleting an account owned by the current user
    ///
    /// # Arguments
    /// self
    /// user_id - ObjectId User ID
    /// mm_id - ObjectId Money Map ID
    /// acc_id - ObjectId Account ID
    ///
    /// # Returns
    /// `MMResult<UpdateResult>`
    pub fn delete(self, user_id: ObjectId, mm_id: ObjectId, acc_id: ObjectId) -> MMResult<mongodb::coll::results::UpdateResult>{
        let coll = self.db.collection(MONEY_MAP_COLLECTION);

        let filter = doc! {
            //Money Map Information
            "_id" => mm_id,
            "deleted" => {
                "$ne" => true
            },
            "users" => {
                "$elemMatch" => {
                    "user_id" => user_id
                }
            },
            "accounts" => {
                "$elemMatch" => {
                    "deleted" => {
                        "$ne" => true
                    }
                }
            },
            //Account Information
            "accounts._id" => acc_id
        };

        let update_doc = doc!{
            "$set" => {
                "accounts.$.deleted" => true
            }
        };

        // Soft delete money map
        match coll.update_one(filter.clone(), update_doc.clone(), None){
            Ok(result) => Ok(result),
            Err(e) => {
                error!("{}", e);
                Err(MMError::new("Failed to delete account.", MMErrorKind::DAO))
            }
        }
    }// end delete
}

/// Create AccountModel from Document
///
/// # Arguments
/// self
/// doc - Document
///
/// # Returns
/// `AccountModel`
pub fn document_to_model(doc: &Document) -> AccountModel{
    AccountModel{
        id: match doc.get("_id"){
            Some(obj_id) => match obj_id{ &Bson::ObjectId(ref id) => Some(id.clone()), _ => None},
            _ => None
        },
        name: match doc.get("name"){
            Some(&Bson::String(ref name)) => Some(name.clone()),
            _ => None
        },
        account_type: match doc.get("account_type"){
            Some(&Bson::String(ref account_type)) => Some(account_type.clone()),
            _ => None
        },
        created: match doc.get("created"){
            Some(&Bson::TimeStamp(ref timestamp)) => Some(timestamp.clone()),
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>// This example shows how to implement a simple trading strategy.
// We are looking for the pair with the highest rise in price over the last 24 hours and we
// add a buy order to buy it.

// Please do NOT run this example with your real account unless you know what you're doing.

extern crate coinnect;

use std::path::PathBuf;

use coinnect::kraken::KrakenApi;

fn main() {
    // We create a KrakenApi by loading a json file containing API configuration
    // (see documentation for more info)
    let path = PathBuf::from("keys_real.json");
    let mut my_api = KrakenApi::new_from_file("account_kraken", path);

    // First, get the list of all pair we can trade with EUR€ as quote
    let pairs_request = my_api.get_tradable_asset_pairs("", "").unwrap();
    let list_all_pairs = pairs_request.get("result").unwrap().as_object().unwrap();

    let mut list_pairs_eur = Vec::new();

    for pair in list_all_pairs {
        // The map structure is explained in documentation
        let quote = pair.1.as_object().unwrap().get("quote").unwrap().as_str().unwrap();
        if quote == "ZEUR" {
            let name = pair.0;
            list_pairs_eur.push(name);
        }
    }

    println!("List {:?}", list_pairs_eur);

    // Now that we have the pairs, we choose the one with the highest price variation.
    // We query the ticker to get the opening and closing price over the last 24 hours for each
    // pairs in list_pairs_eur. KrakenApi has a blocking timer which prevents from ban if you
    // make rapid succession of requests (inside a for loop for example). Here, the ticker function
    // can take a list of pairs as parameter, so 1 request should suffice.

    // Convert Vec into comma separated values String
    let eur_pairs = format!("{:?}", list_pairs_eur);
    let eur_pairs = eur_pairs.replace("\"", "").replace("[", "").replace("]", "").replace(" ", "");

    // Get ticker
    let ticker_request = my_api.get_ticker_information(&eur_pairs).unwrap();
    let list_ticker = ticker_request.get("result").unwrap().as_object().unwrap();

    let mut pair_to_buy = "";
    let mut pair_price_var = 0.0;
    let mut current_price = 0.0;

    for pair in list_ticker {
        let name = pair.0;

        // WARNING: Kraken uses quotes to encapsulate floating value
        let pair_info = pair.1.as_object().unwrap();
        let open_price = pair_info.get("o").unwrap().as_str().unwrap().parse::<f64>().unwrap();
        let close_price_array = pair_info.get("c").unwrap().as_array().unwrap();
        let close_price = close_price_array[0].as_str().unwrap().parse::<f64>().unwrap();

        let price_var = (close_price / open_price - 1.0) * 100.0;

        if price_var > pair_price_var {
            pair_price_var = price_var;
            pair_to_buy = name;
            current_price = close_price;
        }
    }

    println!("{} has the highest price variation ({:.2}%).",
             pair_to_buy,
             pair_price_var);

    // Add a buy limit order for an amount of 100€ for a price of: current_price - 2%
    let buying_price = current_price - (current_price * 2.0 / 100.0);
    let volume = 100.0 / buying_price;

    // Specify optional parameters with an empty str ("")
    // See documentation for more informations
    let _ = my_api.add_standard_order(pair_to_buy, // name of the pair
                                      "buy", // type : buy/sell
                                      "limit", // order type : market/limit/...
                                      &buying_price.to_string(), // price 1
                                      "", // price 2
                                      &volume.to_string(), // volume
                                      "", // leverage
                                      "", // oflags (see doc)
                                      "", // starttm
                                      "", // expiretm
                                      "", // userref
                                      ""); // validate
    // In a real case example, you should check if any error occurs.
}
<commit_msg>Update Kraken example to show how to use errors.<commit_after>// This example shows how to implement a simple trading strategy.
// We are looking for the pair with the highest rise in price over the last 24 hours and we
// add a buy order to buy it.

// Please do NOT run this example with your real account unless you know what you're doing.

extern crate coinnect;

use std::path::PathBuf;

use coinnect::kraken::KrakenApi;
use std::error::Error;

fn main() {
    // We create a KrakenApi by loading a json file containing API configuration
    // (see documentation for more info)
    let path = PathBuf::from("keys_real.json");
    let mut my_api = KrakenApi::new_from_file("account_kraken", path);

    // First, get the list of all pair we can trade with EUR€ as quote
    // You could use a simple unwrap() or use match to recover from an error for example
    let pairs_request = match my_api.get_tradable_asset_pairs("", "") {
        Ok(pairs_request) => pairs_request,
        Err(err) => panic!("Error : {:?}, description : {}", err, err.description())
    };
    let list_all_pairs = pairs_request.get("result").unwrap().as_object().unwrap();

    let mut list_pairs_eur = Vec::new();

    for pair in list_all_pairs {
        // The map structure is explained in documentation
        let quote = pair.1.as_object().unwrap().get("quote").unwrap().as_str().unwrap();
        if quote == "ZEUR" {
            let name = pair.0;
            list_pairs_eur.push(name);
        }
    }

    println!("List {:?}", list_pairs_eur);

    // Now that we have the pairs, we choose the one with the highest price variation.
    // We query the ticker to get the opening and closing price over the last 24 hours for each
    // pairs in list_pairs_eur. KrakenApi has a blocking timer which prevents from ban if you
    // make rapid succession of requests (inside a for loop for example). Here, the ticker function
    // can take a list of pairs as parameter, so 1 request should suffice.

    // Convert Vec into comma separated values String
    let eur_pairs = format!("{:?}", list_pairs_eur);
    let eur_pairs = eur_pairs.replace("\"", "").replace("[", "").replace("]", "").replace(" ", "");

    // Get ticker
    let ticker_request = my_api.get_ticker_information(&eur_pairs).unwrap();
    let list_ticker = ticker_request.get("result").unwrap().as_object().unwrap();

    let mut pair_to_buy = "";
    let mut pair_price_var = 0.0;
    let mut current_price = 0.0;

    for pair in list_ticker {
        let name = pair.0;

        // WARNING: Kraken uses quotes to encapsulate floating value
        let pair_info = pair.1.as_object().unwrap();
        let open_price = pair_info.get("o").unwrap().as_str().unwrap().parse::<f64>().unwrap();
        let close_price_array = pair_info.get("c").unwrap().as_array().unwrap();
        let close_price = close_price_array[0].as_str().unwrap().parse::<f64>().unwrap();

        let price_var = (close_price / open_price - 1.0) * 100.0;

        if price_var > pair_price_var {
            pair_price_var = price_var;
            pair_to_buy = name;
            current_price = close_price;
        }
    }

    println!("{} has the highest price variation ({:.2}%).",
             pair_to_buy,
             pair_price_var);

    // Add a buy limit order for an amount of 100€ for a price of: current_price - 2%
    let buying_price = current_price - (current_price * 2.0 / 100.0);
    let volume = 100.0 / buying_price;

    // Specify optional parameters with an empty str ("")
    // See documentation for more informations
    let _ = my_api.add_standard_order(pair_to_buy, // name of the pair
                                      "buy", // type : buy/sell
                                      "limit", // order type : market/limit/...
                                      &buying_price.to_string(), // price 1
                                      "", // price 2
                                      &volume.to_string(), // volume
                                      "", // leverage
                                      "", // oflags (see doc)
                                      "", // starttm
                                      "", // expiretm
                                      "", // userref
                                      ""); // validate
    // In a real case example, you should check if any error occurs.
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::LinkedList;
use std::str::FromStr;

use Term::*;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;
type StackResult<T> = Result<T, Error>;

type Stack = LinkedList<Value>;
type Code = LinkedList<Term>;
type Definitions = HashMap<String, Code>;

pub struct Forth {
    code: Code,
    defs: Definitions,
    stack: Stack,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

#[derive(Debug, Clone)]
enum Term {
    Number(Value),
    Word(String),
    StartDefinition,
    EndDefinition,
}

impl FromStr for Term {
    type Err = ();

    fn from_str(s: &str) -> Result<Term, ()> {
        match s {
            ":" => Ok(StartDefinition),
            ";" => Ok(EndDefinition),
            _ => Err(()),
        }.or_else(|_| Value::from_str(s).map(Number))
            .or_else(|_| Ok(Word(s.to_ascii_lowercase())))
    }
}

impl Forth {
    pub fn new() -> Forth {
        Forth {
            code: LinkedList::new(),
            defs: HashMap::new(),
            stack: LinkedList::new(),
        }
    }

    pub fn stack(&self) -> Vec<Value> {
        self.stack.iter().cloned().collect()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let mut new_code = Forth::into_code(input);
        self.code.append(&mut new_code);
        self.run()
    }

    fn run(&mut self) -> ForthResult {
        while let Some(term) = self.code.pop_front() {
            try!(self.step_term(term))
        }

        Forth::ok()
    }

    fn step_term(&mut self, term: Term) -> ForthResult {
        match term {
            Number(value) => self.push(value),
            Word(word) => self.step_word(&word),
            StartDefinition => self.store_definition(),
            EndDefinition => Err(Error::InvalidWord),
        }
    }

    fn step_word(&mut self, word: &str) -> ForthResult {
        self.defs
            .get(word)
            .ok_or(Error::UnknownWord)
            .map(Clone::clone)
            .map(|mut code| self.code.append(&mut code))
            .or_else(|_| self.step_built_in(word))
    }

    fn step_built_in(&mut self, word: &str) -> ForthResult {
        match word {
            "+" => self.bin_op(|(a, b)| Ok(a + b)),
            "-" => self.bin_op(|(a, b)| Ok(a - b)),
            "*" => self.bin_op(|(a, b)| Ok(a * b)),
            "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)),
            "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))),
            "drop" => self.pop().and(Forth::ok()),
            "swap" => self.pop_two()
                .and_then(|(a, b)| self.push(b).and(self.push(a))),
            "over" => self.pop_two()
                .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))),
            _ => Err(Error::UnknownWord),
        }
    }

    fn store_definition(&mut self) -> ForthResult {
        let mut def = LinkedList::new();

        loop {
            match self.code.pop_front() {
                Some(EndDefinition) => break,
                Some(term) => def.push_back(term),
                None => return Err(Error::InvalidWord),
            }
        }

        if let Some(Word(name)) = def.pop_front() {
            self.store_word(name, def)
        } else {
            Err(Error::InvalidWord)
        }
    }

    fn push(&mut self, value: Value) -> ForthResult {
        self.stack.push_back(value);
        Forth::ok()
    }

    fn pop(&mut self) -> StackResult<Value> {
        self.stack.pop_back().ok_or(Error::StackUnderflow)
    }

    fn pop_two(&mut self) -> StackResult<(Value, Value)> {
        self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b))))
    }

    fn bin_op<F>(&mut self, op: F) -> ForthResult
    where
        F: FnOnce((Value, Value)) -> StackResult<Value>,
    {
        self.pop_two()
            .and_then(op)
            .and_then(|value| self.push(value))
    }

    fn store_word(&mut self, name: String, code: Code) -> ForthResult {
        let mut resolved_def = Code::new();
        for t in code.iter() {
            match t {
                Term::Number(_) => resolved_def.push_back(t.clone()),
                Term::Word(s) => if let Some(cs) = self.defs.get(s) {
                    resolved_def.append(&mut cs.clone());
                } else {
                    resolved_def.push_back(t.clone());
                },
                _ => unimplemented!("not even sure a definition in a definition is valid Forth"),
            }
        }
        self.defs.insert(name, resolved_def);
        Forth::ok()
    }

    fn into_code(input: &str) -> LinkedList<Term> {
        input
            .split(|c: char| c.is_whitespace() || c.is_control())
            .map(Term::from_str)
            .filter(Result::is_ok)
            .map(Result::unwrap)
            .collect()
    }

    fn ok() -> ForthResult {
        Ok(())
    }
}
<commit_msg>forth: Don't `use` Term<commit_after>use std::collections::HashMap;
use std::collections::LinkedList;
use std::str::FromStr;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;
type StackResult<T> = Result<T, Error>;

type Stack = LinkedList<Value>;
type Code = LinkedList<Term>;
type Definitions = HashMap<String, Code>;

pub struct Forth {
    code: Code,
    defs: Definitions,
    stack: Stack,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

#[derive(Debug, Clone)]
enum Term {
    Number(Value),
    Word(String),
    StartDefinition,
    EndDefinition,
}

impl FromStr for Term {
    type Err = ();

    fn from_str(s: &str) -> Result<Term, ()> {
        match s {
            ":" => Ok(Term::StartDefinition),
            ";" => Ok(Term::EndDefinition),
            _ => Err(()),
        }.or_else(|_| Value::from_str(s).map(Term::Number))
            .or_else(|_| Ok(Term::Word(s.to_ascii_lowercase())))
    }
}

impl Forth {
    pub fn new() -> Forth {
        Forth {
            code: LinkedList::new(),
            defs: HashMap::new(),
            stack: LinkedList::new(),
        }
    }

    pub fn stack(&self) -> Vec<Value> {
        self.stack.iter().cloned().collect()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let mut new_code = Forth::into_code(input);
        self.code.append(&mut new_code);
        self.run()
    }

    fn run(&mut self) -> ForthResult {
        while let Some(term) = self.code.pop_front() {
            try!(self.step_term(term))
        }

        Forth::ok()
    }

    fn step_term(&mut self, term: Term) -> ForthResult {
        match term {
            Term::Number(value) => self.push(value),
            Term::Word(word) => self.step_word(&word),
            Term::StartDefinition => self.store_definition(),
            Term::EndDefinition => Err(Error::InvalidWord),
        }
    }

    fn step_word(&mut self, word: &str) -> ForthResult {
        self.defs
            .get(word)
            .ok_or(Error::UnknownWord)
            .map(Clone::clone)
            .map(|mut code| self.code.append(&mut code))
            .or_else(|_| self.step_built_in(word))
    }

    fn step_built_in(&mut self, word: &str) -> ForthResult {
        match word {
            "+" => self.bin_op(|(a, b)| Ok(a + b)),
            "-" => self.bin_op(|(a, b)| Ok(a - b)),
            "*" => self.bin_op(|(a, b)| Ok(a * b)),
            "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)),
            "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))),
            "drop" => self.pop().and(Forth::ok()),
            "swap" => self.pop_two()
                .and_then(|(a, b)| self.push(b).and(self.push(a))),
            "over" => self.pop_two()
                .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))),
            _ => Err(Error::UnknownWord),
        }
    }

    fn store_definition(&mut self) -> ForthResult {
        let mut def = LinkedList::new();

        loop {
            match self.code.pop_front() {
                Some(Term::EndDefinition) => break,
                Some(term) => def.push_back(term),
                None => return Err(Error::InvalidWord),
            }
        }

        if let Some(Term::Word(name)) = def.pop_front() {
            self.store_word(name, def)
        } else {
            Err(Error::InvalidWord)
        }
    }

    fn push(&mut self, value: Value) -> ForthResult {
        self.stack.push_back(value);
        Forth::ok()
    }

    fn pop(&mut self) -> StackResult<Value> {
        self.stack.pop_back().ok_or(Error::StackUnderflow)
    }

    fn pop_two(&mut self) -> StackResult<(Value, Value)> {
        self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b))))
    }

    fn bin_op<F>(&mut self, op: F) -> ForthResult
    where
        F: FnOnce((Value, Value)) -> StackResult<Value>,
    {
        self.pop_two()
            .and_then(op)
            .and_then(|value| self.push(value))
    }

    fn store_word(&mut self, name: String, code: Code) -> ForthResult {
        let mut resolved_def = Code::new();
        for t in code.iter() {
            match t {
                Term::Number(_) => resolved_def.push_back(t.clone()),
                Term::Word(s) => if let Some(cs) = self.defs.get(s) {
                    resolved_def.append(&mut cs.clone());
                } else {
                    resolved_def.push_back(t.clone());
                },
                _ => unimplemented!("not even sure a definition in a definition is valid Forth"),
            }
        }
        self.defs.insert(name, resolved_def);
        Forth::ok()
    }

    fn into_code(input: &str) -> LinkedList<Term> {
        input
            .split(|c: char| c.is_whitespace() || c.is_control())
            .map(Term::from_str)
            .filter(Result::is_ok)
            .map(Result::unwrap)
            .collect()
    }

    fn ok() -> ForthResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>
<commit_msg>sieve: Added template to stub file<commit_after>pub fn primes_up_to(upper_bound: u64) -> Vec<u64> {
    unimplemented!("Construct a vector of all primes up to {}", upper_bound);
}
<|endoftext|>