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

/// 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, Closure)>,
    pub num_instructions_executed: usize,
}

#[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,
        }
    }
}

pub struct TearDownResult {
    pub return_value: Value,
    pub fuzzable_closures: Vec<(Id, Closure)>,
}

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![],
            num_instructions_executed: 0,
        }
    }

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

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

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

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

    pub fn set_up_module_closure_execution<U: UseProvider>(
        &mut self,
        use_provider: &U,
        closure: Closure,
    ) {
        assert_eq!(closure.captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff).");
        assert_eq!(closure.num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments).");
        self.set_up_closure_execution(use_provider, closure, vec![]);
    }
    pub fn tear_down_module_closure_execution(&mut self) -> TearDownResult {
        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: usize) {
        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);
            self.num_instructions_executed += 1;

            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();
                match self.heap.export_without_dropping(closure) {
                    Value::Closure(closure) => self.fuzzable_closures.push((id, closure)),
                    _ => panic!("Instruction RegisterFuzzableClosure executed, but stack top is not a 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>Don't crash the language server when you call a non-closure, but instead make the VM panic<commit_after>use super::{
    heap::{Heap, ObjectData, ObjectPointer},
    tracer::{TraceEntry, Tracer},
    use_provider::UseProvider,
    value::{Closure, Value},
};
use crate::{
    compiler::{hir::Id, lir::Instruction},
    input::Input,
};
use itertools::Itertools;
use log;
use std::{collections::HashMap, mem};

/// 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, Closure)>,
    pub num_instructions_executed: usize,
}

#[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,
        }
    }
}

pub struct TearDownResult {
    pub return_value: Value,
    pub fuzzable_closures: Vec<(Id, Closure)>,
}

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![],
            num_instructions_executed: 0,
        }
    }

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

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

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

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

    pub fn set_up_module_closure_execution<U: UseProvider>(
        &mut self,
        use_provider: &U,
        closure: Closure,
    ) {
        assert_eq!(closure.captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff).");
        assert_eq!(closure.num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments).");
        self.set_up_closure_execution(use_provider, closure, vec![]);
    }
    pub fn tear_down_module_closure_execution(&mut self) -> TearDownResult {
        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: usize) {
        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);
            self.num_instructions_executed += 1;

            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);
                    }
                    _ => {
                        self.panic("you can only call closures and builtins".to_string());
                    }
                };
            }
            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();
                match self.heap.export_without_dropping(closure) {
                    Value::Closure(closure) => self.fuzzable_closures.push((id, closure)),
                    _ => panic!("Instruction RegisterFuzzableClosure executed, but stack top is not a 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>use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use super::*;
use super::len::*;
use super::internal::*;

pub fn find<PAR_ITER, FIND_OP>(pi: PAR_ITER, find_op: FIND_OP) -> Option<PAR_ITER::Item>
    where PAR_ITER: ParallelIterator,
          FIND_OP: Fn(&PAR_ITER::Item) -> bool + Sync,
{
    let finder = Find {
        find_op: find_op,
        found: AtomicBool::new(false),
        result: Mutex::new(None),
    };
    pi.drive_unindexed(&finder);
    finder.result.into_inner().unwrap()
}

struct Find<ITEM: Send, FIND_OP: Fn(&ITEM) -> bool + Sync> {
    find_op: FIND_OP,
    found: AtomicBool,
    result: Mutex<Option<ITEM>>,
}

impl<'f, ITEM, FIND_OP> Consumer<ITEM> for &'f Find<ITEM, FIND_OP>
    where ITEM: Send, FIND_OP: Fn(&ITEM) -> bool + Sync
{
    type Folder = Self;
    type Reducer = NoopReducer;
    type Result = ();

    fn cost(&mut self, cost: f64) -> f64 {
        cost * FUNC_ADJUSTMENT
    }

    fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
        (self, self, NoopReducer)
    }

    fn into_folder(self) -> Self::Folder {
        self
    }

    fn full(&self) -> bool {
        self.found.load(Ordering::Relaxed)
    }
}

impl<'f, ITEM, FIND_OP> UnindexedConsumer<ITEM> for &'f Find<ITEM, FIND_OP>
    where ITEM: Send, FIND_OP: Fn(&ITEM) -> bool + Sync
{
    fn split_off(&self) -> Self {
        self
    }

    fn to_reducer(&self) -> Self::Reducer {
        NoopReducer
    }
}

impl<'f, ITEM, FIND_OP> Folder<ITEM> for &'f Find<ITEM, FIND_OP>
    where ITEM: Send, FIND_OP: Fn(&ITEM) -> bool + Sync
{
    type Result = ();

    fn consume(self, item: ITEM) -> Self {
        if (self.find_op)(&item) {
            self.found.store(true, Ordering::Relaxed);
            if let Ok(mut guard) = self.result.try_lock() {
                if guard.is_none() {
                    *guard = Some(item);
                }
            }
        }
        self
    }

    fn complete(self) -> Self::Result {
    }

    fn full(&self) -> bool {
        self.found.load(Ordering::Relaxed)
    }
}
<commit_msg>Revert to the reduce-based find<commit_after>use std::sync::atomic::{AtomicBool, Ordering};
use super::*;
use super::len::*;
use super::internal::*;

pub fn find<PAR_ITER, FIND_OP>(pi: PAR_ITER, find_op: FIND_OP) -> Option<PAR_ITER::Item>
    where PAR_ITER: ParallelIterator,
          FIND_OP: Fn(&PAR_ITER::Item) -> bool + Sync,
{
    let found = AtomicBool::new(false);
    let consumer = FindConsumer::new(&find_op, &found);
    pi.drive_unindexed(consumer)
}

struct FindConsumer<'f, FIND_OP: 'f> {
    find_op: &'f FIND_OP,
    found: &'f AtomicBool,
}

impl<'f, FIND_OP> FindConsumer<'f, FIND_OP> {
    fn new(find_op: &'f FIND_OP, found: &'f AtomicBool) -> Self {
        FindConsumer {
            find_op: find_op,
            found: found,
        }
    }
}

impl<'f, ITEM, FIND_OP: 'f> Consumer<ITEM> for FindConsumer<'f, FIND_OP>
    where ITEM: Send, FIND_OP: Fn(&ITEM) -> bool + Sync,
{
    type Folder = FindFolder<'f, ITEM, FIND_OP>;
    type Reducer = FindReducer;
    type Result = Option<ITEM>;

    fn cost(&mut self, cost: f64) -> f64 {
        // This isn't quite right, as we will do more than O(n) reductions, but whatever.
        cost * FUNC_ADJUSTMENT
    }

    fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
        (self.split_off(), self, FindReducer)
    }

    fn into_folder(self) -> Self::Folder {
        FindFolder {
            find_op: self.find_op,
            found: self.found,
            item: None,
        }
    }

    fn full(&self) -> bool {
        self.found.load(Ordering::Relaxed)
    }
}

