<commit_before>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::str::FromStr;
use std::path::PathBuf;

// get from parent
use ERes;
use err;
use read_file;
use parse_split_quote_aware;
use schematic;

#[derive(Debug)]
pub struct SymbolLib {
    pub symbols:Vec<Symbol>,
}

// DEF name reference unused text_offset draw_pinnumber draw_pinname unit_count units_locked option_flag
#[derive(Debug)]
pub struct Symbol {
    pub name:String,
    pub reference:String,
    pub text_offset:f64,
    pub draw_pinnumber: bool,
    pub draw_pinname: bool,
    pub unit_count: i64,
    pub unit_locked: bool,
    pub is_power: bool,
    pub fields:Vec<Field>,
    pub draw:Vec<String>, // TODO parse draw
}
// F n “text” posx posy dimension orientation visibility hjustify vjustify/italic/bold “name”
// F0 "#PWR" 0 0 30 H I C CNN

#[derive(Debug)]
pub struct Field {
    pub i:i64,
    pub value:String,
    pub x:f64,
    pub y:f64,
    pub dimension:i64,
    pub orientation:schematic::Orientation,
    pub visible:bool,
    pub hjustify:schematic::Justify,
    pub vjustify:schematic::Justify,
    pub italic:bool,
    pub bold:bool,
    pub name:String,
}

impl SymbolLib {
    fn new() -> SymbolLib {
        SymbolLib {
            symbols:vec![]
        }
    }

    pub fn find<F>(&self, filter:F) -> Option<&Symbol>
        where F:Fn(&Symbol) -> bool
    {
        for symbol in &self.symbols {
            if filter(symbol) {
                return Some(symbol)
            }
        }
        None
    }
}

impl fmt::Display for SymbolLib {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema-LIBRARY Version 2.3"));
        try!(writeln!(f, "#encoding utf-8"));
        try!(writeln!(f, "#"));
        for i in &self.symbols {
            try!(write!(f, "{}", i))
        };
        writeln!(f, "#End Library")
    }
}

impl Symbol {
    fn new(name:String, reference:String) -> Symbol {
        Symbol {
            name:name,
            reference:reference,
            text_offset:0.0,
            draw_pinnumber:false,
            draw_pinname:false,
            unit_count:1,
            unit_locked:false,
            is_power:false,
            fields:vec![],
            draw:vec![],
        }
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "# {}", &&self.fields[1].value));
        try!(writeln!(f, "#"));
        try!(writeln!(f, "DEF {} {} 0 {} {} {} {} {} {}",
                     self.name, self.reference, self.text_offset,
                     if self.draw_pinnumber { "Y" } else { "N" },
                     if self.draw_pinname { "Y" } else { "N" },
                     self.unit_count,
                     if self.unit_locked { "L" } else { "F" },
                     if self.is_power { "P" } else { "N" },
                     ));
        for field in &self.fields {
            try!(writeln!(f, "{}", field))
        };
        try!(writeln!(f, "DRAW"));
        for draw in &self.draw {
            try!(writeln!(f, "{}", draw))
        };
        try!(writeln!(f, "ENDDRAW"));
        try!(writeln!(f, "ENDDEF"));
        writeln!(f, "#")
    }
}

impl Field {
    fn new() -> Field {
        Field {
            i:0,
            value:String::from(""),
            x:0.0,
            y:0.0,
            dimension:0,
            orientation:schematic::Orientation::Horizontal,
            visible:false,
            hjustify:schematic::Justify::Center,
            vjustify:schematic::Justify::Center,
            italic:false,
            bold:false,
            name:String::from(""),
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "F{} \"{}\" {} {} {} {} {} {} {}{}{}",
               self.i, self.value, self.x, self.y, self.dimension,
               self.orientation,
               if self.visible { "V" } else { "I" },
               self.hjustify, self.vjustify,
               if self.italic { "I" } else { "N" },
               if self.bold { "I" } else { "N" },
                    ));
        if self.i > 3 {
            try!(write!(f, " \"{}\"", self.name))
        };
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return err("end of file reached")
        }
        if $s.here() != $exp {
            return Err(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        let s =  (self.v[self.i]).clone();
        //println!("{}", s);
        s
    }

    fn next(&mut self) {
        self.i += 1;
    }

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}

fn assume_string(e:&'static str, s:&String) -> ERes<()> {
    if String::from(e) != *s {
        return Err(format!("expecting: {}, actually: {}", e, s))
    }
    return Ok(())
}

fn i64_from_string(p:&ParseState, s:&String) -> ERes<i64> {
    match i64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("int parse error in {}; line: {}", s, p.here()))
    }
}

fn f64_from_string(p:&ParseState, s:&String) -> ERes<f64> {
    match f64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("float parse error in {}; line: {}", s, p.here()))
    }
}

fn bool_from_string(s:&String, t:&'static str, f:&'static str) -> ERes<bool> {
    if &s[..] == t {
        return Ok(true)
    }
    if &s[..] == f {
        return Ok(false)
    }
    Err(format!("unknown boolean {}, expected {} or {}", s, t, f))
}

fn char_at(s:&String, p:usize) -> char {
    let v:Vec<char> = s.chars().collect();
    v[..][p]
}

fn parse_symbol(p:&mut ParseState) -> ERes<Symbol> {
    p.next(); // skip line like # name
    assume_line!(p,"#");
    let s = p.here();
    let v = &parse_split_quote_aware(&s);
    if v.len() != 10 {
        return Err(format!("unexpected elements in {}", s))
    }
    try!(assume_string("DEF", &v[0]));
    let mut s = Symbol::new(v[1].clone(), v[2].clone());
    s.text_offset = try!(f64_from_string(p, &v[4]));
    s.draw_pinnumber = try!(bool_from_string(&v[5], "Y", "N"));
    s.draw_pinname = try!(bool_from_string(&v[6], "Y", "N"));
    s.unit_count = try!(i64_from_string(p, &v[7]));
    s.unit_locked = try!(bool_from_string(&v[8], "L", "F"));
    s.is_power = try!(bool_from_string(&v[9], "P", "N"));
    // TODO fields
    // TODO draw
    p.next();
    loop {
        let s2 = p.here();
        if char_at(&s2, 0) == 'F' {
            let f = try!(parse_field(p, &s2));
            s.fields.push(f);
            p.next();
        } else {
            break;
        }
    }
    assume_line!(p, "DRAW");
    while !p.eof() {
        let s2 = p.here();
        if &s2 == "ENDDRAW" {
            p.next();
            break;
        }
        s.draw.push(s2.clone());
        p.next()
    }
    assume_line!(p,"ENDDEF");
    assume_line!(p,"#");
    Ok(s)
}

fn bool_from<T: PartialEq + fmt::Display>(i:T, t:T, f:T) -> ERes<bool> {
    if i == t {
        return Ok(true)
    }
    if i == f {
        return Ok(false)
    }
    Err(format!("unknown boolean {}, expected {} or {}", i, t, f))
}

// F0 "L" 0 50 40 H V C CNN
fn parse_field(p:&mut ParseState, line:&String) -> ERes<Field> {
    let mut f = Field::new();
    let v = &parse_split_quote_aware(&line);
    if v.len() != 9 && v.len() != 10 {
        return Err(format!("unexpected elements in {}", line))
    }
    f.i = try!(i64_from_string(p, &String::from(&v[0][1..])));
    let name = if v.len() == 10 {
        v[9].clone()
    } else {
        match f.i {
            0 => String::from("Reference"),
            1 => String::from("Value"),
            2 => String::from("Footprint"),
            3 => String::from("UserDocLink"),
            _ => return Err(format!("expecting name for componentfield > 3")),
        }
    };
    f.value = v[1].clone();
    f.x = try!(f64_from_string(p, &v[2]));
    f.y = try!(f64_from_string(p, &v[3]));
    f.dimension = try!(i64_from_string(p, &v[4]));
    f.orientation = try!(schematic::Orientation::new(char_at(&v[5], 0)));
    f.visible = try!(bool_from_string(&v[6], "V", "I"));
    f.hjustify = try!(schematic::Justify::new(char_at(&v[7], 0)));
    f.vjustify = try!(schematic::Justify::new(char_at(&v[8], 0)));
    f.italic = try!(bool_from(char_at(&v[8], 1), 'I', 'N'));
    f.bold = try!(bool_from(char_at(&v[8], 2), 'B', 'N'));
    f.name = name;
    Ok(f)
}

