<commit_before>use super::{
    heap::{Heap, ObjectData, ObjectPointer},
    tracer::{TraceEntry, Tracer},
    use_provider::UseProvider,
    value::Value,
};
use crate::{
    compiler::{hir::Id, hir_to_lir::HirToLir, lir::Instruction},
    input::Input,
};
use itertools::Itertools;
use log;
use std::collections::HashMap;

/// A VM can execute some byte code.
#[derive(Clone)]
pub struct Vm {
    pub status: Status,
    next_instruction: InstructionPointer,
    pub heap: Heap,
    pub data_stack: Vec<ObjectPointer>,
    pub call_stack: Vec<InstructionPointer>,
    pub import_stack: Vec<Input>,
    pub tracer: Tracer,
    pub fuzzable_closures: Vec<(Id, ObjectPointer)>,
}

#[derive(Clone)]
pub enum Status {
    Running,
    Done,
    Panicked(Value),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InstructionPointer {
    /// Pointer to the closure object that is currently running code.
    closure: ObjectPointer,

    /// Index of the next instruction to run.
    instruction: usize,
}
impl InstructionPointer {
    fn null_pointer() -> Self {
        Self {
            closure: 0,
            instruction: 0,
        }
    }
    fn start_of_closure(closure: ObjectPointer) -> Self {
        Self {
            closure,
            instruction: 0,
        }
    }
}

impl Vm {
    pub fn new() -> Self {
        Self {
            status: Status::Done,
            next_instruction: InstructionPointer::null_pointer(),
            heap: Heap::new(),
            data_stack: vec![],
            call_stack: vec![],
            import_stack: vec![],
            tracer: Tracer::default(),
            fuzzable_closures: vec![],
        }
    }

    pub fn set_up_closure_execution<U: UseProvider>(
        &mut self,
        use_provider: &U,
        closure: Value,
        arguments: Vec<Value>,
    ) {
        assert!(matches!(self.status, Status::Done));
        assert!(self.data_stack.is_empty());
        assert!(self.call_stack.is_empty());

        let num_args = if let Value::Closure { num_args, .. } = closure.clone() {
            num_args
        } else {
            panic!("Called start_closure with a non-closure.");
        };

        assert_eq!(num_args, arguments.len());

        for arg in arguments {
            let address = self.heap.import(arg);
            self.data_stack.push(address);
        }
        let address = self.heap.import(closure);
        self.data_stack.push(address);

        self.run_instruction(use_provider, Instruction::Call { num_args });
        self.status = Status::Running;
    }
    pub fn tear_down_closure_execution(&mut self) -> Value {
        assert!(matches!(self.status, Status::Done));
        let return_value = self.data_stack.pop().unwrap();
        self.heap.export(return_value)
    }

    pub fn set_up_module_closure_execution<U: UseProvider>(
        &mut self,
        use_provider: &U,
        closure: Value,
    ) {
        if let Value::Closure {
            captured, num_args, ..
        } = closure.clone()
        {
            assert_eq!(captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff).");
            assert_eq!(num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments).");
        } else {
            panic!("Called start_module_closure with a non-closure.");
        };
        self.set_up_closure_execution(use_provider, closure, vec![])
    }
    pub fn tear_down_module_closure_execution(&mut self) -> Value {
        self.tear_down_closure_execution()
    }

    pub fn status(&self) -> Status {
        self.status.clone()
    }

    fn get_from_data_stack(&self, offset: usize) -> ObjectPointer {
        self.data_stack[self.data_stack.len() - 1 - offset as usize].clone()
    }

    pub fn run<U: UseProvider>(&mut self, use_provider: &U, mut num_instructions: u16) {
        assert!(
            matches!(self.status, Status::Running),
            "Called Vm::run on a vm that is not ready to run."
        );
        while matches!(self.status, Status::Running) && num_instructions > 0 {
            num_instructions -= 1;

            let current_closure = self.heap.get(self.next_instruction.closure);
            let current_body = if let ObjectData::Closure { body, .. } = &current_closure.data {
                body
            } else {
                panic!("The instruction pointer points to a non-closure.");
            };
            let instruction = current_body[self.next_instruction.instruction].clone();

            log::trace!(
                "Data stack: {}",
                self.data_stack
                    .iter()
                    .map(|address| format!("{}", self.heap.export_without_dropping(*address)))
                    .join(", ")
            );
            log::trace!(
                "Call stack: {}",
                self.call_stack
                    .iter()
                    .map(|ip| format!("{}:{}", ip.closure, ip.instruction))
                    .join(", ")
            );
            log::trace!(
                "Instruction pointer: {}:{}",
                self.next_instruction.closure,
                self.next_instruction.instruction
            );
            log::trace!("Heap: {:?}", self.heap);

            log::trace!("Running instruction: {instruction:?}");
            self.next_instruction.instruction += 1;
            self.run_instruction(use_provider, instruction);

            if self.next_instruction == InstructionPointer::null_pointer() {
                self.status = Status::Done;
            }
        }
    }
    pub fn run_instruction<U: UseProvider>(&mut self, use_provider: &U, instruction: Instruction) {
        match instruction {
            Instruction::CreateInt(int) => {
                let address = self.heap.create(ObjectData::Int(int));
                self.data_stack.push(address);
            }
            Instruction::CreateText(text) => {
                let address = self.heap.create(ObjectData::Text(text));
                self.data_stack.push(address);
            }
            Instruction::CreateSymbol(symbol) => {
                let address = self.heap.create(ObjectData::Symbol(symbol));
                self.data_stack.push(address);
            }
            Instruction::CreateStruct { num_entries } => {
                let mut key_value_addresses = vec![];
                for _ in 0..(2 * num_entries) {
                    key_value_addresses.push(self.data_stack.pop().unwrap());
                }
                let mut entries = HashMap::new();
                for mut key_and_value in &key_value_addresses.into_iter().rev().chunks(2) {
                    let key = key_and_value.next().unwrap();
                    let value = key_and_value.next().unwrap();
                    assert_eq!(key_and_value.next(), None);
                    entries.insert(key, value);
                }
                let address = self.heap.create(ObjectData::Struct(entries));
                self.data_stack.push(address);
            }
            Instruction::CreateClosure {
                num_args,
                body,
                captured,
            } => {
                let captured = captured
                    .iter()
                    .map(|offset| self.get_from_data_stack(*offset))
                    .collect_vec();
                for address in &captured {
                    self.heap.dup(*address);
                }
                let address = self.heap.create(ObjectData::Closure {
                    captured,
                    num_args,
                    body,
                });
                self.data_stack.push(address);
            }
            Instruction::CreateBuiltin(builtin) => {
                let address = self.heap.create(ObjectData::Builtin(builtin));
                self.data_stack.push(address);
            }
            Instruction::PopMultipleBelowTop(n) => {
                let top = self.data_stack.pop().unwrap();
                for _ in 0..n {
                    let address = self.data_stack.pop().unwrap();
                    self.heap.drop(address);
                }
                self.data_stack.push(top);
            }
            Instruction::PushFromStack(offset) => {
                let address = self.get_from_data_stack(offset);
                self.heap.dup(address);
                self.data_stack.push(address);
            }
            Instruction::Call { num_args } => {
                let closure_address = self.data_stack.pop().unwrap();
                let mut args = vec![];
                for _ in 0..num_args {
                    args.push(self.data_stack.pop().unwrap());
                }
                args.reverse();

                match self.heap.get(closure_address).data.clone() {
                    ObjectData::Closure {
                        captured,
                        num_args: expected_num_args,
                        ..
                    } => {
                        if num_args != expected_num_args {
                            self.panic(format!("Closure expects {expected_num_args} parameters, but you called it with {num_args} arguments."));
                            return;
                        }

                        self.call_stack.push(self.next_instruction);
                        self.data_stack.append(&mut captured.clone());
                        for captured in captured {
                            self.heap.dup(captured);
                        }
                        self.data_stack.append(&mut args);
                        self.next_instruction =
                            InstructionPointer::start_of_closure(closure_address);
                    }
                    ObjectData::Builtin(builtin) => {
                        self.heap.drop(closure_address);
                        self.run_builtin_function(use_provider, &builtin, &args);
                    }
                    _ => panic!("Can only call closures and builtins."),
                };
            }
            Instruction::Needs => {
                let condition = self.data_stack.pop().unwrap();
                let message = self.data_stack.pop().unwrap();

                match self.heap.get(condition).data.clone() {
                    ObjectData::Symbol(symbol) => match symbol.as_str() {
                        "True" => {
                            self.data_stack.push(self.heap.import(Value::nothing()));
                        }
                        "False" => {
                            self.status =
                                Status::Panicked(self.heap.export_without_dropping(message))
                        }
                        _ => {
                            self.panic("Needs expects True or False as a symbol.".to_string());
                        }
                    },
                    _ => {
                        self.panic("Needs expects a boolean symbol.".to_string());
                    }
                }
            }
            Instruction::Return => {
                self.heap.drop(self.next_instruction.closure);
                let caller = self.call_stack.pop().unwrap();
                self.next_instruction = caller;
            }
            Instruction::RegisterFuzzableClosure(id) => {
                let closure = self.data_stack.last().unwrap().clone();
                self.heap.dup(closure);
                self.fuzzable_closures.push((id, closure));
            }
            Instruction::TraceValueEvaluated(id) => {
                let address = *self.data_stack.last().unwrap();
                let value = self.heap.export_without_dropping(address);
                self.tracer.push(TraceEntry::ValueEvaluated { id, value });
            }
            Instruction::TraceCallStarts { id, num_args } => {
                let closure_address = self.data_stack.last().unwrap();
                let closure = self.heap.export_without_dropping(*closure_address);

                let mut args = vec![];
                let stack_size = self.data_stack.len();
                for i in 0..num_args {
                    let address = self.data_stack[stack_size - i - 2];
                    let argument = self.heap.export_without_dropping(address);
                    args.push(argument);
                }
                args.reverse();

                self.tracer
                    .push(TraceEntry::CallStarted { id, closure, args });
            }
            Instruction::TraceCallEnds => {
                let return_value_address = self.data_stack.last().unwrap();
                let return_value = self.heap.export_without_dropping(*return_value_address);
                self.tracer.push(TraceEntry::CallEnded { return_value });
            }
            Instruction::TraceNeedsStarts { id } => {
                let condition = self.data_stack[self.data_stack.len() - 1];
                let message = self.data_stack[self.data_stack.len() - 2];
                let condition = self.heap.export_without_dropping(condition);
                let message = self.heap.export_without_dropping(message);
                self.tracer.push(TraceEntry::NeedsStarted {
                    id,
                    condition,
                    message,
                });
            }
            Instruction::TraceNeedsEnds => self.tracer.push(TraceEntry::NeedsEnded),
            Instruction::TraceModuleStarts { input } => {
                if self.import_stack.contains(&input) {
                    self.panic(format!(
                        "there's an import cycle ({})",
                        self.import_stack
                            .iter()
                            .skip_while(|it| **it != input)
                            .chain([&input])
                            .map(|input| format!("{input}"))
                            .join(" -> "),
                    ));
                }
                self.import_stack.push(input.clone());
                self.tracer.push(TraceEntry::ModuleStarted { input });
            }
            Instruction::TraceModuleEnds => {
                self.import_stack.pop().unwrap();
                self.tracer.push(TraceEntry::ModuleEnded {
                    export_map: self
                        .heap
                        .export_without_dropping(*self.data_stack.last().unwrap()),
                })
            }
            Instruction::Error { id, error } => {
                self.panic(format!(
                    "The VM crashed because there was an error at {id}: {error:?}"
                ));
            }
        }
    }