impl<'f, ITEM, FIND_OP: 'f> UnindexedConsumer<ITEM> for FindConsumer<'f, FIND_OP>
    where ITEM: Send, FIND_OP: Fn(&ITEM) -> bool + Sync,
{
    fn split_off(&self) -> Self {
        FindConsumer::new(self.find_op, self.found)
    }

    fn to_reducer(&self) -> Self::Reducer {
        FindReducer
    }
}

struct FindFolder<'f, ITEM, FIND_OP: 'f> {
    find_op: &'f FIND_OP,
    found: &'f AtomicBool,
    item: Option<ITEM>,
}

impl<'f, ITEM, FIND_OP> Folder<ITEM> for FindFolder<'f, ITEM, FIND_OP>
    where FIND_OP: Fn(&ITEM) -> bool + 'f
{
    type Result = Option<ITEM>;

    fn consume(mut self, item: ITEM) -> Self {
        if (self.find_op)(&item) {
            self.found.store(true, Ordering::Relaxed);
            self.item = Some(item);
        }
        self
    }

    fn complete(self) -> Self::Result {
        self.item
    }

    fn full(&self) -> bool {
        self.found.load(Ordering::Relaxed)
    }
}

struct FindReducer;

impl<ITEM> Reducer<Option<ITEM>> for FindReducer {
    fn reduce(self, left: Option<ITEM>, right: Option<ITEM>) -> Option<ITEM> {
        left.or(right)
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (vars) NANOS numstr
//! Parsing a duration from a string.
//!
//! Use the [`from_str`] function to parse a [`Duration`] from a string.

use std::time::Duration;

use crate::display::Quotable;

/// Parse a duration from a string.
///
/// The string may contain only a number, like "123" or "4.5", or it
/// may contain a number with a unit specifier, like "123s" meaning
/// one hundred twenty three seconds or "4.5d" meaning four and a half
/// days. If no unit is specified, the unit is assumed to be seconds.
///
/// This function uses [`Duration::saturating_mul`] to compute the
/// number of seconds, so it does not overflow. If overflow would have
/// occurred, [`Duration::MAX`] is returned instead.
///
/// # Errors
///
/// This function returns an error if the input string is empty, the
/// input is not a valid number, or the unit specifier is invalid or
/// unknown.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// use uucore::parse_time::from_str;
/// assert_eq!(from_str("123"), Ok(Duration::from_secs(123)));
/// assert_eq!(from_str("2d"), Ok(Duration::from_secs(60 * 60 * 24 * 2)));
/// ```
pub fn from_str(string: &str) -> Result<Duration, String> {
    let len = string.len();
    if len == 0 {
        return Err("empty string".to_owned());
    }
    let slice = &string[..len - 1];
    let (numstr, times) = match string.chars().next_back().unwrap() {
        's' | 'S' => (slice, 1),
        'm' | 'M' => (slice, 60),
        'h' | 'H' => (slice, 60 * 60),
        'd' | 'D' => (slice, 60 * 60 * 24),
        val if !val.is_alphabetic() => (string, 1),
        _ => {
            if string == "inf" || string == "infinity" {
                ("inf", 1)
            } else {
                return Err(format!("invalid time interval {}", string.quote()));
            }
        }
    };
    let num = numstr
        .parse::<f64>()
        .map_err(|e| format!("invalid time interval {}: {}", string.quote(), e))?;

    if num < 0. {
        return Err(format!("invalid time interval {}", string.quote()));
    }

    const NANOS_PER_SEC: u32 = 1_000_000_000;
    let whole_secs = num.trunc();
    let nanos = (num.fract() * (NANOS_PER_SEC as f64)).trunc();
    let duration = Duration::new(whole_secs as u64, nanos as u32);
    Ok(duration.saturating_mul(times))
}

#[cfg(test)]
mod tests {

    use crate::parse_time::from_str;
    use std::time::Duration;

    #[test]
    fn test_no_units() {
        assert_eq!(from_str("123"), Ok(Duration::from_secs(123)));
    }

    #[test]
    fn test_units() {
        assert_eq!(from_str("2d"), Ok(Duration::from_secs(60 * 60 * 24 * 2)));
    }

    #[test]
    fn test_saturating_mul() {
        assert_eq!(from_str("9223372036854775808d"), Ok(Duration::MAX));
    }

    #[test]
    fn test_error_empty() {
        assert!(from_str("").is_err());
    }

    #[test]
    fn test_error_invalid_unit() {
        assert!(from_str("123X").is_err());
    }

    #[test]
    fn test_error_invalid_magnitude() {
        assert!(from_str("12abc3s").is_err());
    }

    #[test]
    fn test_negative() {
        assert!(from_str("-1").is_err());
    }
}
<commit_msg>uucore: no uppercase suffixes in parse_time<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (vars) NANOS numstr
//! Parsing a duration from a string.
//!
//! Use the [`from_str`] function to parse a [`Duration`] from a string.

use std::time::Duration;

use crate::display::Quotable;

/// Parse a duration from a string.
///
/// The string may contain only a number, like "123" or "4.5", or it
/// may contain a number with a unit specifier, like "123s" meaning
/// one hundred twenty three seconds or "4.5d" meaning four and a half
/// days. If no unit is specified, the unit is assumed to be seconds.
///
/// The only allowed suffixes are
///
/// * "s" for seconds,
/// * "m" for minutes,
/// * "h" for hours,
/// * "d" for days.
///
/// This function uses [`Duration::saturating_mul`] to compute the
/// number of seconds, so it does not overflow. If overflow would have
/// occurred, [`Duration::MAX`] is returned instead.
///
/// # Errors
///
/// This function returns an error if the input string is empty, the
/// input is not a valid number, or the unit specifier is invalid or
/// unknown.
///
/// # Examples
///
/// ```rust
/// use std::time::Duration;
/// use uucore::parse_time::from_str;
/// assert_eq!(from_str("123"), Ok(Duration::from_secs(123)));
/// assert_eq!(from_str("2d"), Ok(Duration::from_secs(60 * 60 * 24 * 2)));
/// ```
pub fn from_str(string: &str) -> Result<Duration, String> {
    let len = string.len();
    if len == 0 {
        return Err("empty string".to_owned());
    }
    let slice = &string[..len - 1];
    let (numstr, times) = match string.chars().next_back().unwrap() {
        's' => (slice, 1),
        'm' => (slice, 60),
        'h' => (slice, 60 * 60),
        'd' => (slice, 60 * 60 * 24),
        val if !val.is_alphabetic() => (string, 1),
        _ => {
            if string == "inf" || string == "infinity" {
                ("inf", 1)
            } else {
                return Err(format!("invalid time interval {}", string.quote()));
            }
        }
    };
    let num = numstr
        .parse::<f64>()
        .map_err(|e| format!("invalid time interval {}: {}", string.quote(), e))?;

    if num < 0. {
        return Err(format!("invalid time interval {}", string.quote()));
    }

    const NANOS_PER_SEC: u32 = 1_000_000_000;
    let whole_secs = num.trunc();
    let nanos = (num.fract() * (NANOS_PER_SEC as f64)).trunc();
    let duration = Duration::new(whole_secs as u64, nanos as u32);
    Ok(duration.saturating_mul(times))
}

#[cfg(test)]
mod tests {

    use crate::parse_time::from_str;
    use std::time::Duration;

    #[test]
    fn test_no_units() {
        assert_eq!(from_str("123"), Ok(Duration::from_secs(123)));
    }

    #[test]
    fn test_units() {
        assert_eq!(from_str("2d"), Ok(Duration::from_secs(60 * 60 * 24 * 2)));
    }

    #[test]
    fn test_saturating_mul() {
        assert_eq!(from_str("9223372036854775808d"), Ok(Duration::MAX));
    }

    #[test]
    fn test_error_empty() {
        assert!(from_str("").is_err());
    }

    #[test]
    fn test_error_invalid_unit() {
        assert!(from_str("123X").is_err());
    }

    #[test]
    fn test_error_invalid_magnitude() {
        assert!(from_str("12abc3s").is_err());
    }

    #[test]
    fn test_negative() {
        assert!(from_str("-1").is_err());
    }

    /// Test that capital letters are not allowed in suffixes.
    #[test]
    fn test_no_capital_letters() {
        assert!(from_str("1S").is_err());
        assert!(from_str("1M").is_err());
        assert!(from_str("1H").is_err());
        assert!(from_str("1D").is_err());
    }
}
<|endoftext|>


<commit_before>use super::super::services::image_service;
use super::super::rocket_contrib::JSON;
use super::super::models::{Image, NewImage, Tag};
use std::error::Error;
use rocket::request::Form;
use rocket::response::status;
use rocket::data::Data;
use std::io::prelude::*;
use std::fs::File;
use rocket::response::Stream;

#[get("/images")]
fn get_images() -> Result<JSON<Vec<Image>>, Box<Error>> {
    let result = try!(image_service::get_all());
    Ok(JSON(result))
}

#[get("/images/<id>")]
fn get_image(id: i32) -> Option<JSON<Image>> {
    match image_service::find(id) {
        Ok(t) => Some(JSON(t)),
        Err(_) => None,
    }
}

#[get("/images/<id>/tags")]
fn get_tags_of_image(id: i32) -> Option<JSON<Vec<Tag>>> {
    match image_service::get_tags_of_image(id) {
        Ok(t) => Some(JSON(t)),
        Err(_) => None,
    }
}

#[post("/images", data="<new_image_data>")]
fn new(new_image_data: Form<NewImage>) -> Option<status::Created<JSON<Image>>> {
    let new_image = new_image_data.get();
    match image_service::create(&new_image) {
        Ok(result) => Some(status::Created(format!("/images/{}", result.id), Some(JSON(result)))),
        Err(_) => None,
    }
}

#[post("/images/<id>/file", data="<data>")]
fn new_image_file(id: i32, data: Data) -> Result<status::Created<JSON<Image>>, Box<Error>> {
    let mut stream = data.open();
    let mut buff = vec![];
    try!(stream.read_to_end(&mut buff));
    info!("got new image ({} bytes)", buff.len());
    let result = try!(image_service::create_image_file(id, buff.as_slice()));
    Ok(status::Created(format!("/images/file/{}", result.id), Some(JSON(result))))
}

#[post("/images/<id>/sidecar/new", data="<data>")]
fn new_sidecar_file(id: i32, data: Data) -> Result<status::Created<JSON<Image>>, Box<Error>> {
    let mut stream = data.open();
    let mut buff = vec![];
    try!(stream.read_to_end(&mut buff));
    let result = try!(image_service::create_sidecar_file(id, buff.as_slice()));
    Ok(status::Created(format!("/images/sidecar/{}", result.id), Some(JSON(result))))
}

#[get("/images/<id>/sidecar")]
fn get_sidecar_file(id: i32) -> Option<Stream<File>> {
    match image_service::find_sidecar_file(id) {
        Ok(sf) => Some(Stream::from(sf)),
        Err(_) => None,
    }
}

#[get("/images/<id>/file")]
fn get_image_file(id: i32) -> Option<Stream<File>> {
    match image_service::find_image_file(id) {
        Ok(sf) => Some(Stream::from(sf)),
        Err(_) => None,
    }
}

#[put("/images/update?<image>")]
fn update(image: Image) -> Option<JSON<Image>> {
    match image_service::update(&image) {
        Ok(t) => Some(JSON(t)),
        Err(_) => None,
    }
}
<commit_msg>Fix new sidecar route<commit_after>use super::super::services::image_service;
use super::super::rocket_contrib::JSON;
use super::super::models::{Image, NewImage, Tag};
use std::error::Error;
use rocket::request::Form;
use rocket::response::status;
use rocket::data::Data;
use std::io::prelude::*;
use std::fs::File;
use rocket::response::Stream;

#[get("/images")]
fn get_images() -> Result<JSON<Vec<Image>>, Box<Error>> {
    let result = try!(image_service::get_all());
    Ok(JSON(result))
}

#[get("/images/<id>")]
fn get_image(id: i32) -> Option<JSON<Image>> {
    match image_service::find(id) {
        Ok(t) => Some(JSON(t)),
        Err(_) => None,
    }
}

#[get("/images/<id>/tags")]
fn get_tags_of_image(id: i32) -> Option<JSON<Vec<Tag>>> {
    match image_service::get_tags_of_image(id) {
        Ok(t) => Some(JSON(t)),
        Err(_) => None,
    }
}

#[post("/images", data="<new_image_data>")]
fn new(new_image_data: Form<NewImage>) -> Option<status::Created<JSON<Image>>> {
    let new_image = new_image_data.get();
    match image_service::create(&new_image) {
        Ok(result) => Some(status::Created(format!("/images/{}", result.id), Some(JSON(result)))),
        Err(_) => None,
    }
}

#[post("/images/<id>/file", data="<data>")]
fn new_image_file(id: i32, data: Data) -> Result<status::Created<JSON<Image>>, Box<Error>> {
    let mut stream = data.open();
    let mut buff = vec![];
    try!(stream.read_to_end(&mut buff));
    info!("got new image ({} bytes)", buff.len());
    let result = try!(image_service::create_image_file(id, buff.as_slice()));
    Ok(status::Created(format!("/images/file/{}", result.id), Some(JSON(result))))
}

#[post("/images/<id>/sidecar", data="<data>")]
fn new_sidecar_file(id: i32, data: Data) -> Result<status::Created<JSON<Image>>, Box<Error>> {
    let mut stream = data.open();
    let mut buff = vec![];
    try!(stream.read_to_end(&mut buff));
    let result = try!(image_service::create_sidecar_file(id, buff.as_slice()));
    Ok(status::Created(format!("/images/sidecar/{}", result.id), Some(JSON(result))))
}

#[get("/images/<id>/sidecar")]
fn get_sidecar_file(id: i32) -> Option<Stream<File>> {
    match image_service::find_sidecar_file(id) {
        Ok(sf) => Some(Stream::from(sf)),
        Err(_) => None,
    }
}

#[get("/images/<id>/file")]
fn get_image_file(id: i32) -> Option<Stream<File>> {
    match image_service::find_image_file(id) {
        Ok(sf) => Some(Stream::from(sf)),
        Err(_) => None,
    }
}

#[put("/images/update?<image>")]
fn update(image: Image) -> Option<JSON<Image>> {
    match image_service::update(&image) {
        Ok(t) => Some(JSON(t)),
        Err(_) => None,
    }
}
<|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.

/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X
/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256
/// ends up being far too low for our multithreaded scheduler testing, depending
/// on the number of cores available.
///
/// This fixes issue #7772.
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[allow(non_camel_case_types)]
pub unsafe fn raise_fd_limit() {
    use libc;
    use std::cmp;
    use std::io;
    use std::mem::size_of_val;
    use std::ptr::null_mut;

    type rlim_t = libc::uint64_t;

    #[repr(C)]
    struct rlimit {
        rlim_cur: rlim_t,
        rlim_max: rlim_t
    }
    extern {
        // name probably doesn't need to be mut, but the C function doesn't
        // specify const
        fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
                  oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
                  newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
        fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
        fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int;
    }
    static CTL_KERN: libc::c_int = 1;
    static KERN_MAXFILESPERPROC: libc::c_int = 29;
    static RLIMIT_NOFILE: libc::c_int = 8;

    // The strategy here is to fetch the current resource limits, read the
    // kern.maxfilesperproc sysctl value, and bump the soft resource limit for
    // maxfiles up to the sysctl value.

    // Fetch the kern.maxfilesperproc value
    let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
    let mut maxfiles: libc::c_int = 0;
    let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
    if sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size,
              null_mut(), 0) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling sysctl: {}", err);
    }