fn parse(s: &str) -> ERes<SymbolLib> {
    let mut lib = SymbolLib::new();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema-LIBRARY Version 2.3");
    assume_line!(p, "#encoding utf-8");
    assume_line!(p,"#");
    while !p.eof() {
        //println!("here: {}", &p.here());
        if &p.here() == "#End Library" {
            break;
        }
        let s = try!(parse_symbol(p));
        //println!("new symbol: {}", &s);
        lib.symbols.push(s)
    }
    Ok(lib)
}

pub fn parse_str(s:&str) -> ERes<SymbolLib> {
    parse(s)
}

pub fn parse_file(filename:&PathBuf) -> ERes<SymbolLib> {
    let name = filename.to_str().unwrap();
    let s = try!(read_file(name));
    parse(&s[..])
}
<commit_msg>make field clonable<commit_after>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::str::FromStr;
use std::path::PathBuf;

// get from parent
use ERes;
use err;
use read_file;
use parse_split_quote_aware;
use schematic;

#[derive(Debug)]
pub struct SymbolLib {
    pub symbols:Vec<Symbol>,
}

// DEF name reference unused text_offset draw_pinnumber draw_pinname unit_count units_locked option_flag
#[derive(Debug,Clone)]
pub struct Symbol {
    pub name:String,
    pub reference:String,
    pub text_offset:f64,
    pub draw_pinnumber: bool,
    pub draw_pinname: bool,
    pub unit_count: i64,
    pub unit_locked: bool,
    pub is_power: bool,
    pub fields:Vec<Field>,
    pub draw:Vec<String>, // TODO parse draw
}
// F n “text” posx posy dimension orientation visibility hjustify vjustify/italic/bold “name”
// F0 "#PWR" 0 0 30 H I C CNN

#[derive(Debug,Clone)]
pub struct Field {
    pub i:i64,
    pub value:String,
    pub x:f64,
    pub y:f64,
    pub dimension:i64,
    pub orientation:schematic::Orientation,
    pub visible:bool,
    pub hjustify:schematic::Justify,
    pub vjustify:schematic::Justify,
    pub italic:bool,
    pub bold:bool,
    pub name:String,
}

impl SymbolLib {
    fn new() -> SymbolLib {
        SymbolLib {
            symbols:vec![]
        }
    }

    pub fn find<F>(&self, filter:F) -> Option<&Symbol>
        where F:Fn(&Symbol) -> bool
    {
        for symbol in &self.symbols {
            if filter(symbol) {
                return Some(symbol)
            }
        }
        None
    }
}

impl fmt::Display for SymbolLib {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema-LIBRARY Version 2.3"));
        try!(writeln!(f, "#encoding utf-8"));
        try!(writeln!(f, "#"));
        for i in &self.symbols {
            try!(write!(f, "{}", i))
        };
        writeln!(f, "#End Library")
    }
}

impl Symbol {
    fn new(name:String, reference:String) -> Symbol {
        Symbol {
            name:name,
            reference:reference,
            text_offset:0.0,
            draw_pinnumber:false,
            draw_pinname:false,
            unit_count:1,
            unit_locked:false,
            is_power:false,
            fields:vec![],
            draw:vec![],
        }
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "# {}", &&self.fields[1].value));
        try!(writeln!(f, "#"));
        try!(writeln!(f, "DEF {} {} 0 {} {} {} {} {} {}",
                     self.name, self.reference, self.text_offset,
                     if self.draw_pinnumber { "Y" } else { "N" },
                     if self.draw_pinname { "Y" } else { "N" },
                     self.unit_count,
                     if self.unit_locked { "L" } else { "F" },
                     if self.is_power { "P" } else { "N" },
                     ));
        for field in &self.fields {
            try!(writeln!(f, "{}", field))
        };
        try!(writeln!(f, "DRAW"));
        for draw in &self.draw {
            try!(writeln!(f, "{}", draw))
        };
        try!(writeln!(f, "ENDDRAW"));
        try!(writeln!(f, "ENDDEF"));
        writeln!(f, "#")
    }
}

impl Field {
    fn new() -> Field {
        Field {
            i:0,
            value:String::from(""),
            x:0.0,
            y:0.0,
            dimension:0,
            orientation:schematic::Orientation::Horizontal,
            visible:false,
            hjustify:schematic::Justify::Center,
            vjustify:schematic::Justify::Center,
            italic:false,
            bold:false,
            name:String::from(""),
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "F{} \"{}\" {} {} {} {} {} {} {}{}{}",
               self.i, self.value, self.x, self.y, self.dimension,
               self.orientation,
               if self.visible { "V" } else { "I" },
               self.hjustify, self.vjustify,
               if self.italic { "I" } else { "N" },
               if self.bold { "I" } else { "N" },
                    ));
        if self.i > 3 {
            try!(write!(f, " \"{}\"", self.name))
        };
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return err("end of file reached")
        }
        if $s.here() != $exp {
            return Err(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        let s =  (self.v[self.i]).clone();
        //println!("{}", s);
        s
    }

    fn next(&mut self) {
        self.i += 1;
    }

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}

fn assume_string(e:&'static str, s:&String) -> ERes<()> {
    if String::from(e) != *s {
        return Err(format!("expecting: {}, actually: {}", e, s))
    }
    return Ok(())
}

fn i64_from_string(p:&ParseState, s:&String) -> ERes<i64> {
    match i64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("int parse error in {}; line: {}", s, p.here()))
    }
}

fn f64_from_string(p:&ParseState, s:&String) -> ERes<f64> {
    match f64::from_str(&s[..]) {
        Ok(i) => Ok(i),
        _ => Err(format!("float parse error in {}; line: {}", s, p.here()))
    }
}

fn bool_from_string(s:&String, t:&'static str, f:&'static str) -> ERes<bool> {
    if &s[..] == t {
        return Ok(true)
    }
    if &s[..] == f {
        return Ok(false)
    }
    Err(format!("unknown boolean {}, expected {} or {}", s, t, f))
}

fn char_at(s:&String, p:usize) -> char {
    let v:Vec<char> = s.chars().collect();
    v[..][p]
}

fn parse_symbol(p:&mut ParseState) -> ERes<Symbol> {
    p.next(); // skip line like # name
    assume_line!(p,"#");
    let s = p.here();
    let v = &parse_split_quote_aware(&s);
    if v.len() != 10 {
        return Err(format!("unexpected elements in {}", s))
    }
    try!(assume_string("DEF", &v[0]));
    let mut s = Symbol::new(v[1].clone(), v[2].clone());
    s.text_offset = try!(f64_from_string(p, &v[4]));
    s.draw_pinnumber = try!(bool_from_string(&v[5], "Y", "N"));
    s.draw_pinname = try!(bool_from_string(&v[6], "Y", "N"));
    s.unit_count = try!(i64_from_string(p, &v[7]));
    s.unit_locked = try!(bool_from_string(&v[8], "L", "F"));
    s.is_power = try!(bool_from_string(&v[9], "P", "N"));
    // TODO fields
    // TODO draw
    p.next();
    loop {
        let s2 = p.here();
        if char_at(&s2, 0) == 'F' {
            let f = try!(parse_field(p, &s2));
            s.fields.push(f);
            p.next();
        } else {
            break;
        }
    }
    assume_line!(p, "DRAW");
    while !p.eof() {
        let s2 = p.here();
        if &s2 == "ENDDRAW" {
            p.next();
            break;
        }
        s.draw.push(s2.clone());
        p.next()
    }
    assume_line!(p,"ENDDEF");
    assume_line!(p,"#");
    Ok(s)
}

fn bool_from<T: PartialEq + fmt::Display>(i:T, t:T, f:T) -> ERes<bool> {
    if i == t {
        return Ok(true)
    }
    if i == f {
        return Ok(false)
    }
    Err(format!("unknown boolean {}, expected {} or {}", i, t, f))
}