    pub fn panic(&mut self, message: String) -> Value {
        self.status = Status::Panicked(Value::Text(message));
        Value::Symbol("Never".to_string())
    }
}
<commit_msg>Comment out logging in VM<commit_after>use super::{
    heap::{Heap, ObjectData, ObjectPointer},
    tracer::{TraceEntry, Tracer},
    use_provider::UseProvider,
    value::Value,
};
use crate::{
    compiler::{hir::Id, hir_to_lir::HirToLir, lir::Instruction},
    input::Input,
};
use itertools::Itertools;
use log;
use std::collections::HashMap;

/// A VM can execute some byte code.
#[derive(Clone)]
pub struct Vm {
    pub status: Status,
    next_instruction: InstructionPointer,
    pub heap: Heap,
    pub data_stack: Vec<ObjectPointer>,
    pub call_stack: Vec<InstructionPointer>,
    pub import_stack: Vec<Input>,
    pub tracer: Tracer,
    pub fuzzable_closures: Vec<(Id, ObjectPointer)>,
}

#[derive(Clone)]
pub enum Status {
    Running,
    Done,
    Panicked(Value),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InstructionPointer {
    /// Pointer to the closure object that is currently running code.
    closure: ObjectPointer,

    /// Index of the next instruction to run.
    instruction: usize,
}
impl InstructionPointer {
    fn null_pointer() -> Self {
        Self {
            closure: 0,
            instruction: 0,
        }
    }
    fn start_of_closure(closure: ObjectPointer) -> Self {
        Self {
            closure,
            instruction: 0,
        }
    }
}

impl Vm {
    pub fn new() -> Self {
        Self {
            status: Status::Done,
            next_instruction: InstructionPointer::null_pointer(),
            heap: Heap::new(),
            data_stack: vec![],
            call_stack: vec![],
            import_stack: vec![],
            tracer: Tracer::default(),
            fuzzable_closures: vec![],
        }
    }

    pub fn set_up_closure_execution<U: UseProvider>(
        &mut self,
        use_provider: &U,
        closure: Value,
        arguments: Vec<Value>,
    ) {
        assert!(matches!(self.status, Status::Done));
        assert!(self.data_stack.is_empty());
        assert!(self.call_stack.is_empty());

        let num_args = if let Value::Closure { num_args, .. } = closure.clone() {
            num_args
        } else {
            panic!("Called start_closure with a non-closure.");
        };

        assert_eq!(num_args, arguments.len());

        for arg in arguments {
            let address = self.heap.import(arg);
            self.data_stack.push(address);
        }
        let address = self.heap.import(closure);
        self.data_stack.push(address);

        self.run_instruction(use_provider, Instruction::Call { num_args });
        self.status = Status::Running;
    }
    pub fn tear_down_closure_execution(&mut self) -> Value {
        assert!(matches!(self.status, Status::Done));
        let return_value = self.data_stack.pop().unwrap();
        self.heap.export(return_value)
    }

    pub fn set_up_module_closure_execution<U: UseProvider>(
        &mut self,
        use_provider: &U,
        closure: Value,
    ) {
        if let Value::Closure {
            captured, num_args, ..
        } = closure.clone()
        {
            assert_eq!(captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff).");
            assert_eq!(num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments).");
        } else {
            panic!("Called start_module_closure with a non-closure.");
        };
        self.set_up_closure_execution(use_provider, closure, vec![])
    }
    pub fn tear_down_module_closure_execution(&mut self) -> Value {
        self.tear_down_closure_execution()
    }

    pub fn status(&self) -> Status {
        self.status.clone()
    }

    fn get_from_data_stack(&self, offset: usize) -> ObjectPointer {
        self.data_stack[self.data_stack.len() - 1 - offset as usize].clone()
    }