    // Fetch the current resource limits
    let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
    if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling getrlimit: {}", err);
    }

    // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard
    // limit
    rlim.rlim_cur = cmp::min(maxfiles as rlim_t, rlim.rlim_max);

    // Set our newly-increased resource limit
    if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling setrlimit: {}", err);
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub unsafe fn raise_fd_limit() {}
<commit_msg>Auto merge of #29752 - tamird:fix-compiletest-stage1, r=alexcrichton<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.

/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X
/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256
/// ends up being far too low for our multithreaded scheduler testing, depending
/// on the number of cores available.
///
/// This fixes issue #7772.
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[allow(non_camel_case_types)]
pub unsafe fn raise_fd_limit() {
    use libc;
    use std::cmp;
    use std::io;
    use std::mem::size_of_val;
    use std::ptr::null_mut;

    static CTL_KERN: libc::c_int = 1;
    static KERN_MAXFILESPERPROC: libc::c_int = 29;

    // The strategy here is to fetch the current resource limits, read the
    // kern.maxfilesperproc sysctl value, and bump the soft resource limit for
    // maxfiles up to the sysctl value.

    // Fetch the kern.maxfilesperproc value
    let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
    let mut maxfiles: libc::c_int = 0;
    let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
    if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size,
              null_mut(), 0) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling sysctl: {}", err);
    }

    // Fetch the current resource limits
    let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
    if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling getrlimit: {}", err);
    }

    // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard
    // limit
    rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max);

    // Set our newly-increased resource limit
    if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling setrlimit: {}", err);
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub unsafe fn raise_fd_limit() {}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate curl;
extern crate rs_es;
extern crate serde;
extern crate serde_json;
extern crate regex;