// F0 "L" 0 50 40 H V C CNN
fn parse_field(p:&mut ParseState, line:&String) -> ERes<Field> {
    let mut f = Field::new();
    let v = &parse_split_quote_aware(&line);
    if v.len() != 9 && v.len() != 10 {
        return Err(format!("unexpected elements in {}", line))
    }
    f.i = try!(i64_from_string(p, &String::from(&v[0][1..])));
    let name = if v.len() == 10 {
        v[9].clone()
    } else {
        match f.i {
            0 => String::from("Reference"),
            1 => String::from("Value"),
            2 => String::from("Footprint"),
            3 => String::from("UserDocLink"),
            _ => return Err(format!("expecting name for componentfield > 3")),
        }
    };
    f.value = v[1].clone();
    f.x = try!(f64_from_string(p, &v[2]));
    f.y = try!(f64_from_string(p, &v[3]));
    f.dimension = try!(i64_from_string(p, &v[4]));
    f.orientation = try!(schematic::Orientation::new(char_at(&v[5], 0)));
    f.visible = try!(bool_from_string(&v[6], "V", "I"));
    f.hjustify = try!(schematic::Justify::new(char_at(&v[7], 0)));
    f.vjustify = try!(schematic::Justify::new(char_at(&v[8], 0)));
    f.italic = try!(bool_from(char_at(&v[8], 1), 'I', 'N'));
    f.bold = try!(bool_from(char_at(&v[8], 2), 'B', 'N'));
    f.name = name;
    Ok(f)
}

fn parse(s: &str) -> ERes<SymbolLib> {
    let mut lib = SymbolLib::new();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema-LIBRARY Version 2.3");
    assume_line!(p, "#encoding utf-8");
    assume_line!(p,"#");
    while !p.eof() {
        //println!("here: {}", &p.here());
        if &p.here() == "#End Library" {
            break;
        }
        let s = try!(parse_symbol(p));
        //println!("new symbol: {}", &s);
        lib.symbols.push(s)
    }
    Ok(lib)
}

pub fn parse_str(s:&str) -> ERes<SymbolLib> {
    parse(s)
}

pub fn parse_file(filename:&PathBuf) -> ERes<SymbolLib> {
    let name = filename.to_str().unwrap();
    let s = try!(read_file(name));
    parse(&s[..])
}
<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::AtomicBool,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, Acquire, Acquire, AtomicUsize, Lazy, OneShot, Relaxed,
    SeqCst,
};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 7;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    debug_delay();
    for _ in 0..DESIRED_WAITING_THREADS {
        debug_delay();
        spawn_new_thread(true);
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work(is_immortal: bool) {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while is_immortal || performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(Acquire);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(Acquire);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(Acquire);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return;
    }

    if !SPAWNING.compare_and_swap(false, true, SeqCst) {
        spawn_new_thread(false);
    }
}

fn spawn_new_thread(is_immortal: bool) {
    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(move || {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            perform_work(is_immortal);
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
            assert!(!is_immortal);
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread();
    }

    promise
}
<commit_msg>Fix imports on threadpool<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::AtomicBool,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, Acquire, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst,
};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 7;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    debug_delay();
    for _ in 0..DESIRED_WAITING_THREADS {
        debug_delay();
        spawn_new_thread(true);
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work(is_immortal: bool) {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while is_immortal || performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(Acquire);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(Acquire);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(Acquire);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return;
    }

    if !SPAWNING.compare_and_swap(false, true, SeqCst) {
        spawn_new_thread(false);
    }
}

fn spawn_new_thread(is_immortal: bool) {
    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(move || {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            perform_work(is_immortal);
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
            assert!(!is_immortal);
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread();
    }

    promise
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use rand::distributions::{Sample, Range};
use rand::Rng;

use std::usize;
use std::f64;

use super::MCMove;
use super::select_molecule;

use types::Vector3D;
use sys::{System, EnergyCache};

/// Monte Carlo move for translating a molecule
pub struct Translate {
    /// Type of molecule to translate. `None` means all molecules.
    moltype: Option<u64>,
    /// Index of the molecule to translate
    molid: usize,
    /// New positions of the atom in the translated molecule
    newpos: Vec<Vector3D>,
    /// Maximum displacement value
    delta: f64,
    /// The maximum value must not exceed this value, if set
    maximum_cutoff: Option<f64>,
    /// Translation range for random number generation
    range: Range<f64>,
}

impl Translate {
    /// Create a new `Translate` move, with maximum displacement of `delta`.
    /// Translating all the molecules in the system.
    pub fn new(delta: f64) -> Translate {
        Translate::create(delta, None)
    }

    /// Create a new `Translate` move, with maximum displacement of `delta`.
    /// Translating only molecules with `moltype` type.
    pub fn with_moltype(delta: f64, moltype: u64) -> Translate {
        Translate::create(delta, Some(moltype))
    }

    /// Factorizing the constructors
    fn create(delta: f64, moltype: Option<u64>) -> Translate {
        assert!(delta > 0.0, "delta must be positive in Translate move");
        let delta = delta / f64::sqrt(3.0);
        Translate {
            moltype: moltype,
            molid: usize::MAX,
            newpos: Vec::new(),
            delta: delta,
            maximum_cutoff: None,
            range: Range::new(-delta, delta),
        }
    }
}

impl Default for Translate {
    fn default() -> Translate {
        Translate::new(1.0)
    }
}

impl MCMove for Translate {
    fn describe(&self) -> &str {
        "molecular translation"
    }

    fn setup(&mut self, system: &System) {
        // Limit the displacement range to the maximum cutoff
        self.maximum_cutoff = system.maximum_cutoff();
        if let Some(max) = self.maximum_cutoff {
            if self.delta > max {
                warn!(
                    "Changing the maximal displacement for Translate, \
                    because the interactions cutoff is too low."
                );
                self.delta = max
            }
        }
    }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        if let Some(id) = select_molecule(system, self.moltype, rng) {
            self.molid = id;
        } else {
            warn!("Can not translate molecule: no molecule of this type in the system.");
            return false;
        }

        // Create random displacement vector.
        let delta = Vector3D::new(
            self.range.sample(rng),
            self.range.sample(rng),
            self.range.sample(rng)
        );

        // Generate displaced coordinates
        // Note that this may move a particles' center-of-mass (com) out of
        // the cell. If the move is accepted, we have to wrap the com such
        // that it lies inside the cell.
        let indexes = system.molecule(self.molid).iter();
        self.newpos = system.particles().position[indexes].to_vec();
        for newpos in &mut self.newpos {
            *newpos += delta;
        }
        return true;
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        let idxes = system.molecule(self.molid).iter().collect::<Vec<_>>();
        let cost = cache.move_particles_cost(system, idxes, &self.newpos);
        return cost * beta;
    }

    fn apply(&mut self, system: &mut System) {
        {
            // Update positions.
            let indexes = system.molecule(self.molid).iter();
            let positions = &mut system.particles_mut().position[indexes];
            for (position, newpos) in izip!(positions, &self.newpos) {
                *position = *newpos;
            }
        }
        // Move molecule such that its center-of-mass is inside the simulation
        // cell. Note that particles of the molecule may still be outside the
        // cell, but that is not important.
        system.wrap_molecule(self.molid)
    }

    fn restore(&mut self, _: &mut System) {
        // Nothing to do.
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            if let Some(max) = self.maximum_cutoff {
                if (self.delta * s) < max {
                    warn_once!(
                        "Tried to increase the maximum amplitude for \
                        translations to more than the maximum cutoff -- ignoring."
                    );
                    return;
                }
            }

            self.delta *= s;
            self.range = Range::new(-self.delta, self.delta);
        };
    }
}
<commit_msg>Fix warning in MC move translate<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use rand::distributions::{Sample, Range};
use rand::Rng;

use std::usize;
use std::f64;

use super::MCMove;
use super::select_molecule;

use types::Vector3D;
use sys::{System, EnergyCache};

/// Monte Carlo move for translating a molecule
pub struct Translate {
    /// Type of molecule to translate. `None` means all molecules.
    moltype: Option<u64>,
    /// Index of the molecule to translate
    molid: usize,
    /// New positions of the atom in the translated molecule
    newpos: Vec<Vector3D>,
    /// Maximum displacement value
    delta: f64,
    /// The maximum value must not exceed this value, if set
    maximum_cutoff: Option<f64>,
    /// Translation range for random number generation
    range: Range<f64>,
}

impl Translate {
    /// Create a new `Translate` move, with maximum displacement of `delta`.
    /// Translating all the molecules in the system.
    pub fn new(delta: f64) -> Translate {
        Translate::create(delta, None)
    }