    pub fn run<U: UseProvider>(&mut self, use_provider: &U, mut num_instructions: u16) {
        assert!(
            matches!(self.status, Status::Running),
            "Called Vm::run on a vm that is not ready to run."
        );
        while matches!(self.status, Status::Running) && num_instructions > 0 {
            num_instructions -= 1;

            let current_closure = self.heap.get(self.next_instruction.closure);
            let current_body = if let ObjectData::Closure { body, .. } = &current_closure.data {
                body
            } else {
                panic!("The instruction pointer points to a non-closure.");
            };
            let instruction = current_body[self.next_instruction.instruction].clone();

            // log::trace!(
            //     "Data stack: {}",
            //     self.data_stack
            //         .iter()
            //         .map(|address| format!("{}", self.heap.export_without_dropping(*address)))
            //         .join(", ")
            // );
            // log::trace!(
            //     "Call stack: {}",
            //     self.call_stack
            //         .iter()
            //         .map(|ip| format!("{}:{}", ip.closure, ip.instruction))
            //         .join(", ")
            // );
            // log::trace!(
            //     "Instruction pointer: {}:{}",
            //     self.next_instruction.closure,
            //     self.next_instruction.instruction
            // );
            // log::trace!("Heap: {:?}", self.heap);

            log::trace!("Running instruction: {instruction:?}");
            self.next_instruction.instruction += 1;
            self.run_instruction(use_provider, instruction);

            if self.next_instruction == InstructionPointer::null_pointer() {
                self.status = Status::Done;
            }
        }
    }
    pub fn run_instruction<U: UseProvider>(&mut self, use_provider: &U, instruction: Instruction) {
        match instruction {
            Instruction::CreateInt(int) => {
                let address = self.heap.create(ObjectData::Int(int));
                self.data_stack.push(address);
            }
            Instruction::CreateText(text) => {
                let address = self.heap.create(ObjectData::Text(text));
                self.data_stack.push(address);
            }
            Instruction::CreateSymbol(symbol) => {
                let address = self.heap.create(ObjectData::Symbol(symbol));
                self.data_stack.push(address);
            }
            Instruction::CreateStruct { num_entries } => {
                let mut key_value_addresses = vec![];
                for _ in 0..(2 * num_entries) {
                    key_value_addresses.push(self.data_stack.pop().unwrap());
                }
                let mut entries = HashMap::new();
                for mut key_and_value in &key_value_addresses.into_iter().rev().chunks(2) {
                    let key = key_and_value.next().unwrap();
                    let value = key_and_value.next().unwrap();
                    assert_eq!(key_and_value.next(), None);
                    entries.insert(key, value);
                }
                let address = self.heap.create(ObjectData::Struct(entries));
                self.data_stack.push(address);
            }
            Instruction::CreateClosure {
                num_args,
                body,
                captured,
            } => {
                let captured = captured
                    .iter()
                    .map(|offset| self.get_from_data_stack(*offset))
                    .collect_vec();
                for address in &captured {
                    self.heap.dup(*address);
                }
                let address = self.heap.create(ObjectData::Closure {
                    captured,
                    num_args,
                    body,
                });
                self.data_stack.push(address);
            }
            Instruction::CreateBuiltin(builtin) => {
                let address = self.heap.create(ObjectData::Builtin(builtin));
                self.data_stack.push(address);
            }
            Instruction::PopMultipleBelowTop(n) => {
                let top = self.data_stack.pop().unwrap();
                for _ in 0..n {
                    let address = self.data_stack.pop().unwrap();
                    self.heap.drop(address);
                }
                self.data_stack.push(top);
            }
            Instruction::PushFromStack(offset) => {
                let address = self.get_from_data_stack(offset);
                self.heap.dup(address);
                self.data_stack.push(address);
            }
            Instruction::Call { num_args } => {
                let closure_address = self.data_stack.pop().unwrap();
                let mut args = vec![];
                for _ in 0..num_args {
                    args.push(self.data_stack.pop().unwrap());
                }
                args.reverse();

                match self.heap.get(closure_address).data.clone() {
                    ObjectData::Closure {
                        captured,
                        num_args: expected_num_args,
                        ..
                    } => {
                        if num_args != expected_num_args {
                            self.panic(format!("Closure expects {expected_num_args} parameters, but you called it with {num_args} arguments."));
                            return;
                        }

                        self.call_stack.push(self.next_instruction);
                        self.data_stack.append(&mut captured.clone());
                        for captured in captured {
                            self.heap.dup(captured);
                        }
                        self.data_stack.append(&mut args);
                        self.next_instruction =
                            InstructionPointer::start_of_closure(closure_address);
                    }
                    ObjectData::Builtin(builtin) => {
                        self.heap.drop(closure_address);
                        self.run_builtin_function(use_provider, &builtin, &args);
                    }
                    _ => panic!("Can only call closures and builtins."),
                };
            }
            Instruction::Needs => {
                let condition = self.data_stack.pop().unwrap();
                let message = self.data_stack.pop().unwrap();

                match self.heap.get(condition).data.clone() {
                    ObjectData::Symbol(symbol) => match symbol.as_str() {
                        "True" => {
                            self.data_stack.push(self.heap.import(Value::nothing()));
                        }
                        "False" => {
                            self.status =
                                Status::Panicked(self.heap.export_without_dropping(message))
                        }
                        _ => {
                            self.panic("Needs expects True or False as a symbol.".to_string());
                        }
                    },
                    _ => {
                        self.panic("Needs expects a boolean symbol.".to_string());
                    }
                }
            }
            Instruction::Return => {
                self.heap.drop(self.next_instruction.closure);
                let caller = self.call_stack.pop().unwrap();
                self.next_instruction = caller;
            }
            Instruction::RegisterFuzzableClosure(id) => {
                let closure = self.data_stack.last().unwrap().clone();
                self.heap.dup(closure);
                self.fuzzable_closures.push((id, closure));
            }
            Instruction::TraceValueEvaluated(id) => {
                let address = *self.data_stack.last().unwrap();
                let value = self.heap.export_without_dropping(address);
                self.tracer.push(TraceEntry::ValueEvaluated { id, value });
            }
            Instruction::TraceCallStarts { id, num_args } => {
                let closure_address = self.data_stack.last().unwrap();
                let closure = self.heap.export_without_dropping(*closure_address);

                let mut args = vec![];
                let stack_size = self.data_stack.len();
                for i in 0..num_args {
                    let address = self.data_stack[stack_size - i - 2];
                    let argument = self.heap.export_without_dropping(address);
                    args.push(argument);
                }
                args.reverse();

                self.tracer
                    .push(TraceEntry::CallStarted { id, closure, args });
            }
            Instruction::TraceCallEnds => {
                let return_value_address = self.data_stack.last().unwrap();
                let return_value = self.heap.export_without_dropping(*return_value_address);
                self.tracer.push(TraceEntry::CallEnded { return_value });
            }
            Instruction::TraceNeedsStarts { id } => {
                let condition = self.data_stack[self.data_stack.len() - 1];
                let message = self.data_stack[self.data_stack.len() - 2];
                let condition = self.heap.export_without_dropping(condition);
                let message = self.heap.export_without_dropping(message);
                self.tracer.push(TraceEntry::NeedsStarted {
                    id,
                    condition,
                    message,
                });
            }
            Instruction::TraceNeedsEnds => self.tracer.push(TraceEntry::NeedsEnded),
            Instruction::TraceModuleStarts { input } => {
                if self.import_stack.contains(&input) {
                    self.panic(format!(
                        "there's an import cycle ({})",
                        self.import_stack
                            .iter()
                            .skip_while(|it| **it != input)
                            .chain([&input])
                            .map(|input| format!("{input}"))
                            .join(" -> "),
                    ));
                }
                self.import_stack.push(input.clone());
                self.tracer.push(TraceEntry::ModuleStarted { input });
            }
            Instruction::TraceModuleEnds => {
                self.import_stack.pop().unwrap();
                self.tracer.push(TraceEntry::ModuleEnded {
                    export_map: self
                        .heap
                        .export_without_dropping(*self.data_stack.last().unwrap()),
                })
            }
            Instruction::Error { id, error } => {
                self.panic(format!(
                    "The VM crashed because there was an error at {id}: {error:?}"
                ));
            }
        }
    }