use super::objects::DocType;
use chrono;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use serde_json::value::Value;

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    client: rs_es::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/index)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap();
        let port = cap.name("port").unwrap().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber { client: rs_es::Client::new(&host, port) }
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        if !self.is_existing_index(&index_name).unwrap() {
            info!("creating index {}", index_name);
            self.create_index(&index_name.to_string()).map(|_| index_name)
        } else {
            Ok(index_name)
        }
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        // TODO return an error
        debug!("creating index");
        // Note: for the moment I don't see an easy way to do this with rs_es
        let analysis = include_str!("../../../json/settings.json");
        curl::http::handle()
            .put(self.client.full_url(&name), analysis)
            .exec()
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| {
                if res.get_code() == 200 {
                    Ok(())
                } else {
                    Err(format!("cannot create index: {}",
                                ::std::str::from_utf8(res.get_body()).unwrap()))
                }
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {

        debug!("get last index: {base_index}/_aliases",
               base_index = get_main_index(doc_type, dataset));
        curl::http::handle()
            .get(self.client.full_url(&format!("{base_index}/_aliases",
                                               base_index = get_main_index(doc_type, dataset))))
            .exec()
            .map_err(|e| e.to_string())
            .and_then(|res| {
                match res.get_code() {
                    200 => {
                        let body = ::std::str::from_utf8(res.get_body()).unwrap();
                        let value: Value = ::serde_json::from_str(body).unwrap();
                        Ok(value.as_object()
                                .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                                .unwrap_or_else(|| {
                                    info!("no previous index to delete for type {} and dataset {}",
                                          doc_type,
                                          dataset);
                                    vec![]
                                }))
                    }
                    404 => {
                        info!("impossible to find alias {}, no last index to remove",
                              get_main_index(doc_type, dataset));
                        Ok(vec![])
                    }
                    _ => Err(format!("invalid elasticsearch response: {:?}", res)),
                }
            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String)
                         -> Result<(), String> {
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));
        let main_index = get_main_index(doc_type, dataset);
        try!(self.alias(&main_index, &vec![index.clone()], &last_indexes));
        try!(self.alias("munin", &vec![main_index.to_string()], &vec![]));
        for i in last_indexes {
            try!(self.delete_index(&i))
        }
        Ok(())
    }

    fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        curl::http::handle()
            .get(self.client.full_url(&name))
            .exec()
            .map_err(|e| e.to_string())
            .map(|res| res.get_code() == 200)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        debug!("adding aliases for {}", alias);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations = AliasOperations {
            actions: add_operations.chain(remove_operations).collect(),
        };
        let json = serde_json::to_string(&operations).unwrap();
        let e = curl::http::handle()
                    .post(self.client.full_url("_aliases"), &json)
                    .exec();
        e.map_err(|e| e.to_string())
         .and_then(|res| {
             info!("es response: {}",
                   ::std::str::from_utf8(res.get_body()).unwrap());
             if res.get_code() == 200 {
                 Ok(())
             } else {
                 error!("es response: {}", res);
                 Err("failed".to_string())
             }
         })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.client
                      .delete_index(&index)
                      .map(|res| res.acknowledged)
                      .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            mut iter: I)
                            -> Result<u32, rs_es::error::EsError>
        where T: serde::Serialize + DocType,
              I: Iterator<Item = T>
    {
        use self::rs_es::operations::bulk::Action;
        let mut chunk = Vec::new();
        let mut nb = 0;
        loop {
            chunk.clear();
            let addr = match iter.next() {
                Some(a) => a,
                None => break,
            };
            chunk.push(Action::index(addr));

            nb += 1;
            for addr in iter.by_ref().take(1000) {
                chunk.push(Action::index(addr));
                nb += 1;
            }
            try!(self.client
                     .bulk(&chunk)
                     .with_index(&index)
                     .with_doc_type(T::doc_type())
                     .send());
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, doc_type: &str, dataset: &str, iter: I) -> Result<u32, String>
        where T: serde::Serialize + DocType,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = self.make_index(doc_type, dataset).unwrap();
        let nb_elements = self.bulk_index(&index, iter).unwrap();
        self.publish_index(doc_type, dataset, index).unwrap();
        Ok(nb_elements)
    }
}
<commit_msg>small correction<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate curl;
extern crate rs_es;
extern crate serde;
extern crate serde_json;
extern crate regex;