    /// Create a new `Translate` move, with maximum displacement of `delta`.
    /// Translating only molecules with `moltype` type.
    pub fn with_moltype(delta: f64, moltype: u64) -> Translate {
        Translate::create(delta, Some(moltype))
    }

    /// Factorizing the constructors
    fn create(delta: f64, moltype: Option<u64>) -> Translate {
        assert!(delta > 0.0, "delta must be positive in Translate move");
        let delta = delta / f64::sqrt(3.0);
        Translate {
            moltype: moltype,
            molid: usize::MAX,
            newpos: Vec::new(),
            delta: delta,
            maximum_cutoff: None,
            range: Range::new(-delta, delta),
        }
    }
}

impl Default for Translate {
    fn default() -> Translate {
        Translate::new(1.0)
    }
}

impl MCMove for Translate {
    fn describe(&self) -> &str {
        "molecular translation"
    }

    fn setup(&mut self, system: &System) {
        // Limit the displacement range to the maximum cutoff
        self.maximum_cutoff = system.maximum_cutoff();
        if let Some(max) = self.maximum_cutoff {
            if self.delta > max {
                warn!("Changing the maximal displacement for Translate, because the interactions \
                       cutoff is too low.");
                self.delta = max
            }
        }
    }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        if let Some(id) = select_molecule(system, self.moltype, rng) {
            self.molid = id;
        } else {
            warn!("Can not translate molecule: no molecule of this type in the system.");
            return false;
        }

        // Create random displacement vector.
        let delta = Vector3D::new(self.range.sample(rng),
                                  self.range.sample(rng),
                                  self.range.sample(rng));

        // Generate displaced coordinates
        // Note that this may move a particles' center-of-mass (com) out of
        // the cell. If the move is accepted, we have to wrap the com such
        // that it lies inside the cell.
        let indexes = system.molecule(self.molid).iter();
        self.newpos = system.particles().position[indexes].to_vec();
        for newpos in &mut self.newpos {
            *newpos += delta;
        }
        return true;
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        let idxes = system.molecule(self.molid).iter().collect::<Vec<_>>();
        let cost = cache.move_particles_cost(system, idxes, &self.newpos);
        return cost * beta;
    }

    fn apply(&mut self, system: &mut System) {
        {
            // Update positions.
            let indexes = system.molecule(self.molid).iter();
            let positions = &mut system.particles_mut().position[indexes];
            for (position, newpos) in izip!(positions, &self.newpos) {
                *position = *newpos;
            }
        }
        // Move molecule such that its center-of-mass is inside the simulation
        // cell. Note that particles of the molecule may still be outside the
        // cell, but that is not important.
        system.wrap_molecule(self.molid)
    }

    fn restore(&mut self, _: &mut System) {
        // Nothing to do.
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            if let Some(max) = self.maximum_cutoff {
                if (self.delta * s) > max {
                    warn_once!("Tried to increase the maximum amplitude for translations to more \
                                than the maximum cutoff -- ignoring.");
                    return;
                }
            }

            self.delta *= s;
            self.range = Range::new(-self.delta, self.delta);
        };
    }
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;

use arch::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, Context, ContextMemory};
use arch::elf::Elf;
use arch::memory;
use arch::regs::Regs;

use collections::string::{String, ToString};
use collections::vec::Vec;

use common::slice::GetSlice;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use fs::Url;

use system::error::{Error, Result, ENOEXEC};

fn execute_inner(url: Url) -> Result<(*mut Context, usize)> {
    let mut vec: Vec<u8> = Vec::new();

    {
        let mut resource = try!(url.open());
        'reading: loop {
            let mut bytes = [0; 4096];
            match resource.read(&mut bytes) {
                Ok(0) => break 'reading,
                Ok(count) => vec.push_all(bytes.get_slice(.. count)),
                Err(err) => return Err(err)
            }
        }
    }

    match Elf::from(&vec) {
        Ok(executable) => {
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    let offset = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + offset);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy((physical_address + offset) as *mut u8,
                                 (executable.data.as_ptr() as usize + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            ::memset((physical_address + offset + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - offset,
                            virtual_size: virtual_size + offset,
                            writeable: segment.flags & 2 == 2,
                            allocated: true,
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                let mut contexts = ::env().contexts.lock();
                let mut context = try!(contexts.current_mut());

                //debugln!("{}: {}: execute {}", context.pid, context.name, url.string);

                context.name = url.string;
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));

                unsafe { context.unmap() };
                context.memory = Arc::new(UnsafeCell::new(memory));
                unsafe { context.map() };

                Ok((context.deref_mut(), entry))
            } else {
                Err(Error::new(ENOEXEC))
            }
        },
        Err(msg) => {
            debugln!("execute: failed to exec '{}': {}", url.string, msg);
            Err(Error::new(ENOEXEC))
        }
    }
}

pub fn execute_outer(context_ptr: *mut Context, entry: usize, mut args: Vec<String>) -> ! {
    Context::spawn("kexec".to_string(), box move || {
        let context = unsafe { &mut *context_ptr };

        let mut context_args: Vec<usize> = Vec::new();
        context_args.push(0); // ENVP
        context_args.push(0); // ARGV NULL
        let mut argc = 0;
        while let Some(mut arg) = args.pop() {
            if ! arg.ends_with('\0') {
                arg.push('\0');
            }

            let physical_address = arg.as_ptr() as usize;
            let virtual_address = context.next_mem();
            let virtual_size = arg.len();

            mem::forget(arg);

            unsafe {
                (*context.memory.get()).push(ContextMemory {
                    physical_address: physical_address,
                    virtual_address: virtual_address,
                    virtual_size: virtual_size,
                    writeable: false,
                    allocated: true,
                });
            }

            context_args.push(virtual_address as usize);
            argc += 1;
        }
        context_args.push(argc);

        context.regs = Regs::default();
        context.regs.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

        context.stack = Some(ContextMemory {
            physical_address: unsafe { memory::alloc(CONTEXT_STACK_SIZE) },
            virtual_address: CONTEXT_STACK_ADDR,
            virtual_size: CONTEXT_STACK_SIZE,
            writeable: true,
            allocated: true,
        });

        let user_sp = if let Some(ref stack) = context.stack {
            let mut sp = stack.physical_address + stack.virtual_size - 128;
            for arg in context_args.iter() {
                sp -= mem::size_of::<usize>();
                unsafe { ptr::write(sp as *mut usize, *arg) };
            }
            sp - stack.physical_address + stack.virtual_address
        } else {
            0
        };

        unsafe {
            context.push(0x20 | 3);
            context.push(user_sp);
            context.push(1 << 9);
            context.push(0x18 | 3);
            context.push(entry);
            context.push(context_userspace as usize);
        }

        if let Some(vfork) = context.vfork.take() {
            unsafe { (*vfork).blocked = false; }
        }
    });

    loop {
        unsafe { context_switch() };
    }
}

/// Execute an executable
pub fn execute(args: Vec<String>) -> Result<usize> {
    let contexts = ::env().contexts.lock();
    let current = try!(contexts.current());

    if let Ok((context_ptr, entry)) = execute_inner(Url::from_string(current.canonicalize(args.get(0).map_or("", |p| &p)))) {
        execute_outer(context_ptr, entry, args);
    }else{
        let (context_ptr, entry) = try!(execute_inner(Url::from_string("file:/bin/".to_string() + args.get(0).map_or("", |p| &p))));
        execute_outer(context_ptr, entry, args);
    }
}
<commit_msg>Hack to fix sys_brk<commit_after>use alloc::arc::Arc;

use arch::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, Context, ContextMemory};
use arch::elf::Elf;
use arch::memory;
use arch::regs::Regs;

use collections::string::{String, ToString};
use collections::vec::Vec;

use common::slice::GetSlice;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use fs::Url;

use system::error::{Error, Result, ENOEXEC};