    pub fn panic(&mut self, message: String) -> Value {
        self.status = Status::Panicked(Value::Text(message));
        Value::Symbol("Never".to_string())
    }
}
<|endoftext|>


<commit_before>extern crate ostrov;
extern crate test;

use ostrov::ast::AST;
use ostrov::runtime::Runtime;

use test::Bencher;

#[bench]
fn nested_evaluation(b: &mut Bencher) {
    b.iter(|| {
        let input = "
            (if
                (if
                    (if
                        (if
                            (if
                                (if
                                    (> 1 2 3 4 5 6 7 8 9 10)
                                    (= 2 2 2 2 2 2 2 2 2 2)
                                    #f
                                )
                                (= 2 2 2 2 2 2 2 2 2 2)
                                #f
                            )
                            (= 2 2 2 2 2 2 2 2 2 2)
                            #f
                        )
                        (= 2 2 2 2 2 2 2 2 2 2)
                        #f
                    )
                    (= 2 2 2 2 2 2 2 2 2 2)
                    #f
                )
                2
                3
            )
        ";

        let mut runtime = Runtime::new();

        match runtime.eval_str(input) {
            Ok(exprs)  => assert_eq!(AST::Integer(3), exprs[0]),
            Err(error) => panic!(format!("{}", error)),
        }
    })
}
<commit_msg>Added benchmark on procedure evaluation.<commit_after>extern crate ostrov;
extern crate test;

use ostrov::ast::AST;
use ostrov::runtime::Runtime;

use test::Bencher;

#[bench]
fn nested_evaluation(b: &mut Bencher) {
    b.iter(|| {
        let input = "
            (if
                (if
                    (if
                        (if
                            (if
                                (if
                                    (> 1 2 3 4 5 6 7 8 9 10)
                                    (= 2 2 2 2 2 2 2 2 2 2)
                                    #f
                                )
                                (= 2 2 2 2 2 2 2 2 2 2)
                                #f
                            )
                            (= 2 2 2 2 2 2 2 2 2 2)
                            #f
                        )
                        (= 2 2 2 2 2 2 2 2 2 2)
                        #f
                    )
                    (= 2 2 2 2 2 2 2 2 2 2)
                    #f
                )
                2
                3
            )
        ";

        let mut runtime = Runtime::new();

        match runtime.eval_str(input) {
            Ok(exprs)  => assert_eq!(AST::Integer(3), exprs[0]),
            Err(error) => panic!(format!("{}", error)),
        }
    })
}

#[bench]
fn procedure_evaluation(b: &mut Bencher) {
    b.iter(|| {
        let input = "
            (define (fact n)
                (if (= n 1)
                    1
                    (* n (fact (- n 1)))))
            (fact 15)
        ";

        let mut runtime = Runtime::new();

        match runtime.eval_str(input) {
            Ok(exprs)  => assert_eq!(AST::Integer(1307674368000), exprs[1]),
            Err(error) => panic!(format!("{}", error)),
        }
    })
}
<|endoftext|>


<commit_before>#![feature(test)]
#![deny(warnings)]

extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;
extern crate test;
extern crate tokio;

use std::net::SocketAddr;

use futures::{Future, Stream};
use tokio::runtime::current_thread::Runtime;

use hyper::{Body, Method, Request, Response, Server};
use hyper::client::HttpConnector;

#[bench]
fn http1_get(b: &mut test::Bencher) {
    opts()
        .bench(b)
}

#[bench]
fn http1_post(b: &mut test::Bencher) {
    opts()
        .method(Method::POST)
        .request_body(b"foo bar baz quux")
        .bench(b)
}

#[bench]
fn http1_get_parallel(b: &mut test::Bencher) {
    opts()
        .parallel(10)
        .bench(b)
}

#[bench]
fn http2_get(b: &mut test::Bencher) {
    opts()
        .http2()
        .bench(b)
}

#[bench]
fn http2_post(b: &mut test::Bencher) {
    opts()
        .http2()
        .method(Method::POST)
        .request_body(b"foo bar baz quux")
        .bench(b)
}

#[bench]
fn http2_get_parallel(b: &mut test::Bencher) {
    opts()
        .http2()
        .parallel(10)
        .bench(b)
}

// ==== Benchmark Options =====

struct Opts {
    http2: bool,
    parallel_cnt: u32,
    request_method: Method,
    request_body: Option<&'static [u8]>,
    response_body: &'static [u8],
}

fn opts() -> Opts {
    Opts {
        http2: false,
        parallel_cnt: 1,
        request_method: Method::GET,
        request_body: None,
        response_body: b"Hello",
    }
}

impl Opts {
    fn http2(mut self) -> Self {
        self.http2 = true;
        self
    }

    fn method(mut self, m: Method) -> Self {
        self.request_method = m;
        self
    }

    fn request_body(mut self, body: &'static [u8]) -> Self {
        self.request_body = Some(body);
        self
    }

    fn parallel(mut self, cnt: u32) -> Self {
        assert!(cnt > 0, "parallel count must be larger than 0");
        self.parallel_cnt = cnt;
        self
    }

    fn bench(self, b: &mut test::Bencher) {
        let _ = pretty_env_logger::try_init();
        let mut rt = Runtime::new().unwrap();
        let addr = spawn_hello(&mut rt, self.response_body);

        let connector = HttpConnector::new(1);
        let client = hyper::Client::builder()
            .http2_only(self.http2)
            .build::<_, Body>(connector);

        let url: hyper::Uri = format!("http://{}/hello", addr).parse().unwrap();

        let make_request = || {
            let body = self
                .request_body
                .map(Body::from)
                .unwrap_or_else(|| Body::empty());
            let mut req = Request::new(body);
            *req.method_mut() = self.request_method.clone();
            req
        };

        if self.parallel_cnt == 1 {
            b.iter(move || {
                let mut req = make_request();
                *req.uri_mut() = url.clone();
                rt.block_on(client.request(req).and_then(|res| {
                    res.into_body().for_each(|_chunk| {
                        Ok(())
                    })
                })).expect("client wait");
            });
        } else {
            b.iter(|| {
                let futs = (0..self.parallel_cnt)
                    .into_iter()
                    .map(|_| {
                        let mut req = make_request();
                        *req.uri_mut() = url.clone();
                        client.request(req).and_then(|res| {
                            res.into_body().for_each(|_chunk| {
                                Ok(())
                            })
                        }).map_err(|e| panic!("client error: {}", e))
                    });
                let _ = rt.block_on(::futures::future::join_all(futs));
            });
        }
    }
}

fn spawn_hello(rt: &mut Runtime, body: &'static [u8]) -> SocketAddr {
    use hyper::service::{service_fn};
    let addr = "127.0.0.1:0".parse().unwrap();

    let srv = Server::bind(&addr)
        .serve(move || {
            service_fn(move |req: Request<Body>| {
                req.into_body()
                    .concat2()
                    .map(move |_| {
                        Response::new(Body::from(body))
                    })
            })
        });
    let addr = srv.local_addr();
    let fut = srv.map_err(|err| panic!("server error: {}", err));
    rt.spawn(fut);
    return addr
}
<commit_msg>test(benches): don't concat chunks, just drop them<commit_after>#![feature(test)]
#![deny(warnings)]

extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;
extern crate test;
extern crate tokio;

use std::net::SocketAddr;

use futures::{Future, Stream};
use tokio::runtime::current_thread::Runtime;

use hyper::{Body, Method, Request, Response, Server};
use hyper::client::HttpConnector;

#[bench]
fn http1_get(b: &mut test::Bencher) {
    opts()
        .bench(b)
}

#[bench]
fn http1_post(b: &mut test::Bencher) {
    opts()
        .method(Method::POST)
        .request_body(b"foo bar baz quux")
        .bench(b)
}

#[bench]
fn http1_get_parallel(b: &mut test::Bencher) {
    opts()
        .parallel(10)
        .bench(b)
}

#[bench]
fn http2_get(b: &mut test::Bencher) {
    opts()
        .http2()
        .bench(b)
}

#[bench]
fn http2_post(b: &mut test::Bencher) {
    opts()
        .http2()
        .method(Method::POST)
        .request_body(b"foo bar baz quux")
        .bench(b)
}

#[bench]
fn http2_get_parallel(b: &mut test::Bencher) {
    opts()
        .http2()
        .parallel(10)
        .bench(b)
}

// ==== Benchmark Options =====

struct Opts {
    http2: bool,
    parallel_cnt: u32,
    request_method: Method,
    request_body: Option<&'static [u8]>,
    response_body: &'static [u8],
}

fn opts() -> Opts {
    Opts {
        http2: false,
        parallel_cnt: 1,
        request_method: Method::GET,
        request_body: None,
        response_body: b"Hello",
    }
}

impl Opts {
    fn http2(mut self) -> Self {
        self.http2 = true;
        self
    }