use super::objects::DocType;
use chrono;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use serde_json::value::Value;

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    client: rs_es::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/index)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap();
        let port = cap.name("port").unwrap().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber { client: rs_es::Client::new(&host, port) }
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        if !self.is_existing_index(&index_name).unwrap() {
            info!("creating index {}", index_name);
            self.create_index(&index_name.to_string()).map(|_| index_name)
        } else {
            Ok(index_name)
        }
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: for the moment I don't see an easy way to do this with rs_es
        let analysis = include_str!("../../../json/settings.json");
        curl::http::handle()
            .put(self.client.full_url(&name), analysis)
            .exec()
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| {
                if res.get_code() == 200 {
                    Ok(())
                } else {
                    Err(format!("cannot create index: {}",
                                ::std::str::from_utf8(res.get_body()).unwrap()))
                }
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        debug!("get last index: {base_index}/_aliases",
               base_index = get_main_index(doc_type, dataset));
        curl::http::handle()
            .get(self.client.full_url(&format!("{base_index}/_aliases",
                                               base_index = get_main_index(doc_type, dataset))))
            .exec()
            .map_err(|e| e.to_string())
            .and_then(|res| {
                match res.get_code() {
                    200 => {
                        let body = ::std::str::from_utf8(res.get_body()).unwrap();
                        let value: Value = ::serde_json::from_str(body).unwrap();
                        Ok(value.as_object()
                                .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                                .unwrap_or_else(|| {
                                    info!("no previous index to delete for type {} and dataset {}",
                                          doc_type,
                                          dataset);
                                    vec![]
                                }))
                    }
                    404 => {
                        info!("impossible to find alias {}, no last index to remove",
                              get_main_index(doc_type, dataset));
                        Ok(vec![])
                    }
                    _ => Err(format!("invalid elasticsearch response: {:?}", res)),
                }
            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String)
                         -> Result<(), String> {
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));
        let main_index = get_main_index(doc_type, dataset);
        try!(self.alias(&main_index, &vec![index.clone()], &last_indexes));
        try!(self.alias("munin", &vec![main_index.to_string()], &vec![]));
        for i in last_indexes {
            try!(self.delete_index(&i))
        }
        Ok(())
    }

    fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        curl::http::handle()
            .get(self.client.full_url(&name))
            .exec()
            .map_err(|e| e.to_string())
            .map(|res| res.get_code() == 200)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        debug!("adding aliases for {}", alias);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations = AliasOperations {
            actions: add_operations.chain(remove_operations).collect(),
        };
        let json = serde_json::to_string(&operations).unwrap();
        let e = curl::http::handle()
                    .post(self.client.full_url("_aliases"), &json)
                    .exec();
        e.map_err(|e| e.to_string())
         .and_then(|res| {
             info!("es response: {}",
                   ::std::str::from_utf8(res.get_body()).unwrap());
             if res.get_code() == 200 {
                 Ok(())
             } else {
                 error!("es response: {}", res);
                 Err("failed".to_string())
             }
         })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.client
                      .delete_index(&index)
                      .map(|res| res.acknowledged)
                      .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            mut iter: I)
                            -> Result<u32, rs_es::error::EsError>
        where T: serde::Serialize + DocType,
              I: Iterator<Item = T>
    {
        use self::rs_es::operations::bulk::Action;
        let mut chunk = Vec::new();
        let mut nb = 0;
        loop {
            chunk.clear();
            let addr = match iter.next() {
                Some(a) => a,
                None => break,
            };
            chunk.push(Action::index(addr));

            nb += 1;
            for addr in iter.by_ref().take(1000) {
                chunk.push(Action::index(addr));
                nb += 1;
            }
            try!(self.client
                     .bulk(&chunk)
                     .with_index(&index)
                     .with_doc_type(T::doc_type())
                     .send());
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, doc_type: &str, dataset: &str, iter: I) -> Result<u32, String>
        where T: serde::Serialize + DocType,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = self.make_index(doc_type, dataset).unwrap();
        let nb_elements = self.bulk_index(&index, iter).unwrap();
        self.publish_index(doc_type, dataset, index).unwrap();
        Ok(nb_elements)
    }

}
<|endoftext|>


<commit_before>extern crate conduit_middleware;
extern crate diesel;
extern crate serde_json;

use serde_json::Value;

use self::diesel::prelude::*;
use conduit::{Handler, Method};

use builders::{CrateBuilder, PublishBuilder, VersionBuilder};
use schema::versions;
use views::EncodableVersion;
use {app, new_user, req, RequestHelper, TestApp};

#[derive(Deserialize)]
struct VersionList {
    versions: Vec<EncodableVersion>,
}
#[derive(Deserialize)]
struct VersionResponse {
    version: EncodableVersion,
}