fn execute_inner(url: Url) -> Result<(*mut Context, usize)> {
    let mut vec: Vec<u8> = Vec::new();

    {
        let mut resource = try!(url.open());
        'reading: loop {
            let mut bytes = [0; 4096];
            match resource.read(&mut bytes) {
                Ok(0) => break 'reading,
                Ok(count) => vec.push_all(bytes.get_slice(.. count)),
                Err(err) => return Err(err)
            }
        }
    }

    match Elf::from(&vec) {
        Ok(executable) => {
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    let offset = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + offset);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy((physical_address + offset) as *mut u8,
                                 (executable.data.as_ptr() as usize + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            ::memset((physical_address + offset + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - offset,
                            virtual_size: virtual_size + offset,
                            writeable: segment.flags & 2 == 2,
                            allocated: true,
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                let mut contexts = ::env().contexts.lock();
                let mut context = try!(contexts.current_mut());

                //debugln!("{}: {}: execute {}", context.pid, context.name, url.string);

                context.name = url.string;
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));

                unsafe { context.unmap() };
                context.memory = Arc::new(UnsafeCell::new(memory));
                unsafe { context.map() };

                Ok((context.deref_mut(), entry))
            } else {
                Err(Error::new(ENOEXEC))
            }
        },
        Err(msg) => {
            debugln!("execute: failed to exec '{}': {}", url.string, msg);
            Err(Error::new(ENOEXEC))
        }
    }
}

pub fn execute_outer(context_ptr: *mut Context, entry: usize, mut args: Vec<String>) -> ! {
    Context::spawn("kexec".to_string(), box move || {
        let context = unsafe { &mut *context_ptr };

        let mut context_args: Vec<usize> = Vec::new();
        context_args.push(0); // ENVP
        context_args.push(0); // ARGV NULL
        let mut argc = 0;
        while let Some(mut arg) = args.pop() {
            if ! arg.ends_with('\0') {
                arg.push('\0');
            }

            let physical_address = arg.as_ptr() as usize;
            let virtual_address = context.next_mem();
            let virtual_size = arg.len();

            mem::forget(arg);

            unsafe {
                (*context.memory.get()).push(ContextMemory {
                    physical_address: physical_address,
                    virtual_address: virtual_address,
                    virtual_size: virtual_size,
                    writeable: false,
                    allocated: true,
                });
            }

            context_args.push(virtual_address as usize);
            argc += 1;
        }
        context_args.push(argc);

        //TODO: No default heap, fix brk
        {
            let virtual_address = context.next_mem();
            let virtual_size = 4096;
            let physical_address = unsafe { memory::alloc(virtual_size) };
            if physical_address > 0 {
                unsafe {
                    (*context.memory.get()).push(ContextMemory {
                        physical_address: physical_address,
                        virtual_address: virtual_address,
                        virtual_size: virtual_size,
                        writeable: true,
                        allocated: true
                    });
                }
            }
        }

        context.regs = Regs::default();
        context.regs.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

        context.stack = Some(ContextMemory {
            physical_address: unsafe { memory::alloc(CONTEXT_STACK_SIZE) },
            virtual_address: CONTEXT_STACK_ADDR,
            virtual_size: CONTEXT_STACK_SIZE,
            writeable: true,
            allocated: true,
        });

        let user_sp = if let Some(ref stack) = context.stack {
            let mut sp = stack.physical_address + stack.virtual_size - 128;
            for arg in context_args.iter() {
                sp -= mem::size_of::<usize>();
                unsafe { ptr::write(sp as *mut usize, *arg) };
            }
            sp - stack.physical_address + stack.virtual_address
        } else {
            0
        };

        unsafe {
            context.push(0x20 | 3);
            context.push(user_sp);
            context.push(1 << 9);
            context.push(0x18 | 3);
            context.push(entry);
            context.push(context_userspace as usize);
        }

        if let Some(vfork) = context.vfork.take() {
            unsafe { (*vfork).blocked = false; }
        }
    });

    loop {
        unsafe { context_switch() };
    }
}

/// Execute an executable
pub fn execute(args: Vec<String>) -> Result<usize> {
    let contexts = ::env().contexts.lock();
    let current = try!(contexts.current());

    if let Ok((context_ptr, entry)) = execute_inner(Url::from_string(current.canonicalize(args.get(0).map_or("", |p| &p)))) {
        execute_outer(context_ptr, entry, args);
    }else{
        let (context_ptr, entry) = try!(execute_inner(Url::from_string("file:/bin/".to_string() + args.get(0).map_or("", |p| &p))));
        execute_outer(context_ptr, entry, args);
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use super::Value;
use map::Map;
use number::Number;

macro_rules! from_integer {
    ($($ty:ident)*) => {
        $(
            impl From<$ty> for Value {
                fn from(n: $ty) -> Self {
                    Value::Number(n.into())
                }
            }
        )*
    };
}

from_integer! {
    i8 i16 i32 i64 isize
    u8 u16 u32 u64 usize
}

#[cfg(feature = "arbitrary_precision")]
serde_if_integer128! {
    from_integer! {
        i128 u128
    }
}

impl From<f32> for Value {
    /// Convert 32-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let f: f32 = 13.37;
    /// let x: Value = f.into();
    /// ```
    fn from(f: f32) -> Self {
        From::from(f as f64)
    }
}

impl From<f64> for Value {
    /// Convert 64-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let f: f64 = 13.37;
    /// let x: Value = f.into();
    /// ```
    fn from(f: f64) -> Self {
        Number::from_f64(f).map_or(Value::Null, Value::Number)
    }
}

impl From<bool> for Value {
    /// Convert boolean to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let b = false;
    /// let x: Value = b.into();
    /// ```
    fn from(f: bool) -> Self {
        Value::Bool(f)
    }
}

impl From<String> for Value {
    /// Convert `String` to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let s: String = "lorem".to_string();
    /// let x: Value = s.into();
    /// ```
    fn from(f: String) -> Self {
        Value::String(f)
    }
}

impl<'a> From<&'a str> for Value {
    /// Convert string slice to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let s: &str = "lorem";
    /// let x: Value = s.into();
    /// ```
    fn from(f: &str) -> Self {
        Value::String(f.to_string())
    }
}

impl<'a> From<Cow<'a, str>> for Value {
    /// Convert copy-on-write string to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Borrowed("lorem");
    /// let x: Value = s.into();
    /// ```
    ///
    /// ```edition2018
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Owned("lorem".to_string());
    /// let x: Value = s.into();
    /// ```
    fn from(f: Cow<'a, str>) -> Self {
        Value::String(f.into_owned())
    }
}

impl From<Map<String, Value>> for Value {
    /// Convert map (with string keys) to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::{Map, Value};
    ///
    /// let mut m = Map::new();
    /// m.insert("Lorem".to_string(), "ipsum".into());
    /// let x: Value = m.into();
    /// ```
    fn from(f: Map<String, Value>) -> Self {
        Value::Object(f)
    }
}

impl<T: Into<Value>> From<Vec<T>> for Value {
    /// Convert a `Vec` to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// ```
    fn from(f: Vec<T>) -> Self {
        Value::Array(f.into_iter().map(Into::into).collect())
    }
}

impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
    /// Convert a slice to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v: &[&str] = &["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// ```
    fn from(f: &'a [T]) -> Self {
        Value::Array(f.iter().cloned().map(Into::into).collect())
    }
}

impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value {
    /// Convert an iteratable type to a `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v = std::iter::repeat(42).take(5);
    /// let x: Value = v.collect();
    /// ```
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into_iter().collect();
    /// ```
    ///
    /// ```edition2018
    /// use std::iter::FromIterator;
    /// use serde_json::Value;
    ///
    /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
    /// ```
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Value::Array(iter.into_iter().map(Into::into).collect())
    }
}
<commit_msg>Add `impl From<()> for Value`<commit_after>use std::borrow::Cow;

use super::Value;
use map::Map;
use number::Number;

macro_rules! from_integer {
    ($($ty:ident)*) => {
        $(
            impl From<$ty> for Value {
                fn from(n: $ty) -> Self {
                    Value::Number(n.into())
                }
            }
        )*
    };
}

from_integer! {
    i8 i16 i32 i64 isize
    u8 u16 u32 u64 usize
}

#[cfg(feature = "arbitrary_precision")]
serde_if_integer128! {
    from_integer! {
        i128 u128
    }
}

impl From<f32> for Value {
    /// Convert 32-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let f: f32 = 13.37;
    /// let x: Value = f.into();
    /// ```
    fn from(f: f32) -> Self {
        From::from(f as f64)
    }
}

impl From<f64> for Value {
    /// Convert 64-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let f: f64 = 13.37;
    /// let x: Value = f.into();
    /// ```
    fn from(f: f64) -> Self {
        Number::from_f64(f).map_or(Value::Null, Value::Number)
    }
}