    fn method(mut self, m: Method) -> Self {
        self.request_method = m;
        self
    }

    fn request_body(mut self, body: &'static [u8]) -> Self {
        self.request_body = Some(body);
        self
    }

    fn parallel(mut self, cnt: u32) -> Self {
        assert!(cnt > 0, "parallel count must be larger than 0");
        self.parallel_cnt = cnt;
        self
    }

    fn bench(self, b: &mut test::Bencher) {
        let _ = pretty_env_logger::try_init();
        let mut rt = Runtime::new().unwrap();
        let addr = spawn_hello(&mut rt, self.response_body);

        let connector = HttpConnector::new(1);
        let client = hyper::Client::builder()
            .http2_only(self.http2)
            .build::<_, Body>(connector);

        let url: hyper::Uri = format!("http://{}/hello", addr).parse().unwrap();

        let make_request = || {
            let body = self
                .request_body
                .map(Body::from)
                .unwrap_or_else(|| Body::empty());
            let mut req = Request::new(body);
            *req.method_mut() = self.request_method.clone();
            req
        };

        if self.parallel_cnt == 1 {
            b.iter(move || {
                let mut req = make_request();
                *req.uri_mut() = url.clone();
                rt.block_on(client.request(req).and_then(|res| {
                    res.into_body().for_each(|_chunk| {
                        Ok(())
                    })
                })).expect("client wait");
            });
        } else {
            b.iter(|| {
                let futs = (0..self.parallel_cnt)
                    .into_iter()
                    .map(|_| {
                        let mut req = make_request();
                        *req.uri_mut() = url.clone();
                        client.request(req).and_then(|res| {
                            res.into_body().for_each(|_chunk| {
                                Ok(())
                            })
                        }).map_err(|e| panic!("client error: {}", e))
                    });
                let _ = rt.block_on(::futures::future::join_all(futs));
            });
        }
    }
}

fn spawn_hello(rt: &mut Runtime, body: &'static [u8]) -> SocketAddr {
    use hyper::service::{service_fn};
    let addr = "127.0.0.1:0".parse().unwrap();

    let srv = Server::bind(&addr)
        .serve(move || {
            service_fn(move |req: Request<Body>| {
                req
                    .into_body()
                    .for_each(|_chunk| {
                        Ok(())
                    })
                    .map(move |_| {
                        Response::new(Body::from(body))
                    })
            })
        });
    let addr = srv.local_addr();
    let fut = srv.map_err(|err| panic!("server error: {}", err));
    rt.spawn(fut);
    return addr
}
<|endoftext|>


<commit_before>use std::net::UdpSocket;

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use once_cell::sync::Lazy;

const MESSAGE_SIZE: usize = 0xffff;
const DEFAULT_MESSAGE: [u8; 0xffff] = [0xff; 0xffff];
const BENCH_LOOP_ADDR: &str = "127.0.0.1:8002";
const FEEDBACK_LOOP_ADDR: &str = "127.0.0.1:8001";
const QUILKIN_ADDR: &str = "127.0.0.1:8000";
const NUMBER_OF_PACKETS: usize = 10_000;

const PACKETS: &[&[u8]] = &[
    // Half IPv4 MTU.
    &[0xffu8; 254],
    // IPv4 MTU.
    &[0xffu8; 508],
    // Ethernet MTU.
    &[0xffu8; 1500],
];

static SERVER_INIT: Lazy<()> = Lazy::new(|| {
    std::thread::spawn(|| {
        let runtime = tokio::runtime::Runtime::new().unwrap();
        let config = quilkin::config::Builder::empty()
            .with_port(8000)
            .with_static(
                vec![],
                vec![quilkin::endpoint::Endpoint::new(
                    FEEDBACK_LOOP_ADDR.parse().unwrap(),
                )],
            )
            .build();
        let server = quilkin::Builder::from(std::sync::Arc::new(config))
            .validate()
            .unwrap()
            .build();

        runtime.block_on(async move {
            let (_shutdown_tx, shutdown_rx) = tokio::sync::watch::channel::<()>(());
            server.run(shutdown_rx).await.unwrap();
        });
    });
});

static FEEDBACK_LOOP: Lazy<()> = Lazy::new(|| {
    std::thread::spawn(|| {
        let socket = UdpSocket::bind(FEEDBACK_LOOP_ADDR).unwrap();

        loop {
            let mut packet = [0; MESSAGE_SIZE];
            let (_, addr) = socket.recv_from(&mut packet).unwrap();
            let length = packet
                .iter()
                .position(|&x| x == 0)
                .unwrap_or_else(|| packet.len());
            let packet = &packet[..length];
            assert_eq!(packet, &DEFAULT_MESSAGE[..length]);
            socket.send_to(packet, addr).unwrap();
        }
    });
});

fn criterion_benchmark(c: &mut Criterion) {
    Lazy::force(&FEEDBACK_LOOP);
    Lazy::force(&SERVER_INIT);
    // Sleep to give the servers some time to warm-up.
    std::thread::sleep(std::time::Duration::from_millis(500));
    let socket = UdpSocket::bind(BENCH_LOOP_ADDR).unwrap();
    let mut packet = [0; MESSAGE_SIZE];

    let mut group = c.benchmark_group("throughput");
    for message in PACKETS {
        group.sample_size(NUMBER_OF_PACKETS);
        group.sampling_mode(criterion::SamplingMode::Flat);
        group.throughput(criterion::Throughput::Bytes(message.len() as u64));
        group.bench_with_input(
            BenchmarkId::new("direct", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    socket.send_to(message, FEEDBACK_LOOP_ADDR).unwrap();
                    socket.recv_from(&mut packet).unwrap();
                })
            },
        );
        group.bench_with_input(
            BenchmarkId::new("quilkin", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    socket.send_to(message, QUILKIN_ADDR).unwrap();
                    socket.recv_from(&mut packet).unwrap();
                })
            },
        );
    }
    group.finish();
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
<commit_msg>Benchmark comparing read and write throughput (#479)<commit_after>use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::{atomic, mpsc, Arc};
use std::thread::sleep;
use std::time;

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use once_cell::sync::Lazy;

use quilkin::config::Admin;

const MESSAGE_SIZE: usize = 0xffff;
const DEFAULT_MESSAGE: [u8; 0xffff] = [0xff; 0xffff];
const BENCH_LOOP_ADDR: &str = "127.0.0.1:8002";
const FEEDBACK_LOOP_ADDR: &str = "127.0.0.1:8001";
const QUILKIN_ADDR: &str = "127.0.0.1:8000";
const NUMBER_OF_PACKETS: usize = 10_000;

const PACKETS: &[&[u8]] = &[
    // Half IPv4 MTU.
    &[0xffu8; 254],
    // IPv4 MTU.
    &[0xffu8; 508],
    // Ethernet MTU.
    &[0xffu8; 1500],
];

/// Run and instance of quilkin that sends and received data
/// from the given address.
fn run_quilkin(port: u16, endpoint: SocketAddr) {
    std::thread::spawn(move || {
        let runtime = tokio::runtime::Runtime::new().unwrap();
        let config = quilkin::config::Builder::empty()
            .with_port(port)
            .with_admin(Admin {
                address: "[::]:0".parse().unwrap(),
            })
            .with_static(
                vec![],
                vec![quilkin::endpoint::Endpoint::new(endpoint.into())],
            )
            .build();
        let server = quilkin::Builder::from(std::sync::Arc::new(config))
            .validate()
            .unwrap()
            .build();

        runtime.block_on(async move {
            let (_shutdown_tx, shutdown_rx) = tokio::sync::watch::channel::<()>(());
            server.run(shutdown_rx).await.unwrap();
        });
    });
}

static THROUGHPUT_SERVER_INIT: Lazy<()> = Lazy::new(|| {
    run_quilkin(8000, FEEDBACK_LOOP_ADDR.parse().unwrap());
});

static FEEDBACK_LOOP: Lazy<()> = Lazy::new(|| {
    std::thread::spawn(|| {
        let socket = UdpSocket::bind(FEEDBACK_LOOP_ADDR).unwrap();

        loop {
            let mut packet = [0; MESSAGE_SIZE];
            let (_, addr) = socket.recv_from(&mut packet).unwrap();
            let length = packet
                .iter()
                .position(|&x| x == 0)
                .unwrap_or_else(|| packet.len());
            let packet = &packet[..length];
            assert_eq!(packet, &DEFAULT_MESSAGE[..length]);
            socket.send_to(packet, addr).unwrap();
        }
    });
});

fn throughput_benchmark(c: &mut Criterion) {
    Lazy::force(&FEEDBACK_LOOP);
    Lazy::force(&THROUGHPUT_SERVER_INIT);
    // Sleep to give the servers some time to warm-up.
    std::thread::sleep(std::time::Duration::from_millis(500));
    let socket = UdpSocket::bind(BENCH_LOOP_ADDR).unwrap();
    let mut packet = [0; MESSAGE_SIZE];

    let mut group = c.benchmark_group("throughput");
    for message in PACKETS {
        group.sample_size(NUMBER_OF_PACKETS);
        group.sampling_mode(criterion::SamplingMode::Flat);
        group.throughput(criterion::Throughput::Bytes(message.len() as u64));
        group.bench_with_input(
            BenchmarkId::new("direct", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    socket.send_to(message, FEEDBACK_LOOP_ADDR).unwrap();
                    socket.recv_from(&mut packet).unwrap();
                })
            },
        );
        group.bench_with_input(
            BenchmarkId::new("quilkin", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    socket.send_to(message, QUILKIN_ADDR).unwrap();
                    socket.recv_from(&mut packet).unwrap();
                })
            },
        );
    }
    group.finish();
}