#[test]
fn index() {
    let (_b, app, middle) = app();
    let mut req = req(Method::Get, "/api/v1/versions");
    let mut response = ok_resp!(middle.call(&mut req));
    let json: VersionList = ::json(&mut response);
    assert_eq!(json.versions.len(), 0);

    let (v1, v2) = {
        let conn = app.diesel_database.get().unwrap();
        let u = new_user("foo").create_or_update(&conn).unwrap();
        CrateBuilder::new("foo_vers_index", u.id)
            .version(VersionBuilder::new("2.0.0").license(Some("MIT")))
            .version(VersionBuilder::new("2.0.1").license(Some("MIT/Apache-2.0")))
            .expect_build(&conn);
        let ids = versions::table
            .select(versions::id)
            .load::<i32>(&*conn)
            .unwrap();
        (ids[0], ids[1])
    };
    req.with_query(&format!("ids[]={}&ids[]={}", v1, v2));
    let mut response = ok_resp!(middle.call(&mut req));
    let json: VersionList = ::json(&mut response);
    assert_eq!(json.versions.len(), 2);

    for v in &json.versions {
        match v.num.as_ref() {
            "2.0.0" => assert_eq!(v.license, Some(String::from("MIT"))),
            "2.0.1" => assert_eq!(v.license, Some(String::from("MIT/Apache-2.0"))),
            _ => panic!("unexpected version"),
        }
    }
}

#[test]
fn show() {
    let (_b, app, middle) = app();
    let mut req = req(Method::Get, "/api/v1/versions");
    let v = {
        let conn = app.diesel_database.get().unwrap();
        let user = new_user("foo").create_or_update(&conn).unwrap();
        let krate = CrateBuilder::new("foo_vers_show", user.id).expect_build(&conn);
        VersionBuilder::new("2.0.0")
            .size(1234)
            .expect_build(krate.id, &conn)
    };
    req.with_path(&format!("/api/v1/versions/{}", v.id));
    let mut response = ok_resp!(middle.call(&mut req));
    let json: VersionResponse = ::json(&mut response);
    assert_eq!(json.version.id, v.id);
    assert_eq!(json.version.crate_size, Some(1234));
}

#[test]
fn authors() {
    let (_b, app, middle) = app();
    let mut req = req(Method::Get, "/api/v1/crates/foo_authors/1.0.0/authors");
    {
        let conn = app.diesel_database.get().unwrap();
        let u = new_user("foo").create_or_update(&conn).unwrap();
        CrateBuilder::new("foo_authors", u.id)
            .version("1.0.0")
            .expect_build(&conn);
    }
    let mut response = ok_resp!(middle.call(&mut req));
    let mut data = Vec::new();
    response.body.write_body(&mut data).unwrap();
    let s = ::std::str::from_utf8(&data).unwrap();
    let json: Value = serde_json::from_str(s).unwrap();
    let json = json.as_object().unwrap();
    assert!(json.contains_key("users"));
}

#[test]
fn record_rerendered_readme_time() {
    let (_b, app, _middle) = app();
    let version = {
        let conn = app.diesel_database.get().unwrap();
        let u = new_user("foo").create_or_update(&conn).unwrap();
        let c = CrateBuilder::new("foo_authors", u.id).expect_build(&conn);
        VersionBuilder::new("1.0.0").expect_build(c.id, &conn)
    };
    {
        let conn = app.diesel_database.get().unwrap();
        version.record_readme_rendering(&conn).unwrap();
        version.record_readme_rendering(&conn).unwrap();
    }
}

#[test]
fn version_size() {
    let (_, _, user) = TestApp::with_proxy().with_user();
    let crate_to_publish = PublishBuilder::new("foo_version_size").version("1.0.0");
    user.publish(crate_to_publish).good();

    // Add a file to version 2 so that it's a different size than version 1
    let files = [("foo_version_size-2.0.0/big", &[b'a'; 1] as &[_])];
    let crate_to_publish = PublishBuilder::new("foo_version_size")
        .version("2.0.0")
        .files(&files);
    user.publish(crate_to_publish).good();

    let crate_json = user.show_crate("foo_version_size");

    let version1 = crate_json
        .versions
        .iter()
        .find(|v| v.num == "1.0.0")
        .expect("Could not find v1.0.0");
    assert_eq!(version1.crate_size, Some(35));

    let version2 = crate_json
        .versions
        .iter()
        .find(|v| v.num == "2.0.0")
        .expect("Could not find v2.0.0");
    assert_eq!(version2.crate_size, Some(91));
}
<commit_msg>Convert version tests to TestApp<commit_after>use serde_json::Value;

use diesel::prelude::*;

use builders::{CrateBuilder, PublishBuilder, VersionBuilder};
use schema::versions;
use views::EncodableVersion;
use {RequestHelper, TestApp};

#[derive(Deserialize)]
struct VersionList {
    versions: Vec<EncodableVersion>,
}
#[derive(Deserialize)]
struct VersionResponse {
    version: EncodableVersion,
}

#[test]
fn index() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();
    let url = "/api/v1/versions";

    let json: VersionList = anon.get(url).good();
    assert_eq!(json.versions.len(), 0);

    let (v1, v2) = app.db(|conn| {
        CrateBuilder::new("foo_vers_index", user.id)
            .version(VersionBuilder::new("2.0.0").license(Some("MIT")))
            .version(VersionBuilder::new("2.0.1").license(Some("MIT/Apache-2.0")))
            .expect_build(conn);
        let ids = versions::table
            .select(versions::id)
            .load::<i32>(conn)
            .unwrap();
        (ids[0], ids[1])
    });

    let query = format!("ids[]={}&ids[]={}", v1, v2);
    let json: VersionList = anon.get_with_query(url, &query).good();
    assert_eq!(json.versions.len(), 2);

    for v in &json.versions {
        match v.num.as_ref() {
            "2.0.0" => assert_eq!(v.license, Some(String::from("MIT"))),
            "2.0.1" => assert_eq!(v.license, Some(String::from("MIT/Apache-2.0"))),
            _ => panic!("unexpected version"),
        }
    }
}

#[test]
fn show() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    let v = app.db(|conn| {
        let krate = CrateBuilder::new("foo_vers_show", user.id).expect_build(conn);
        VersionBuilder::new("2.0.0").size(1234).expect_build(krate.id, conn)
    });

    let url = format!("/api/v1/versions/{}", v.id);
    let json: VersionResponse = anon.get(&url).good();
    assert_eq!(json.version.id, v.id);
    assert_eq!(json.version.crate_size, Some(1234));
}

#[test]
fn authors() {
    let (app, anon, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        CrateBuilder::new("foo_authors", user.id)
            .version("1.0.0")
            .expect_build(conn);
    });

    let json: Value = anon.get("/api/v1/crates/foo_authors/1.0.0/authors").good();
    let json = json.as_object().unwrap();
    assert!(json.contains_key("users"));
}

#[test]
fn record_rerendered_readme_time() {
    let (app, _, user) = TestApp::init().with_user();
    let user = user.as_model();

    app.db(|conn| {
        let c = CrateBuilder::new("foo_authors", user.id).expect_build(conn);
        let version = VersionBuilder::new("1.0.0").expect_build(c.id, conn);

        version.record_readme_rendering(conn).unwrap();
        version.record_readme_rendering(conn).unwrap();
    });
}