impl From<bool> for Value {
    /// Convert boolean to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let b = false;
    /// let x: Value = b.into();
    /// ```
    fn from(f: bool) -> Self {
        Value::Bool(f)
    }
}

impl From<String> for Value {
    /// Convert `String` to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let s: String = "lorem".to_string();
    /// let x: Value = s.into();
    /// ```
    fn from(f: String) -> Self {
        Value::String(f)
    }
}

impl<'a> From<&'a str> for Value {
    /// Convert string slice to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let s: &str = "lorem";
    /// let x: Value = s.into();
    /// ```
    fn from(f: &str) -> Self {
        Value::String(f.to_string())
    }
}

impl<'a> From<Cow<'a, str>> for Value {
    /// Convert copy-on-write string to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Borrowed("lorem");
    /// let x: Value = s.into();
    /// ```
    ///
    /// ```edition2018
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Owned("lorem".to_string());
    /// let x: Value = s.into();
    /// ```
    fn from(f: Cow<'a, str>) -> Self {
        Value::String(f.into_owned())
    }
}

impl From<Map<String, Value>> for Value {
    /// Convert map (with string keys) to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::{Map, Value};
    ///
    /// let mut m = Map::new();
    /// m.insert("Lorem".to_string(), "ipsum".into());
    /// let x: Value = m.into();
    /// ```
    fn from(f: Map<String, Value>) -> Self {
        Value::Object(f)
    }
}

impl<T: Into<Value>> From<Vec<T>> for Value {
    /// Convert a `Vec` to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// ```
    fn from(f: Vec<T>) -> Self {
        Value::Array(f.into_iter().map(Into::into).collect())
    }
}

impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
    /// Convert a slice to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v: &[&str] = &["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// ```
    fn from(f: &'a [T]) -> Self {
        Value::Array(f.iter().cloned().map(Into::into).collect())
    }
}

impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value {
    /// Convert an iteratable type to a `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v = std::iter::repeat(42).take(5);
    /// let x: Value = v.collect();
    /// ```
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into_iter().collect();
    /// ```
    ///
    /// ```edition2018
    /// use std::iter::FromIterator;
    /// use serde_json::Value;
    ///
    /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
    /// ```
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Value::Array(iter.into_iter().map(Into::into).collect())
    }
}

impl From<()> for Value {
    /// Convert `()` to `Value`
    ///
    /// # Examples
    ///
    /// ```edition2018
    /// use serde_json::Value;
    ///
    /// let u = ();
    /// let x: Value = u.into();
    /// ```
    fn from((): ()) -> Self {
        Value::Null
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use std::{
    collections::HashMap,
    hash::{BuildHasher, Hash},
    time::{Duration, SystemTime},
};

#[cfg(feature = "serde1")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde1")))]
pub mod serde;

/// Extension trait for [SystemTimes](SystemTime) in the future, i.e. deadlines.
pub trait TimeUntil {
    /// How much time from now until this time is reached.
    fn time_until(&self) -> Duration;
}

impl TimeUntil for SystemTime {
    fn time_until(&self) -> Duration {
        self.duration_since(SystemTime::now()).unwrap_or_default()
    }
}

/// Collection compaction; configurable `shrink_to_fit`.
pub trait Compact {
    /// Compacts space if the ratio of length : capacity is less than `usage_ratio_threshold`.
    fn compact(&mut self, usage_ratio_threshold: f64);
}

impl<K, V, H> Compact for HashMap<K, V, H>
where
    K: Eq + Hash,
    H: BuildHasher,
{
    fn compact(&mut self, usage_ratio_threshold: f64) {
        if self.capacity() > 1000 {
            let usage_ratio = self.len() as f64 / self.capacity() as f64;
            if usage_ratio < usage_ratio_threshold {
                self.shrink_to_fit();
            }
        }
    }
}
<commit_msg>Use HashMap::shrink_to in impl of Comapct::compact.<commit_after>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use std::{
    collections::HashMap,
    hash::{BuildHasher, Hash},
    time::{Duration, SystemTime},
};

#[cfg(feature = "serde1")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde1")))]
pub mod serde;

/// Extension trait for [SystemTimes](SystemTime) in the future, i.e. deadlines.
pub trait TimeUntil {
    /// How much time from now until this time is reached.
    fn time_until(&self) -> Duration;
}

impl TimeUntil for SystemTime {
    fn time_until(&self) -> Duration {
        self.duration_since(SystemTime::now()).unwrap_or_default()
    }
}

/// Collection compaction; configurable `shrink_to_fit`.
pub trait Compact {
    /// Compacts space if the ratio of length : capacity is less than `usage_ratio_threshold`.
    fn compact(&mut self, usage_ratio_threshold: f64);
}

impl<K, V, H> Compact for HashMap<K, V, H>
where
    K: Eq + Hash,
    H: BuildHasher,
{
    fn compact(&mut self, usage_ratio_threshold: f64) {
        let usage_ratio_threshold = usage_ratio_threshold.clamp(f64::MIN_POSITIVE, 1.);
        let cap = f64::max(1000., self.len() as f64 / usage_ratio_threshold);
        self.shrink_to(cap as usize);
    }
}

#[test]
fn test_compact() {
    let mut map = HashMap::with_capacity(2048);
    assert_eq!(map.capacity(), 3584);

    // Make usage ratio 25%
    for i in 0..896 {
        map.insert(format!("k{}", i), "v");
    }

    map.compact(-1.0);
    assert_eq!(map.capacity(), 3584);

    map.compact(0.25);
    assert_eq!(map.capacity(), 3584);

    map.compact(0.50);
    assert_eq!(map.capacity(), 1792);

    map.compact(1.0);
    assert_eq!(map.capacity(), 1792);

    map.compact(2.0);
    assert_eq!(map.capacity(), 1792);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RwLock;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    cache: Arc<RwLock<HashMap<PathBuf, RwLock<File>>>>,
}

impl Store {

    fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }
    fn retrieve<'a>(&'a self, path: PathBuf) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }
    fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }
    fn retrieve_copy(&self, id : String) -> Result<Entry> {
        unimplemented!();
    }
    fn delete(&self, path: PathBuf) -> Result<()> {
        unimplemented!();
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.cache.iter().map(|f| f.unlock());
    }

}

pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

<commit_msg>Add Drop to FileLockEntry<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::{RwLock, Mutex};

use fs2::FileExt;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<PathBuf, (File, Option<Entry>)>>>,
}

impl Store {

    fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }
    fn retrieve<'a>(&'a self, path: PathBuf) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }
    fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }
    fn retrieve_copy(&self, id : String) -> Result<Entry> {
        unimplemented!();
    }
    fn delete(&self, path: PathBuf) -> Result<()> {
        unimplemented!();
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| (f.1).0.unlock());
    }

}

pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: PathBuf,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: PathBuf) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        let mut map = self.store.entries.write().unwrap();
        let (_, ref mut en) = *map.get_mut(&self.key).unwrap();
        *en = Some(self.entry.clone());
    }
}
<|endoftext|>


<commit_before>use chrono::{DateTime, Utc};
use result::*;
use serde_urlencoded;
use serde_json::Value;

mod types;

pub use self::types::*;
use client::{Client, Method};
use response::{parse_list_elements_json, parse_object_json, ListResponse};

/// Query parameters for `get_all_released_orders`
#[derive(Debug, Serialize)]
#[allow(non_snake_case)]
pub struct ReleasedQueryParams {
  pub limit: Option<i32>,
  pub createdStartDate: DateTime<Utc>,
  pub nextCursor: Option<String>,
}

/// Query parameters for `get_all_orders`
#[derive(Debug, Serialize, Default)]
#[allow(non_snake_case)]
pub struct QueryParams {
  pub sku: Option<String>,
  pub customerOrderId: Option<String>,
  pub purchaseOrderId: Option<String>,
  pub status: Option<String>,
  pub createdStartDate: Option<DateTime<Utc>>,
  pub createdEndDate: Option<DateTime<Utc>>,
  pub fromExpectedShipDate: Option<DateTime<Utc>>,
  pub toExpectedShipDate: Option<DateTime<Utc>>,
  pub limit: Option<i32>,
  pub nextCursor: Option<String>,
}