const WRITE_LOOP_ADDR: &str = "127.0.0.1:8003";
const READ_LOOP_ADDR: &str = "127.0.0.1:8004";

const READ_QUILKIN_PORT: u16 = 9001;
static READ_SERVER_INIT: Lazy<()> = Lazy::new(|| {
    run_quilkin(READ_QUILKIN_PORT, READ_LOOP_ADDR.parse().unwrap());
});

const WRITE_QUILKIN_PORT: u16 = 9002;
static WRITE_SERVER_INIT: Lazy<()> = Lazy::new(|| {
    run_quilkin(WRITE_QUILKIN_PORT, WRITE_LOOP_ADDR.parse().unwrap());
});

/// Binds a socket to `addr`, and waits for an initial packet to be sent to it to establish
/// a connection. After which any `Vec<u8>` sent to the returned channel will result in that
/// data being send via that connection - thereby skipping the proxy `read` operation.
fn write_feedback(addr: SocketAddr) -> mpsc::Sender<Vec<u8>> {
    let (write_tx, write_rx) = mpsc::channel::<Vec<u8>>();
    std::thread::spawn(move || {
        let socket = UdpSocket::bind(addr).unwrap();
        let mut packet = [0; MESSAGE_SIZE];
        let (_, source) = socket.recv_from(&mut packet).unwrap();
        while let Ok(packet) = write_rx.recv() {
            socket.send_to(packet.as_slice(), source).unwrap();
        }
    });
    write_tx
}

fn readwrite_benchmark(c: &mut Criterion) {
    Lazy::force(&READ_SERVER_INIT);

    // start a feedback server for read operations, that sends a response through a channel,
    // thereby skipping a proxy connection on the return.
    let (read_tx, read_rx) = mpsc::channel::<Vec<u8>>();
    std::thread::spawn(move || {
        let socket = UdpSocket::bind(READ_LOOP_ADDR).unwrap();
        let mut packet = [0; MESSAGE_SIZE];
        loop {
            let (length, _) = socket.recv_from(&mut packet).unwrap();
            let packet = &packet[..length];
            assert_eq!(packet, &DEFAULT_MESSAGE[..length]);

            if read_tx.send(packet.to_vec()).is_err() {
                return;
            }
        }
    });

    // start a feedback server for a direct write benchmark.
    let direct_write_addr = (Ipv4Addr::LOCALHOST, 9004).into();
    let direct_write_tx = write_feedback(direct_write_addr);

    // start a feedback server for a quilkin write benchmark.
    let quilkin_write_addr = (Ipv4Addr::LOCALHOST, WRITE_QUILKIN_PORT);
    let quilkin_write_tx = write_feedback(WRITE_LOOP_ADDR.parse().unwrap());
    Lazy::force(&WRITE_SERVER_INIT);

    // Sleep to give the servers some time to warm-up.
    std::thread::sleep(std::time::Duration::from_millis(500));

    let socket = UdpSocket::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();

    // prime the direct write connection
    socket.send_to(PACKETS[0], direct_write_addr).unwrap();

    // we need to send packets at least once a minute, otherwise the endpoint session expires.
    // So setting up a ping packet for the write test.
    // TODO(markmandel): If we ever make session timeout configurable, we can remove this.
    let ping_socket = socket.try_clone().unwrap();
    let stop = Arc::new(atomic::AtomicBool::default());
    let ping_stop = stop.clone();
    std::thread::spawn(move || {
        while !ping_stop.load(atomic::Ordering::Relaxed) {
            ping_socket.send_to(PACKETS[0], quilkin_write_addr).unwrap();
            sleep(time::Duration::from_secs(30));
        }
    });

    let mut group = c.benchmark_group("readwrite");

    for message in PACKETS {
        group.sample_size(NUMBER_OF_PACKETS);
        group.sampling_mode(criterion::SamplingMode::Flat);
        group.throughput(criterion::Throughput::Bytes(message.len() as u64));

        // direct read
        group.bench_with_input(
            BenchmarkId::new("direct-read", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    socket.send_to(message, READ_LOOP_ADDR).unwrap();
                    read_rx.recv().unwrap();
                })
            },
        );
        // quilkin read
        let addr = (Ipv4Addr::LOCALHOST, READ_QUILKIN_PORT);
        group.bench_with_input(
            BenchmarkId::new("quilkin-read", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    socket.send_to(message, addr).unwrap();
                    read_rx.recv().unwrap();
                })
            },
        );

        // direct write
        let mut packet = [0; MESSAGE_SIZE];
        group.bench_with_input(
            BenchmarkId::new("direct-write", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    direct_write_tx.send(message.to_vec()).unwrap();
                    socket.recv(&mut packet).unwrap();
                })
            },
        );

        // quilkin write
        let mut packet = [0; MESSAGE_SIZE];
        group.bench_with_input(
            BenchmarkId::new("quilkin-write", format!("{} bytes", message.len())),
            &message,
            |b, message| {
                b.iter(|| {
                    quilkin_write_tx.send(message.to_vec()).unwrap();
                    socket.recv(&mut packet).unwrap();
                })
            },
        );
    }

    stop.store(true, atomic::Ordering::Relaxed);
}