#[test]
fn version_size() {
    let (_, _, user) = TestApp::with_proxy().with_user();
    let crate_to_publish = PublishBuilder::new("foo_version_size").version("1.0.0");
    user.publish(crate_to_publish).good();

    // Add a file to version 2 so that it's a different size than version 1
    let files = [("foo_version_size-2.0.0/big", &[b'a'; 1] as &[_])];
    let crate_to_publish = PublishBuilder::new("foo_version_size")
        .version("2.0.0")
        .files(&files);
    user.publish(crate_to_publish).good();

    let crate_json = user.show_crate("foo_version_size");

    let version1 = crate_json
        .versions
        .iter()
        .find(|v| v.num == "1.0.0")
        .expect("Could not find v1.0.0");
    assert_eq!(version1.crate_size, Some(35));

    let version2 = crate_json
        .versions
        .iter()
        .find(|v| v.num == "2.0.0")
        .expect("Could not find v2.0.0");
    assert_eq!(version2.crate_size, Some(91));
}
<|endoftext|>


<commit_before>// rustyVM - Java VM written in pure Rust
// Copyright (c) 2013 Alexander Gessler
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

use std::hashmap::{HashMap};

use objectbroker::{ObjectBroker};

// Global thread state and management. All threads maintain some global state
// in the central Broker messaging task. Global state includes scheduling info,
// join()-waitlists as well as whether threads are daemons or not.

// Notably, this design makes access to threads scale badly as it is inherently
// single-threaded. On the other side, it makes thread maintenance very easy
// and safe. It is reasonable to assume that most code will not too often interact
// directly with java.lang.Thread.

// References:
// http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
// http://docs.oracle.com/javase/7/docs/api/java/lang/ThreadGroup.html

// Remote messages responded to by the threadmanager (messages are received
// and forwarded by broker)
pub enum RemoteThreadOpMessage {

	THREAD_JOIN,
	THREAD_NOTIFY_TERMINATION,
	THREAD_SET_PRIORITY(int),
	THREAD_SET_NAME(~str)
}

pub struct GlobThreadInfo {
	tid : uint,

	// id of the thread group this thread pertains to
	gid : uint,

	// given name of the thread, used for debugging
	name : ~str,

	// java thread priority
	priority : int,

	//
	daemon : bool,
}

pub struct GlobThreadGroupInfo {
	gid : uint,
	parent_gid : Option<uint>,

	// further group members (i.e. daemon, max-prio) ignored for now
}

pub struct ThreadManager {

	priv groups : HashMap<uint, GlobThreadGroupInfo>,
	priv threads : HashMap<uint, GlobThreadInfo>,

	// number of threads in `threads` with daemon=false,
	// when this counter reaches 0, the VM shuts down
	priv alive_nondaemon_count : uint,

	priv state : ThreadManagerState,
}

pub enum ThreadManagerState {
	// initial state when no thread has been added yet
	TMS_NoThreadSeenYet,

	// running state - at least one non-daemon thread
	TMS_Running,

	// all non-daemon threads have died. Transition from
	// here to Running is possible by adding a new thread
	// that is not a daemon.
	TMS_AllNonDaemonsDead,
}

impl ThreadManager {

	// ----------------------------------------------
	pub fn new() -> ThreadManager {
		// always add the default thread group "0"
		let mut groups : HashMap<uint, GlobThreadGroupInfo> = HashMap::new();
		groups.insert(0, GlobThreadGroupInfo {
			gid : 0,
			parent_gid : None
		});

		ThreadManager{
			groups : groups,
			threads : HashMap::new(),

			alive_nondaemon_count : 0,
			state : TMS_NoThreadSeenYet,
		}
	}

	// ----------------------------------------------
	pub fn get_state(&self) -> ThreadManagerState {
		self.state
	}

	// ----------------------------------------------
	// Register a thread with the ThreadManager
	pub fn add_thread(&mut self, tid : uint, gid : uint) {
		self.threads.insert(tid, GlobThreadInfo {
			tid : tid,
			gid : gid,
			name : ~"",
			priority : 0,
			daemon : false,
		});

		self.state = TMS_Running;
	}

	// ----------------------------------------------
	// Unregister a thread from the ThreadManager
	pub fn remove_thread(&mut self, tid : uint) {
		let t = self.threads.pop(&tid).unwrap();
		if t.daemon {
			self.alive_nondaemon_count -= 1;
		}
		self.state = if self.alive_nondaemon_count == 0 { TMS_AllNonDaemonsDead } else { TMS_Running };
	}

	// ----------------------------------------------
	pub fn process_message(&mut self, src_tid : uint, dest_tid : uint,
		op : RemoteThreadOpMessage)  {

		match op {
			THREAD_JOIN => (),
			THREAD_NOTIFY_TERMINATION => fail!("THREAD_NOTIFY_TERMINATION unexpected"),
			THREAD_SET_PRIORITY(prio) => (),
			THREAD_SET_NAME(name) => (),
		}
	}
}

<commit_msg>ThreadManager: actually increment nondaemon count when adding thread<commit_after>// rustyVM - Java VM written in pure Rust
// Copyright (c) 2013 Alexander Gessler
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

use std::hashmap::{HashMap};

use objectbroker::{ObjectBroker};

// Global thread state and management. All threads maintain some global state
// in the central Broker messaging task. Global state includes scheduling info,
// join()-waitlists as well as whether threads are daemons or not.

// Notably, this design makes access to threads scale badly as it is inherently
// single-threaded. On the other side, it makes thread maintenance very easy
// and safe. It is reasonable to assume that most code will not too often interact
// directly with java.lang.Thread.

// References:
// http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
// http://docs.oracle.com/javase/7/docs/api/java/lang/ThreadGroup.html

// Remote messages responded to by the threadmanager (messages are received
// and forwarded by broker)
pub enum RemoteThreadOpMessage {

	THREAD_JOIN,
	THREAD_NOTIFY_TERMINATION,
	THREAD_SET_PRIORITY(int),
	THREAD_SET_NAME(~str)
}

pub struct GlobThreadInfo {
	tid : uint,

	// id of the thread group this thread pertains to
	gid : uint,

	// given name of the thread, used for debugging
	name : ~str,

	// java thread priority
	priority : int,

	//
	daemon : bool,
}

pub struct GlobThreadGroupInfo {
	gid : uint,
	parent_gid : Option<uint>,

	// further group members (i.e. daemon, max-prio) ignored for now
}

pub struct ThreadManager {

	priv groups : HashMap<uint, GlobThreadGroupInfo>,
	priv threads : HashMap<uint, GlobThreadInfo>,

	// number of threads in `threads` with daemon=false,
	// when this counter reaches 0, the VM shuts down
	priv alive_nondaemon_count : uint,

	priv state : ThreadManagerState,
}