#[derive(Debug, Clone)]
#[allow(non_snake_case)]
pub struct ShipParams {
  pub lineNumber: String,
  pub shipDateTime: DateTime<Utc>,
  pub carrierName: Option<String>,
  pub methodCode: String,
  pub trackingNumber: String,
  pub trackingURL: String,
  pub otherCarrier: Option<String>,
  pub unitOfMeasurement: Option<String>,
  pub amount: Option<String>,
}

impl ShipParams {
  fn to_value(&self) -> Value {
    let timestamp: i64 =
      self.shipDateTime.timestamp() * 1000 + self.shipDateTime.timestamp_subsec_millis() as i64;
    json!({
      "lineNumber": self.lineNumber,
      "orderLineStatuses": {
        "orderLineStatus": [
          {
            "status": "Shipped",
            "statusQuantity": {
              "unitOfMeasurement": self.unitOfMeasurement.clone().unwrap_or_else(|| "EACH".to_owned()),
              "amount": self.amount.clone().unwrap_or_else(|| "1".to_owned()),
            },
            "trackingInfo": {
              "shipDateTime": timestamp,
              "carrierName": {
                "otherCarrier": self.otherCarrier,
                "carrier": self.carrierName,
              },
              "methodCode": self.methodCode,
              "trackingNumber": self.trackingNumber,
              "trackingURL": self.trackingURL
            }
          }
        ]
      }
    })
  }
}

pub type OrderList = ListResponse<Order>;