criterion_group!(benches, readwrite_benchmark, throughput_benchmark);
criterion_main!(benches);
<|endoftext|>


<commit_before>#[crate_id = "date#1.0"];
#[crate_type = "lib"];
#[license = "MIT"];
#[desc = "Library for simple date management" ];
#[comment = "Example of library: date management"];
//! Date management
//!
//! Use "constructor", string manipulation
//! Tested with rust-0.10-pre
//!
//! @author Eliovir <http://github.com/~eliovir>
//!
//! @license MIT license <http://www.opensource.org/licenses/mit-license.php>
//!
//! @since 2013-10-24
use std::from_str::FromStr;
use std::fmt;

/**
 * Simple struct to handle date.
 */
pub struct Date {
	day: int,
	month: int,
	year: int
}

impl Date {
	/**
	 * Add days to the current day. Use negative to remove day.
	 */
	pub fn addDays(&mut self, days: int) {
		let mut day = self.day;
		let mut month = self.month;
		let mut year = self.year;
		day = day + days;
		if days > 0 {
			while day > Date::monthLength(year, month) {
				day = day - Date::monthLength(year, month);
				month = month + 1;
				if month > 12 {
					year = year + 1;
					month = 1;
				}
			}
		}
		if day == 0 {
			month = month - 1;
			if month < 1 {
				month = 12;
				year = year - 1;
			}
			day = Date::monthLength(year, month);
		}
		if days < 0 {
			while day < 1 {
				month = month - 1;
				if month < 1 {
					year = year - 1;
					month = 12;
				}
				day = day + Date::monthLength(year, month);
			}
		}
		self.day = day;
		self.month = month;
		self.year = year;
	}

	/**
	 * Check if defined date is valid.
	 */
	pub fn isValid(&self) -> bool {
		if self.month < 1 || self.month > 12 {
			false
		} else if self.day < 1 || self.day > Date::monthLength(self.year, self.month) {
			false
		} else {
			true
		}
	}

	/*
	 * Static methods
	 */

	/**
	 * Static method to know if the year is a leap year.
	 */
	pub fn isLeap(year: int) -> bool {
		(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
	}

	/**
	 * Static method to get the number of days in the month.
	 */
	pub fn monthLength(year: int, month: int) -> int {
		match  month {
			1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
			2 => if Date::isLeap(year) { 29 } else { 28 },
			4 | 6 | 9 | 11 => 30,
			_ => fail!("Wrong month")
		}
	}

	/**
	 * "Constructor".
	 */
	pub fn new(year: int, month: int, day: int) -> Date {
		Date{day: day, month: month, year: year}
	}

	/**
	 * "Constructor" using string like "2013-10-24".
	 */
	pub fn newFromString(string: &str) -> Date {
		if string.len() < 10 {
			fail!("Wrong format!");
		}
		let year = FromStr::from_str(string.slice_chars(0, 4)).unwrap();
		let month = FromStr::from_str(string.slice_chars(5, 7)).unwrap();
		let day = FromStr::from_str(string.slice_chars(8, 10)).unwrap();
		Date{day: day, month: month, year: year}
	}
}

/**
 * Operator overloading
 *
 * @see http://maniagnosis.crsr.net/2013/04/operator-overloading-in-rust.html
 */
impl fmt::Show for Date {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f.buf, "{:4d}-{:2d}-{:2d}", self.year, self.month, self.day)
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn addDays() {
		let mut date = ::Date::new(2013, 10, 24);
		let orig = date.to_str();
		let days = 2;
		date.addDays(days);
		let expected="2013-10-26";
		let found=date.to_str();
		assert!(expected==found, format!("Adding {:d} days to {} should return {}, not {}", days, orig, expected, found));
	}
	#[test]
	fn isLeap() {
		assert!(!::Date::isLeap(1900), "1900 is not a leap year");
		assert!(!::Date::isLeap(1901), "1901 is not a leap year");
		assert!(::Date::isLeap(2000), "2000 is leap year");
		assert!(::Date::isLeap(2004), "2004 is leap year");
	}
	#[test]
	fn isValid() {
		let mut date = ::Date::new(2013, 10, 24);
		assert!(date.isValid(), "2013-10-24 is a valid date");
		date = ::Date::new(2013, 02, 29);
		assert!(!date.isValid(), "2013-02-29 isn't a valid date");
		date = ::Date::new(2012, 02, 29);
		assert!(date.isValid(), "2012-02-29 isn't a valid date");
	}
	#[test]
	fn to_str() {
		let date = ::Date::new(2013, 10, 24);
		let expected = "2013-10-24";
		let found = date.to_str();
		assert!(expected == found, format!("{}!={}", expected, found));
	}
	/*
	 * Static methods
	 */
	#[test]
	fn monthLength() {
		assert!(::Date::monthLength(2000, 2) == 29, "February 2000 has 29 days");
		assert!(::Date::monthLength(2001, 2) == 28, "February 2001 has 28 days");
		assert!(::Date::monthLength(2013, 2) == 28, "February 2013 has 28 days");
		assert!(::Date::monthLength(2013, 9) == 30, "September 2013 has 30 days");
		assert!(::Date::monthLength(2013, 10) == 31, "October 2013 has 31 days");
	}
	#[test]
	fn new() {
		let date = ::Date::new(2013, 10, 24);
		let expected = "2013-10-24";
		let found = date.to_str();
		assert!(expected == found, format!("{}!={}", expected, found));
	}
	#[test]
	fn newFromString() {
		let date = ::Date::newFromString("2013-10-24 23:24:34");
		let expected = "2013-10-24";
		let found = date.to_str();
		assert!(expected == found, format!("{}!={}", expected, found));
	}
}

<commit_msg>date.rs : add getDayOfYear()<commit_after>#[crate_id = "date#1.0"];
#[crate_type = "lib"];
#[license = "MIT"];
#[desc = "Library for simple date management" ];
#[comment = "Example of library: date management"];
//! Date management
//!
//! Use "constructor", string manipulation
//! Tested with rust-0.10-pre
//!
//! @author Eliovir <http://github.com/~eliovir>
//!
//! @license MIT license <http://www.opensource.org/licenses/mit-license.php>
//!
//! @since 2013-10-24
//!
//! @todo : getDayOfWeek(), getWeek(), comparisons
use std::from_str::FromStr;
use std::fmt;

/**
 * Simple struct to handle date.
 */
pub struct Date {
	day: int,
	month: int,
	year: int
}

impl Date {
	/**
	 * Add days to the current day. Use negative to remove day.
	 */
	pub fn addDays(&mut self, days: int) {
		let mut day = self.day;
		let mut month = self.month;
		let mut year = self.year;
		day = day + days;
		if days > 0 {
			while day > Date::monthLength(year, month) {
				day = day - Date::monthLength(year, month);
				month = month + 1;
				if month > 12 {
					year = year + 1;
					month = 1;
				}
			}
		}
		if day == 0 {
			month = month - 1;
			if month < 1 {
				month = 12;
				year = year - 1;
			}
			day = Date::monthLength(year, month);
		}
		if days < 0 {
			while day < 1 {
				month = month - 1;
				if month < 1 {
					year = year - 1;
					month = 12;
				}
				day = day + Date::monthLength(year, month);
			}
		}
		self.day = day;
		self.month = month;
		self.year = year;
	}

	/**
	 * Get day of year.
	 */
	pub fn getDayOfYear(&self) -> int {
		let mut doy = self.day;
		for month in range(1, self.month) {
			doy += Date::monthLength(self.year, month);
		}
		doy
	}