#[deriving(Eq)]
pub enum ThreadManagerState {
	// initial state when no thread has been added yet
	TMS_NoThreadSeenYet,

	// running state - at least one non-daemon thread
	TMS_Running,

	// all non-daemon threads have died. Transition from
	// here to Running is possible by adding a new thread
	// that is not a daemon.
	TMS_AllNonDaemonsDead,
}

impl ThreadManager {

	// ----------------------------------------------
	pub fn new() -> ThreadManager {
		// always add the default thread group "0"
		let mut groups : HashMap<uint, GlobThreadGroupInfo> = HashMap::new();
		groups.insert(0, GlobThreadGroupInfo {
			gid : 0,
			parent_gid : None
		});

		ThreadManager{
			groups : groups,
			threads : HashMap::new(),

			alive_nondaemon_count : 0,
			state : TMS_NoThreadSeenYet,
		}
	}

	// ----------------------------------------------
	pub fn get_state(&self) -> ThreadManagerState {
		self.state
	}

	// ----------------------------------------------
	// Register a thread with the ThreadManager
	pub fn add_thread(&mut self, tid : uint, gid : uint) {
		self.threads.insert(tid, GlobThreadInfo {
			tid : tid,
			gid : gid,
			name : ~"",
			priority : 0,
			daemon : false,
		});

		self.alive_nondaemon_count += 1;
		self.state = TMS_Running;
	}

	// ----------------------------------------------
	// Unregister a thread from the ThreadManager
	pub fn remove_thread(&mut self, tid : uint) {
		let t = self.threads.pop(&tid).unwrap();
		if t.daemon {
			self.alive_nondaemon_count -= 1;
		}
		self.state = if self.alive_nondaemon_count == 0 { TMS_AllNonDaemonsDead } else { TMS_Running };
	}

	// ----------------------------------------------
	pub fn process_message(&mut self, src_tid : uint, dest_tid : uint,
		op : RemoteThreadOpMessage)  {

		match op {
			THREAD_JOIN => (),
			THREAD_NOTIFY_TERMINATION => fail!("THREAD_NOTIFY_TERMINATION unexpected"),
			THREAD_SET_PRIORITY(prio) => (),
			THREAD_SET_NAME(name) => (),
		}
	}
}

<|endoftext|>


<commit_before>use material::textures::ImageTexture;
use vec3::Vec3;

#[allow(dead_code)]
pub struct CubeMap {
    pub faces: Vec<ImageTexture>
}

impl CubeMap {
    #[allow(dead_code)]
    pub fn load(x: &str, x_neg: &str, y: &str, y_neg: &str, z: &str, z_neg: &str) -> CubeMap {
        CubeMap {
            faces: vec![
                ImageTexture::load(x),
                ImageTexture::load(x_neg),
                ImageTexture::load(y),
                ImageTexture::load(y_neg),
                ImageTexture::load(z),
                ImageTexture::load(z_neg)
            ]
        }
    }

    #[allow(dead_code)]
    pub fn color(&self, dir: Vec3) -> Vec3 {
        let x_mag = dir.x.abs();
        let y_mag = dir.y.abs();
        let z_mag = dir.z.abs();

        let mut face = -1;
        let mut s = 0.0;
        let mut t = 0.0;

        if x_mag >= y_mag && x_mag > z_mag {
            // +x -x direction
            face = if dir.x < 0.0 { 0 } else { 1 };
            s = dir.y / dir.x;
            t = dir.z / dir.x;
        } else if y_mag >= x_mag && y_mag > z_mag {
            // +y -y direction
            face = if dir.y < 0.0 { 2 } else { 3 };
            s = dir.x / dir.y;
            t = dir.z / dir.y;
        } else if z_mag >= y_mag && z_mag > x_mag {
            // +z -z direction
            face = if dir.z < 0.0 { 4 } else { 5 };
            s = dir.x / dir.z;
            t = dir.y / dir.z;
        }

        // [-1..1] -> [0..1]
        let seam_delta = 0.0001;
        s = (s * 0.5 + 0.5).max(seam_delta).min(1.0 - seam_delta);
        t = (t * 0.5 + 0.5).max(seam_delta).min(1.0 - seam_delta);

        self.faces[face].sample(s, t)
    }
}
<commit_msg>Make CubeMap face image coordinates human-sensible.<commit_after>use material::textures::ImageTexture;
use vec3::Vec3;

#[allow(dead_code)]
pub struct CubeMap {
    pub faces: Vec<ImageTexture>
}

impl CubeMap {
    /// For y-axis as up, load: left, right, down, up, front, back
    #[allow(dead_code)]
    pub fn load(x: &str, x_neg: &str, y: &str, y_neg: &str, z: &str, z_neg: &str) -> CubeMap {
        CubeMap {
            faces: vec![
                ImageTexture::load(x),
                ImageTexture::load(x_neg),
                ImageTexture::load(y),
                ImageTexture::load(y_neg),
                ImageTexture::load(z),
                ImageTexture::load(z_neg)
            ]
        }
    }

    #[allow(dead_code)]
    pub fn color(&self, dir: Vec3) -> Vec3 {
        let x_mag = dir.x.abs();
        let y_mag = dir.y.abs();
        let z_mag = dir.z.abs();

        let mut face = !0;
        let mut s = 0.0;
        let mut t = 0.0;

        if x_mag >= y_mag && x_mag >= z_mag {
            // +x -x direction
            face = if dir.x <= 0.0 { 0 } else { 1 };
            let scale = if dir.x < 0.0 { 1.0 } else { -1.0 };
            s = scale * dir.z / dir.x.abs();
            t = dir.y / dir.x.abs();
        } else if y_mag >= x_mag && y_mag >= z_mag {
            // +y -y direction
            face = if dir.y <= 0.0 { 2 } else { 3 };
            let scale = if dir.y < 0.0 { 1.0 } else { -1.0 };
            s = scale * dir.x / dir.y.abs();
            t = dir.z / dir.y.abs();
        } else if z_mag >= y_mag && z_mag >= x_mag {
            // +z -z direction
            face = if dir.z <= 0.0 { 4 } else { 5 };
            let scale = if dir.z < 0.0 { -1.0 } else { 1.0 };
            s = scale * dir.x / dir.z.abs();
            t = dir.y / dir.z.abs();
        }

        // [-1..1] -> [0..1]
        let seam_delta = 0.0001;
        s = (1.0 - (s * 0.5 + 0.5)).max(seam_delta).min(1.0 - seam_delta);
        t = (1.0 - (t * 0.5 + 0.5)).max(seam_delta).min(1.0 - seam_delta);

        if face == !0 {
            fail!("CubeMap could not get a cube face for direction {} {} {}", dir.x, dir.y, dir.z);
        }

        self.faces[face].sample(s, t)
    }
}
<|endoftext|>