impl Client {
  pub fn get_all_released_orders(&self, params: &ReleasedQueryParams) -> WalmartResult<OrderList> {
    let qs = serde_urlencoded::to_string(params)?;
    let mut res = self
      .request_json(Method::Get, "/v3/orders/released", qs)?
      .send()?;
    parse_list_elements_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn get_all_orders(&self, params: &QueryParams) -> WalmartResult<OrderList> {
    let mut res = self
      .request_json(
        Method::Get,
        "/v3/orders",
        serde_urlencoded::to_string(params)?,
      )?
      .send()?;
    parse_list_elements_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn get_all_orders_by_next_cursor(&self, next_cursor: &str) -> WalmartResult<OrderList> {
    use url::form_urlencoded;
    let mut res = self
      .request_json(
        Method::Get,
        "/v3/orders",
        form_urlencoded::parse((&next_cursor[1..]).as_bytes())
          .into_owned()
          .collect::<Vec<_>>(),
      )?
      .send()?;
    parse_list_elements_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn get_order(&self, purchase_order_id: &str) -> WalmartResult<Order> {
    let path = format!("/v3/orders/{}", purchase_order_id);
    let mut res = self.request_json(Method::Get, &path, ())?.send()?;
    parse_object_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn ack_order(&self, purchase_order_id: &str) -> WalmartResult<Order> {
    let path = format!("/v3/orders/{}/acknowledge", purchase_order_id);
    let mut res = self
      .request_json(Method::Post, &path, ())?
      .json(&Vec::<i32>::new())
      .send()?;
    parse_object_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn ship_order_line(
    &self,
    purchase_order_id: &str,
    line: &ShipParams,
  ) -> WalmartResult<Order> {
    self.ship_order(purchase_order_id, &[line.clone()])
  }

  pub fn ship_order(
    &self,
    purchase_order_id: &str,
    lines: &[ShipParams],
  ) -> WalmartResult<Order> {
    let line_values: Vec<_> = lines.into_iter()
      .map(ShipParams::to_value)
      .collect();
    let body = json!({
      "orderShipment": {
        "orderLines": {
          "orderLine": line_values,
        }
      }
    });
    let path = format!("/v3/orders/{}/shipping", purchase_order_id);
    let mut res = self
      .request_json(
        Method::Post,
        &path,
        vec![("purchaseOrderId", purchase_order_id)],
      )?
      .json(&body)
      .send()?;
    parse_object_json(res.status(), &mut res, "order").map_err(Into::into)
  }
}<commit_msg>Expose ShipParams::to_value<commit_after>use chrono::{DateTime, Utc};
use result::*;
use serde_json::Value;
use serde_urlencoded;

mod types;

pub use self::types::*;
use client::{Client, Method};
use response::{parse_list_elements_json, parse_object_json, ListResponse};

/// Query parameters for `get_all_released_orders`
#[derive(Debug, Serialize)]
#[allow(non_snake_case)]
pub struct ReleasedQueryParams {
  pub limit: Option<i32>,
  pub createdStartDate: DateTime<Utc>,
  pub nextCursor: Option<String>,
}

/// Query parameters for `get_all_orders`
#[derive(Debug, Serialize, Default)]
#[allow(non_snake_case)]
pub struct QueryParams {
  pub sku: Option<String>,
  pub customerOrderId: Option<String>,
  pub purchaseOrderId: Option<String>,
  pub status: Option<String>,
  pub createdStartDate: Option<DateTime<Utc>>,
  pub createdEndDate: Option<DateTime<Utc>>,
  pub fromExpectedShipDate: Option<DateTime<Utc>>,
  pub toExpectedShipDate: Option<DateTime<Utc>>,
  pub limit: Option<i32>,
  pub nextCursor: Option<String>,
}

#[derive(Debug, Clone)]
#[allow(non_snake_case)]
pub struct ShipParams {
  pub lineNumber: String,
  pub shipDateTime: DateTime<Utc>,
  pub carrierName: Option<String>,
  pub methodCode: String,
  pub trackingNumber: String,
  pub trackingURL: String,
  pub otherCarrier: Option<String>,
  pub unitOfMeasurement: Option<String>,
  pub amount: Option<String>,
}

impl ShipParams {
  pub fn to_value(&self) -> Value {
    let timestamp: i64 =
      self.shipDateTime.timestamp() * 1000 + self.shipDateTime.timestamp_subsec_millis() as i64;
    json!({
      "lineNumber": self.lineNumber,
      "orderLineStatuses": {
        "orderLineStatus": [
          {
            "status": "Shipped",
            "statusQuantity": {
              "unitOfMeasurement": self.unitOfMeasurement.clone().unwrap_or_else(|| "EACH".to_owned()),
              "amount": self.amount.clone().unwrap_or_else(|| "1".to_owned()),
            },
            "trackingInfo": {
              "shipDateTime": timestamp,
              "carrierName": {
                "otherCarrier": self.otherCarrier,
                "carrier": self.carrierName,
              },
              "methodCode": self.methodCode,
              "trackingNumber": self.trackingNumber,
              "trackingURL": self.trackingURL
            }
          }
        ]
      }
    })
  }
}

pub type OrderList = ListResponse<Order>;

impl Client {
  pub fn get_all_released_orders(&self, params: &ReleasedQueryParams) -> WalmartResult<OrderList> {
    let qs = serde_urlencoded::to_string(params)?;
    let mut res = self
      .request_json(Method::Get, "/v3/orders/released", qs)?
      .send()?;
    parse_list_elements_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn get_all_orders(&self, params: &QueryParams) -> WalmartResult<OrderList> {
    let mut res = self
      .request_json(
        Method::Get,
        "/v3/orders",
        serde_urlencoded::to_string(params)?,
      )?
      .send()?;
    parse_list_elements_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn get_all_orders_by_next_cursor(&self, next_cursor: &str) -> WalmartResult<OrderList> {
    use url::form_urlencoded;
    let mut res = self
      .request_json(
        Method::Get,
        "/v3/orders",
        form_urlencoded::parse((&next_cursor[1..]).as_bytes())
          .into_owned()
          .collect::<Vec<_>>(),
      )?
      .send()?;
    parse_list_elements_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn get_order(&self, purchase_order_id: &str) -> WalmartResult<Order> {
    let path = format!("/v3/orders/{}", purchase_order_id);
    let mut res = self.request_json(Method::Get, &path, ())?.send()?;
    parse_object_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn ack_order(&self, purchase_order_id: &str) -> WalmartResult<Order> {
    let path = format!("/v3/orders/{}/acknowledge", purchase_order_id);
    let mut res = self
      .request_json(Method::Post, &path, ())?
      .json(&Vec::<i32>::new())
      .send()?;
    parse_object_json(res.status(), &mut res, "order").map_err(Into::into)
  }

  pub fn ship_order_line(
    &self,
    purchase_order_id: &str,
    line: &ShipParams,
  ) -> WalmartResult<Order> {
    self.ship_order(purchase_order_id, &[line.clone()])
  }

  pub fn ship_order(&self, purchase_order_id: &str, lines: &[ShipParams]) -> WalmartResult<Order> {
    let line_values: Vec<_> = lines.into_iter().map(ShipParams::to_value).collect();
    let body = json!({
      "orderShipment": {
        "orderLines": {
          "orderLine": line_values,
        }
      }
    });
    let path = format!("/v3/orders/{}/shipping", purchase_order_id);
    let mut res = self
      .request_json(
        Method::Post,
        &path,
        vec![("purchaseOrderId", purchase_order_id)],
      )?
      .json(&body)
      .send()?;
    parse_object_json(res.status(), &mut res, "order").map_err(Into::into)
  }
}
<|endoftext|>


<commit_before>//! # imag
//!
//! This is the _developer_ documentation for the imag personal information management suite for the
//! commandline.
//!
//! For the user documentation, have a look
//! [at the 'doc' subtree in the repository](http://git.imag-pim.org/imag/tree/doc)
//! which can be compiled to HTML or PDF using [pandoc](pandoc.org) (and might be a bit outdated as
//! imag is not yet released for use).
//!
//! ## General
//!
//! _Some_ things from the user documentation might be helpful for developers as well, so make sure
//! to at least skim over it if you want to contribute to the imag source.
//!
//! Also make sure you had a look at
//! [the CONTRIBUTING](http://git.imag-pim.org/imag/tree/CONTRIBUTING.md)
//! file and [the developers certificate of origin](http://developercertificate.org/), which we also
//! have in the `CONTRIBUTING` file, by the way.
//!
//! ## Contributing
//!
//! All things relevant for contributing are descripbed in
//! [the CONTRIBUTING file](http://git.imag-pim.org/imag/tree/CONTRIBUTING.md),
//! but here are some additional notes:
//!
//! * We have a `editorconfig` file in the repository. Would be nice if you'd
//!   [use it](http://editorconfig.org/)
//! * We have [default.nix](http://git.imag-pim.org/imag/tree/default.nix) file, which can be used
//!   to install dependencies in `nix-shell` environments. If you have a installation of the nix
//!   package manager, feel free to use this opportunity to be _pure_.
//! * If you want to play around with imag, use the
//!   [imagrc.toml](http://git.imag-pim.org/imag/tree/imagrc.toml)
//!   file from the repository, we try to keep it up to date.
//! * You can use [the Makefile](http://git.imag-pim.org/imag/tree/Makefile) to build things (if you
//!   have all dependencies and cargo/rustc installed, of course).
//! * It is a real advantage to use `cargo-check` when developing things - it speeds you up, beleive
//!   me!
//!

<commit_msg>.imag-documentation: Add copyright notice to all files<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

//! # imag
//!
//! This is the _developer_ documentation for the imag personal information management suite for the
//! commandline.
//!
//! For the user documentation, have a look
//! [at the 'doc' subtree in the repository](http://git.imag-pim.org/imag/tree/doc)
//! which can be compiled to HTML or PDF using [pandoc](pandoc.org) (and might be a bit outdated as
//! imag is not yet released for use).
//!
//! ## General
//!
//! _Some_ things from the user documentation might be helpful for developers as well, so make sure
//! to at least skim over it if you want to contribute to the imag source.
//!
//! Also make sure you had a look at
//! [the CONTRIBUTING](http://git.imag-pim.org/imag/tree/CONTRIBUTING.md)
//! file and [the developers certificate of origin](http://developercertificate.org/), which we also
//! have in the `CONTRIBUTING` file, by the way.
//!
//! ## Contributing
//!
//! All things relevant for contributing are descripbed in
//! [the CONTRIBUTING file](http://git.imag-pim.org/imag/tree/CONTRIBUTING.md),
//! but here are some additional notes:
//!
//! * We have a `editorconfig` file in the repository. Would be nice if you'd
//!   [use it](http://editorconfig.org/)
//! * We have [default.nix](http://git.imag-pim.org/imag/tree/default.nix) file, which can be used
//!   to install dependencies in `nix-shell` environments. If you have a installation of the nix
//!   package manager, feel free to use this opportunity to be _pure_.
//! * If you want to play around with imag, use the
//!   [imagrc.toml](http://git.imag-pim.org/imag/tree/imagrc.toml)
//!   file from the repository, we try to keep it up to date.
//! * You can use [the Makefile](http://git.imag-pim.org/imag/tree/Makefile) to build things (if you
//!   have all dependencies and cargo/rustc installed, of course).
//! * It is a real advantage to use `cargo-check` when developing things - it speeds you up, beleive
//!   me!
//!

<|endoftext|>


<commit_before>use std::collections::HashSet;

#[test]
fn all_aggregrated_diffs_equal_latest_version(
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let ((expected, baseline_duration), (actual, diff_duration)) = std::thread::scope(
        |scope| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
            let baseline = scope.spawn(|| -> Result<_, crates_index::Error> {
                let index = crates_index::Index::new_cargo_default()?;
                let start = std::time::Instant::now();
                let mut versions = HashSet::new();
                for krate in index.crates() {
                    for version in krate.versions() {
                        versions.insert(version.checksum().to_owned());
                    }
                }
                Ok((versions, start.elapsed()))
            });

            let actual = scope.spawn(|| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
                use crates_index_diff::git;

                let start = std::time::Instant::now();
                let repo_path = crates_index::Index::new_cargo_default()?.path().to_owned();
                let index = crates_index_diff::Index::from_path_or_cloned(repo_path)?;
                let changes = index.changes_between_commits(
                    git::hash::ObjectId::empty_tree(git::hash::Kind::Sha1),
                    index.repository().head_id()?,
                )?;

                use crates_index_diff::Change::*;
                let mut versions = HashSet::new();

                for change in changes {
                    match change {
                        Added(v) | Yanked(v) => {
                            versions.insert(v.checksum.to_owned());
                        }
                        Deleted {
                            versions: deleted, ..
                        } => {
                            for deleted_version in deleted {
                                versions.remove(&deleted_version.checksum);
                            }
                        }
                    }
                }
                Ok((versions, start.elapsed()))
            });

            Ok((
                baseline.join().expect("no panic")?,
                actual.join().expect("no panic")?,
            ))
        },
    )?;

    dbg!(baseline_duration, expected.len());
    dbg!(diff_duration, actual.len());
    // assert_eq!(
    //     actual.len(),
    //     expected.len(),
    //     "aggregated of all changes produces the final result"
    // );

    Ok(())
}
<commit_msg>make baseline work with CI (#26)<commit_after>use std::collections::HashSet;

#[test]
fn all_aggregrated_diffs_equal_latest_version(
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let ((expected, baseline_duration), (actual, diff_duration)) = std::thread::scope(
        |scope| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
            let baseline = scope.spawn(|| -> Result<_, crates_index::Error> {
                let index = crates_index::Index::new_cargo_default()?;
                let start = std::time::Instant::now();
                let mut versions = HashSet::new();
                for krate in index.crates() {
                    for version in krate.versions() {
                        versions.insert(version.checksum().to_owned());
                    }
                }
                Ok((versions, start.elapsed()))
            });

            let actual = scope.spawn(|| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
                use crates_index_diff::git;

                let start = std::time::Instant::now();
                let repo_path = crates_index::Index::new_cargo_default()?.path().to_owned();
                let index = crates_index_diff::Index::from_path_or_cloned(repo_path)?;
                let changes = index.changes_between_commits(
                    git::hash::ObjectId::empty_tree(git::hash::Kind::Sha1),
                    index
                        .repository()
                        .find_reference("refs/remotes/origin/HEAD")?
                        .target()
                        .id(),
                )?;

                use crates_index_diff::Change::*;
                let mut versions = HashSet::new();

                for change in changes {
                    match change {
                        Added(v) | Yanked(v) => {
                            versions.insert(v.checksum.to_owned());
                        }
                        Deleted {
                            versions: deleted, ..
                        } => {
                            for deleted_version in deleted {
                                versions.remove(&deleted_version.checksum);
                            }
                        }
                    }
                }
                Ok((versions, start.elapsed()))
            });

            Ok((
                baseline.join().expect("no panic")?,
                actual.join().expect("no panic")?,
            ))
        },
    )?;

    dbg!(baseline_duration, expected.len());
    dbg!(diff_duration, actual.len());
    // assert_eq!(
    //     actual.len(),
    //     expected.len(),
    //     "aggregated of all changes produces the final result"
    // );

    Ok(())
}
<|endoftext|>