	/**
	 * Check if defined date is valid.
	 */
	pub fn isValid(&self) -> bool {
		if self.month < 1 || self.month > 12 {
			false
		} else if self.day < 1 || self.day > Date::monthLength(self.year, self.month) {
			false
		} else {
			true
		}
	}

	/*
	 * Static methods
	 */

	/**
	 * Static method to know if the year is a leap year.
	 */
	pub fn isLeap(year: int) -> bool {
		(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
	}

	/**
	 * Static method to get the number of days in the month.
	 */
	pub fn monthLength(year: int, month: int) -> int {
		match  month {
			1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
			2 => if Date::isLeap(year) { 29 } else { 28 },
			4 | 6 | 9 | 11 => 30,
			_ => fail!("Wrong month")
		}
	}

	/**
	 * "Constructor".
	 */
	pub fn new(year: int, month: int, day: int) -> Date {
		Date{day: day, month: month, year: year}
	}

	/**
	 * "Constructor" using string like "2013-10-24".
	 */
	pub fn newFromString(string: &str) -> Date {
		if string.len() < 10 {
			fail!("Wrong format!");
		}
		let year = FromStr::from_str(string.slice_chars(0, 4)).unwrap();
		let month = FromStr::from_str(string.slice_chars(5, 7)).unwrap();
		let day = FromStr::from_str(string.slice_chars(8, 10)).unwrap();
		Date{day: day, month: month, year: year}
	}
}

/**
 * Operator overloading
 *
 * @see http://maniagnosis.crsr.net/2013/04/operator-overloading-in-rust.html
 */
impl fmt::Show for Date {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f.buf, "{:4d}-{:2d}-{:2d}", self.year, self.month, self.day)
	}
}

#[cfg(test)]
mod tests {
	#[test]
	fn addDays() {
		let mut date = ::Date::new(2013, 10, 24);
		let orig = date.to_str();
		let days = 2;
		date.addDays(days);
		let expected = "2013-10-26";
		let found = date.to_str();
		assert!(expected==found, format!("Adding {:d} days to {} should return {}, not {}", days, orig, expected, found));
	}
	#[test]
	fn getDayOfYear() {
		let date = ::Date::new(2014, 01, 01);
		let expected = 1;
		let found = date.getDayOfYear();
		assert!(expected==found, format!("{:?} must be day number {} of the year, not {}.", date, expected, found));
		let date = ::Date::new(2012, 12, 31);
		let expected = 366;
		let found = date.getDayOfYear();
		assert!(expected==found, format!("{:?} must be day number {} of the year, not {}.", date, expected, found));
	}
	#[test]
	fn isLeap() {
		assert!(!::Date::isLeap(1900), "1900 is not a leap year");
		assert!(!::Date::isLeap(1901), "1901 is not a leap year");
		assert!(::Date::isLeap(2000), "2000 is leap year");
		assert!(::Date::isLeap(2004), "2004 is leap year");
	}
	#[test]
	fn isValid() {
		let mut date = ::Date::new(2013, 10, 24);
		assert!(date.isValid(), "2013-10-24 is a valid date");
		date = ::Date::new(2013, 02, 29);
		assert!(!date.isValid(), "2013-02-29 isn't a valid date");
		date = ::Date::new(2012, 02, 29);
		assert!(date.isValid(), "2012-02-29 isn't a valid date");
	}
	#[test]
	fn to_str() {
		let date = ::Date::new(2013, 10, 24);
		let expected = "2013-10-24";
		let found = date.to_str();
		assert!(expected == found, format!("{}!={}", expected, found));
	}
	/*
	 * Static methods
	 */
	#[test]
	fn monthLength() {
		assert!(::Date::monthLength(2000, 2) == 29, "February 2000 has 29 days");
		assert!(::Date::monthLength(2001, 2) == 28, "February 2001 has 28 days");
		assert!(::Date::monthLength(2013, 2) == 28, "February 2013 has 28 days");
		assert!(::Date::monthLength(2013, 9) == 30, "September 2013 has 30 days");
		assert!(::Date::monthLength(2013, 10) == 31, "October 2013 has 31 days");
	}
	#[test]
	fn new() {
		let date = ::Date::new(2013, 10, 24);
		let expected = "2013-10-24";
		let found = date.to_str();
		assert!(expected == found, format!("{}!={}", expected, found));
	}
	#[test]
	fn newFromString() {
		let date = ::Date::newFromString("2013-10-24 23:24:34");
		let expected = "2013-10-24";
		let found = date.to_str();
		assert!(expected == found, format!("{}!={}", expected, found));
	}
}

<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use dirs;
use evcxr;

use colored::*;
use evcxr::{CommandContext, CompilationError, Error};
use rustyline::{error::ReadlineError, Editor};
use std::fs;
use std::io;
use std::sync::mpsc;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: CommandContext,
}

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new() -> Result<Repl, Error> {
        let (command_context, outputs) = CommandContext::new()?;
        send_output(outputs.stdout, io::stdout());
        send_output(outputs.stderr, io::stderr());
        let mut repl = Repl { command_context };
        repl.execute(":load_config");
        Ok(repl)
    }

    fn execute(&mut self, to_run: &str) {
        match self.command_context.execute(to_run) {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(errors);
            }
            Err(err) => eprintln!("{}", format!("{}", err).bright_red()),
        }
    }

    fn display_errors(&mut self, errors: Vec<CompilationError>) {
        for error in errors {
            if error.is_from_user_code() {
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        for _ in 1..span.start_column + PROMPT.len() {
                            print!(" ");
                        }
                        let mut carrots = String::new();
                        for _ in span.start_column..span.end_column {
                            carrots.push('^');
                        }
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this should't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

fn main() {
    evcxr::runtime_hook();
    println!("Welcome to evcxr. For help, type :help");
    let mut repl = match Repl::new() {
        Ok(c) => c,
        Err(error) => {
            eprintln!("{}", error);
            return;
        }
    };

    let mut editor = Editor::<()>::new();
    let mut opt_history_file = None;
    let config_dir = dirs::config_dir().map(|h| h.join("evcxr"));
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let readline = editor.readline(&PROMPT.yellow());
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line);
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
}
<commit_msg>Fix prompt color<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use dirs;
use evcxr;

use colored::*;
use evcxr::{CommandContext, CompilationError, Error};
use rustyline::{error::ReadlineError, Editor};
use std::fs;
use std::io;
use std::sync::mpsc;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: CommandContext,
}

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new() -> Result<Repl, Error> {
        let (command_context, outputs) = CommandContext::new()?;
        send_output(outputs.stdout, io::stdout());
        send_output(outputs.stderr, io::stderr());
        let mut repl = Repl { command_context };
        repl.execute(":load_config");
        Ok(repl)
    }

    fn execute(&mut self, to_run: &str) {
        match self.command_context.execute(to_run) {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(errors);
            }
            Err(err) => eprintln!("{}", format!("{}", err).bright_red()),
        }
    }

    fn display_errors(&mut self, errors: Vec<CompilationError>) {
        for error in errors {
            if error.is_from_user_code() {
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        for _ in 1..span.start_column + PROMPT.len() {
                            print!(" ");
                        }
                        let mut carrots = String::new();
                        for _ in span.start_column..span.end_column {
                            carrots.push('^');
                        }
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this should't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

fn main() {
    evcxr::runtime_hook();
    println!("Welcome to evcxr. For help, type :help");
    let mut repl = match Repl::new() {
        Ok(c) => c,
        Err(error) => {
            eprintln!("{}", error);
            return;
        }
    };

    let mut editor = Editor::<()>::new();
    let mut opt_history_file = None;
    let config_dir = dirs::config_dir().map(|h| h.join("evcxr"));
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = editor.readline(&prompt);
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line);
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
}
<|endoftext|>