<commit_before>use std::error::Error;
use std::collections::{VecDeque, vec_deque};
use std::str;
use std::cmp;
use std::mem;

use itertools::Itertools;
use rust_htslib::bcf;

pub fn match_variants(matchbcf: &str, max_dist: u32, max_len_diff: u32) -> Result<(), Box<Error>> {
    let inbcf = try!(bcf::Reader::new(&"-"));
    let mut header = bcf::Header::with_template(&inbcf.header);

    header.push_record(
        format!("##INFO=<ID=MATCHING,Number=A,Type=Integer,\
        Description=\"For each alternative allele, -1 if it does not match a variant in another VCF/BCF. \
        If it matches a variant, an id i>=0 is points to the i-th variant in the VCF/BCF (counting each \
        alternative allele separately). For indels, matching is fuzzy: distance of centres <= {}, difference of \
        lengths <= {}\">", max_dist, max_len_diff).as_bytes()
    );
    header.push_record(
        format!("##rust-bio-tools={}", env!("CARGO_PKG_VERSION")).as_bytes()
    );
    header.push_record(
        b"##rust-bio-tools-subcommand=vcf-match"
    );
    let mut outbcf = try!(bcf::Writer::new(&"-", &header, false, false));
    let mut buffer = RecordBuffer::new(try!(bcf::Reader::new(&matchbcf)), max_dist);

    let mut rec = bcf::Record::new();
    let mut i = 0;
    loop {
        if let Err(e) = inbcf.read(&mut rec) {
            if e.is_eof() {
                break;
            }
            return Err(Box::new(e));
        }
        outbcf.translate(&mut rec);

        if let Some(rid) = rec.rid() {
            let chrom = inbcf.header.rid2name(rid);
            let pos = rec.pos();
            // move buffer to pos
            try!(buffer.fill(chrom, pos));

            let var = try!(Variant::new(&mut rec, &mut i));
            let matching = var.alleles.iter().map(|a| {
                for v in buffer.iter() {
                    if let Some(id) = var.matches(v, a, max_dist, max_len_diff) {
                        return id as i32;
                    }
                }
                -1
            }).collect_vec();

            try!(rec.push_info_integer(b"MATCHING", &matching));
            try!(outbcf.write(&rec));
        } else {
            try!(outbcf.write(&rec));
        }

        if (i) % 1000 == 0 {
            info!("{} variants written.", i);
        }
    }
    info!("{} variants written.", i);

    Ok(())
}

#[derive(Debug)]
pub struct Variant {
    id: u32,
    rid: u32,
    pos: u32,
    alleles: Vec<VariantType>
}

impl Variant {

    pub fn new(rec: &mut bcf::Record, id: &mut u32) -> Result<Self, Box<Error>> {
        let pos = rec.pos();

        let svlen = if let Ok(Some(svlen)) = rec.info(b"SVLEN").integer() {
            Some(svlen[0] as u32)
        } else { None };
        let svtype = if let Ok(Some(svtype)) = rec.info(b"SVTYPE").string() {
            Some(svtype[0].to_owned())
        } else { None };
        let end = if let Ok(Some(end)) = rec.info(b"END").integer() {
            Some(end[0] as u32)
        } else { None };
        let inslen = if let Ok(Some(inslen)) = rec.info(b"INSLEN").integer() {
            Some(inslen[0] as u32)
        } else { None };
        let alleles = rec.alleles();
        let refallele = alleles[0];

        let _alleles: Vec<VariantType> = if let Some(svtype) = svtype {
            vec![
                if svtype == b"INS" {
                    let svlen = match (svlen, inslen) {
                        (Some(svlen), _)     => svlen,
                        (None, Some(inslen)) => inslen,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or INSLEN".to_owned())));
                        }
                    };
                    VariantType::Insertion(svlen)
                } else if svtype == b"DEL" {
                    let svlen = match(svlen, end) {
                        (Some(svlen), _)  => svlen,
                        (None, Some(end)) => end - 1 - pos,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or END".to_owned())));
                        }
                    };
                    VariantType::Deletion(svlen)
                } else {
                    warn!("Unsupported variant {}", try!(str::from_utf8(&svtype)));
                    VariantType::Unsupported
                }
            ]
        } else {
            let mut _alleles = Vec::with_capacity(alleles.len() - 1);
            for a in &alleles[1..] {
                _alleles.push(
                    if a.len() < refallele.len() {
                        VariantType::Deletion((refallele.len() - a.len()) as u32)
                    } else if a.len() > refallele.len() {
                        VariantType::Insertion((a.len() - refallele.len()) as u32)
                    } else if a.len() == 1 {
                        VariantType::SNV(a[0])
                    } else {
                        warn!("Unsupported variant {} -> {}", try!(str::from_utf8(refallele)), try!(str::from_utf8(a)));
                        VariantType::Unsupported
                    }
                );
            }
            _alleles
        };

        let var = Variant {
            id: *id,
            rid: rec.rid().unwrap(),
            pos: pos,
            alleles: _alleles
        };
        *id += alleles.len() as u32 - 1;
        Ok(var)
    }

    pub fn centerpoint(&self, allele: &VariantType) -> u32 {
        match allele {
            &VariantType::SNV(_) => self.pos,
            &VariantType::Insertion(_) => self.pos,
            &VariantType::Deletion(len) => (self.pos as f64 + len as f64 / 2.0) as u32,
            &VariantType::Unsupported => panic!("Unsupported variant.")
        }
    }

    pub fn matches(&self, other: &Variant, allele: &VariantType, max_dist: u32, max_len_diff: u32) -> Option<u32> {
        if allele.is_unsupported() {
            return None;
        }
        for (j, b) in other.alleles.iter().enumerate() {
            if b.is_unsupported() {
                continue;
            }
            let dist = (self.centerpoint(allele) as i32 - other.centerpoint(b) as i32).abs() as u32;
            match (allele, b) {
                (&VariantType::SNV(a), &VariantType::SNV(b)) => {
                    if a == b && dist == 0 {
                        return Some(other.id(j));
                    }
                },
                (&VariantType::Insertion(l1), &VariantType::Insertion(l2)) |
                (&VariantType::Deletion(l1), &VariantType::Deletion(l2)) => {
                    if (l1 as i32 - l2 as i32).abs() as u32 <= max_len_diff && dist <= max_dist {
                        return Some(other.id(j));
                    }
                },
                // TODO: for now, ignore complex variants
                _ => continue
            }
        }
        None
    }

    pub fn id(&self, allele: usize) -> u32 {
        self.id + allele as u32
    }
}

#[derive(Debug)]
pub enum VariantType {
    SNV(u8),
    Insertion(u32),
    Deletion(u32),
    Unsupported
}

impl VariantType {
    pub fn is_unsupported(&self) -> bool {
        match self {
            &VariantType::Unsupported => true,
            _ => false
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum MatchError {
        MissingTag(tag: String) {
            description("missing tag")
            display("missing tag {}", tag)
        }
    }
}

pub struct RecordBuffer {
    reader: bcf::Reader,
    ringbuffer: VecDeque<Variant>,
    ringbuffer2: VecDeque<Variant>,
    window: u32,
    i: u32
}

impl RecordBuffer {
    pub fn new(reader: bcf::Reader, window: u32) -> Self {
        RecordBuffer {
            reader: reader,
            ringbuffer: VecDeque::new(),
            ringbuffer2: VecDeque::new(),
            window: window,
            i: 0
        }
    }

    pub fn last_rid(&self) -> Option<u32> {
        self.ringbuffer.back().map(|var| var.rid)
    }

    pub fn next_rid(&self) -> Option<u32> {
        self.ringbuffer2.back().map(|var| var.rid)
    }

    fn swap_buffers(&mut self) {
        // swap with buffer for next rid
        mem::swap(&mut self.ringbuffer2, &mut self.ringbuffer);
        // clear second buffer
        self.ringbuffer2.clear();
    }

    fn drain_left(&mut self, rid: u32, window_start: u32) {
        // remove records too far left or from wrong rid
        let to_remove = self.ringbuffer.iter().take_while(|var| var.pos < window_start || var.rid != rid).count();
        self.ringbuffer.drain(..to_remove);
    }

    pub fn fill(&mut self, chrom: &[u8], pos: u32) -> Result<(), Box<Error>> {
        let window_start = cmp::max(pos as i32 - self.window as i32 - 1, 0) as u32;
        let window_end = pos + self.window;
        let rid = try!(self.reader.header.name2rid(chrom));

        match (self.last_rid(), self.next_rid()) {
            (Some(last_rid), _) => {
                if last_rid != rid {
                    self.swap_buffers();
                } else {
                    self.drain_left(rid, window_start);
                }
            },
            (_, Some(_)) => {
                self.swap_buffers();
                self.drain_left(rid, window_start);
            },
            _ => ()
        }

        if !self.ringbuffer2.is_empty() {
            // We have already read beyond the current rid. Hence we can't extend to the right for
            // this rid.
            return Ok(())
        }

        // extend to the right
        let mut rec = bcf::Record::new();
        loop {
            if let Err(e) = self.reader.read(&mut rec) {
                if e.is_eof() {
                    break;
                }
                return Err(Box::new(e));
            }
            let pos = rec.pos();
            if let Some(rec_rid) = rec.rid() {
                if rec_rid == rid {
                    if pos > window_end {
                        // Record is beyond our window. Store it anyways but stop.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                        break;
                    } else if pos >= window_start {
                        // Record is within out window.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    }
                } else if rec_rid > rid {
                    // record comes from next rid. Store it in second buffer but stop filling.
                    self.ringbuffer2.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    break;
                } else {
                    // Record comes from previous rid. Ignore it.
                    continue;
                }
            } else {
                // skip records without proper rid
                continue;
            }
        }

        Ok(())
    }

    pub fn iter(&self) -> vec_deque::Iter<Variant> {
        self.ringbuffer.iter()
    }
}
<commit_msg>Take absolute value of SVLEN.<commit_after>use std::error::Error;
use std::collections::{VecDeque, vec_deque};
use std::str;
use std::cmp;
use std::mem;

use itertools::Itertools;
use rust_htslib::bcf;

pub fn match_variants(matchbcf: &str, max_dist: u32, max_len_diff: u32) -> Result<(), Box<Error>> {
    let inbcf = try!(bcf::Reader::new(&"-"));
    let mut header = bcf::Header::with_template(&inbcf.header);

    header.push_record(
        format!("##INFO=<ID=MATCHING,Number=A,Type=Integer,\
        Description=\"For each alternative allele, -1 if it does not match a variant in another VCF/BCF. \
        If it matches a variant, an id i>=0 is points to the i-th variant in the VCF/BCF (counting each \
        alternative allele separately). For indels, matching is fuzzy: distance of centres <= {}, difference of \
        lengths <= {}\">", max_dist, max_len_diff).as_bytes()
    );
    header.push_record(
        format!("##rust-bio-tools={}", env!("CARGO_PKG_VERSION")).as_bytes()
    );
    header.push_record(
        b"##rust-bio-tools-subcommand=vcf-match"
    );
    let mut outbcf = try!(bcf::Writer::new(&"-", &header, false, false));
    let mut buffer = RecordBuffer::new(try!(bcf::Reader::new(&matchbcf)), max_dist);

    let mut rec = bcf::Record::new();
    let mut i = 0;
    loop {
        if let Err(e) = inbcf.read(&mut rec) {
            if e.is_eof() {
                break;
            }
            return Err(Box::new(e));
        }
        outbcf.translate(&mut rec);

        if let Some(rid) = rec.rid() {
            let chrom = inbcf.header.rid2name(rid);
            let pos = rec.pos();
            // move buffer to pos
            try!(buffer.fill(chrom, pos));

            let var = try!(Variant::new(&mut rec, &mut i));
            let matching = var.alleles.iter().map(|a| {
                for v in buffer.iter() {
                    if let Some(id) = var.matches(v, a, max_dist, max_len_diff) {
                        return id as i32;
                    }
                }
                -1
            }).collect_vec();

            try!(rec.push_info_integer(b"MATCHING", &matching));
            try!(outbcf.write(&rec));
        } else {
            try!(outbcf.write(&rec));
        }

        if (i) % 1000 == 0 {
            info!("{} variants written.", i);
        }
    }
    info!("{} variants written.", i);

    Ok(())
}

#[derive(Debug)]
pub struct Variant {
    id: u32,
    rid: u32,
    pos: u32,
    alleles: Vec<VariantType>
}

impl Variant {

    pub fn new(rec: &mut bcf::Record, id: &mut u32) -> Result<Self, Box<Error>> {
        let pos = rec.pos();

        let svlen = if let Ok(Some(svlen)) = rec.info(b"SVLEN").integer() {
            Some(svlen[0].abs() as u32)
        } else { None };
        let svtype = if let Ok(Some(svtype)) = rec.info(b"SVTYPE").string() {
            Some(svtype[0].to_owned())
        } else { None };
        let end = if let Ok(Some(end)) = rec.info(b"END").integer() {
            Some(end[0] as u32)
        } else { None };
        let inslen = if let Ok(Some(inslen)) = rec.info(b"INSLEN").integer() {
            Some(inslen[0] as u32)
        } else { None };
        let alleles = rec.alleles();
        let refallele = alleles[0];

        let _alleles: Vec<VariantType> = if let Some(svtype) = svtype {
            vec![
                if svtype == b"INS" {
                    let svlen = match (svlen, inslen) {
                        (Some(svlen), _)     => svlen,
                        (None, Some(inslen)) => inslen,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or INSLEN".to_owned())));
                        }
                    };
                    VariantType::Insertion(svlen)
                } else if svtype == b"DEL" {
                    let svlen = match(svlen, end) {
                        (Some(svlen), _)  => svlen,
                        (None, Some(end)) => end - 1 - pos,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or END".to_owned())));
                        }
                    };
                    VariantType::Deletion(svlen)
                } else {
                    warn!("Unsupported variant {}", try!(str::from_utf8(&svtype)));
                    VariantType::Unsupported
                }
            ]
        } else {
            let mut _alleles = Vec::with_capacity(alleles.len() - 1);
            for a in &alleles[1..] {
                _alleles.push(
                    if a.len() < refallele.len() {
                        VariantType::Deletion((refallele.len() - a.len()) as u32)
                    } else if a.len() > refallele.len() {
                        VariantType::Insertion((a.len() - refallele.len()) as u32)
                    } else if a.len() == 1 {
                        VariantType::SNV(a[0])
                    } else {
                        warn!("Unsupported variant {} -> {}", try!(str::from_utf8(refallele)), try!(str::from_utf8(a)));
                        VariantType::Unsupported
                    }
                );
            }
            _alleles
        };

        let var = Variant {
            id: *id,
            rid: rec.rid().unwrap(),
            pos: pos,
            alleles: _alleles
        };
        *id += alleles.len() as u32 - 1;
        Ok(var)
    }

    pub fn centerpoint(&self, allele: &VariantType) -> u32 {
        match allele {
            &VariantType::SNV(_) => self.pos,
            &VariantType::Insertion(_) => self.pos,
            &VariantType::Deletion(len) => (self.pos as f64 + len as f64 / 2.0) as u32,
            &VariantType::Unsupported => panic!("Unsupported variant.")
        }
    }

    pub fn matches(&self, other: &Variant, allele: &VariantType, max_dist: u32, max_len_diff: u32) -> Option<u32> {
        if allele.is_unsupported() {
            return None;
        }
        for (j, b) in other.alleles.iter().enumerate() {
            if b.is_unsupported() {
                continue;
            }
            let dist = (self.centerpoint(allele) as i32 - other.centerpoint(b) as i32).abs() as u32;
            match (allele, b) {
                (&VariantType::SNV(a), &VariantType::SNV(b)) => {
                    if a == b && dist == 0 {
                        return Some(other.id(j));
                    }
                },
                (&VariantType::Insertion(l1), &VariantType::Insertion(l2)) |
                (&VariantType::Deletion(l1), &VariantType::Deletion(l2)) => {
                    if (l1 as i32 - l2 as i32).abs() as u32 <= max_len_diff && dist <= max_dist {
                        return Some(other.id(j));
                    }
                },
                // TODO: for now, ignore complex variants
                _ => continue
            }
        }
        None
    }

    pub fn id(&self, allele: usize) -> u32 {
        self.id + allele as u32
    }
}

#[derive(Debug)]
pub enum VariantType {
    SNV(u8),
    Insertion(u32),
    Deletion(u32),
    Unsupported
}

impl VariantType {
    pub fn is_unsupported(&self) -> bool {
        match self {
            &VariantType::Unsupported => true,
            _ => false
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum MatchError {
        MissingTag(tag: String) {
            description("missing tag")
            display("missing tag {}", tag)
        }
    }
}

pub struct RecordBuffer {
    reader: bcf::Reader,
    ringbuffer: VecDeque<Variant>,
    ringbuffer2: VecDeque<Variant>,
    window: u32,
    i: u32
}

impl RecordBuffer {
    pub fn new(reader: bcf::Reader, window: u32) -> Self {
        RecordBuffer {
            reader: reader,
            ringbuffer: VecDeque::new(),
            ringbuffer2: VecDeque::new(),
            window: window,
            i: 0
        }
    }

    pub fn last_rid(&self) -> Option<u32> {
        self.ringbuffer.back().map(|var| var.rid)
    }

    pub fn next_rid(&self) -> Option<u32> {
        self.ringbuffer2.back().map(|var| var.rid)
    }

    fn swap_buffers(&mut self) {
        // swap with buffer for next rid
        mem::swap(&mut self.ringbuffer2, &mut self.ringbuffer);
        // clear second buffer
        self.ringbuffer2.clear();
    }

    fn drain_left(&mut self, rid: u32, window_start: u32) {
        // remove records too far left or from wrong rid
        let to_remove = self.ringbuffer.iter().take_while(|var| var.pos < window_start || var.rid != rid).count();
        self.ringbuffer.drain(..to_remove);
    }

    pub fn fill(&mut self, chrom: &[u8], pos: u32) -> Result<(), Box<Error>> {
        let window_start = cmp::max(pos as i32 - self.window as i32 - 1, 0) as u32;
        let window_end = pos + self.window;
        let rid = try!(self.reader.header.name2rid(chrom));

        match (self.last_rid(), self.next_rid()) {
            (Some(last_rid), _) => {
                if last_rid != rid {
                    self.swap_buffers();
                } else {
                    self.drain_left(rid, window_start);
                }
            },
            (_, Some(_)) => {
                self.swap_buffers();
                self.drain_left(rid, window_start);
            },
            _ => ()
        }

        if !self.ringbuffer2.is_empty() {
            // We have already read beyond the current rid. Hence we can't extend to the right for
            // this rid.
            return Ok(())
        }

        // extend to the right
        let mut rec = bcf::Record::new();
        loop {
            if let Err(e) = self.reader.read(&mut rec) {
                if e.is_eof() {
                    break;
                }
                return Err(Box::new(e));
            }
            let pos = rec.pos();
            if let Some(rec_rid) = rec.rid() {
                if rec_rid == rid {
                    if pos > window_end {
                        // Record is beyond our window. Store it anyways but stop.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                        break;
                    } else if pos >= window_start {
                        // Record is within out window.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    }
                } else if rec_rid > rid {
                    // record comes from next rid. Store it in second buffer but stop filling.
                    self.ringbuffer2.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    break;
                } else {
                    // Record comes from previous rid. Ignore it.
                    continue;
                }
            } else {
                // skip records without proper rid
                continue;
            }
        }

        Ok(())
    }

    pub fn iter(&self) -> vec_deque::Iter<Variant> {
        self.ringbuffer.iter()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![allow(clippy::useless_attribute)] //issue #2910
#![allow(clippy::random_state)] // issue #3628

#[macro_use]
extern crate serde_derive;

/// Test that we do not lint for unused underscores in a `MacroAttribute`
/// expansion
#[deny(clippy::used_underscore_binding)]
#[derive(Deserialize)]
struct MacroAttributesTest {
    _foo: u32,
}

#[test]
fn macro_attributes_test() {
    let _ = MacroAttributesTest { _foo: 0 };
}

fn main() {}
<commit_msg>Revert "tests: used_underscore_binding_macro: disable random_state lint."<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![allow(clippy::useless_attribute)] //issue #2910

#[macro_use]
extern crate serde_derive;

/// Test that we do not lint for unused underscores in a `MacroAttribute`
/// expansion
#[deny(clippy::used_underscore_binding)]
#[derive(Deserialize)]
struct MacroAttributesTest {
    _foo: u32,
}

#[test]
fn macro_attributes_test() {
    let _ = MacroAttributesTest { _foo: 0 };
}

fn main() {}
<|endoftext|>


<commit_before>use std::io::{ Write, LineWriter, Error };
use std::result::Result;
use std::fs::File;
use std::collections::HashMap;

static STACK_POINTER: &'static str = "SP";

lazy_static! {
    static ref MEMORY_SEGMENT_BASE: HashMap<&'static str, &'static str> = {
        let mut map = HashMap::new();
        map.insert("local", "LCL");
        map.insert("argument", "ARG");
        map.insert("this", "THIS");
        map.insert("that", "THAT");
        map.insert("temp", "5"); // this is very special segment
        map
    };
}

pub struct CodeWriter {
    target_descriptor: LineWriter<File>
}

impl CodeWriter {
    // Opens the output file, and gets ready to write into it
    pub fn new(target_file : String) -> Result<Self, Error> {
        let file = File::create(target_file)?;
        let line_writer = LineWriter::new(file);

        Ok( CodeWriter{ target_descriptor: line_writer } )
    }

    // Writes to the file assembly code which represents current arithmetic command
    pub fn write_arithmetic(&mut self, raw : &String, opcode : &String) {
        let helper_comment = format!("// {}\n", raw);
        let code = format!("opcode is {:?}\n", opcode);
        self.target_descriptor.write(&helper_comment.into_bytes());
        self.target_descriptor.write(&code.into_bytes());
    }

    // Writes assembly for push and pop commands
    pub fn write_push(&mut self, raw : &String, segment : &String, index : &usize) {
        let helper_comment = format!("// {}\n", raw);
        self.target_descriptor.write(&helper_comment.into_bytes());

        if segment.starts_with("constant") {
            let at = format!("@{}\n", index);
            self.target_descriptor.write(&at.into_bytes());

            let action = format!("D=A\n");
            self.target_descriptor.write(&action.into_bytes());

            let set_stack_pointer = format!("@{}\n", STACK_POINTER);
            self.target_descriptor.write(&set_stack_pointer.into_bytes());

            let move_address_to_current_stack_pointer = format!("A=M\n");
            self.target_descriptor.write(&move_address_to_current_stack_pointer.into_bytes());

            let move_value_to_stack = format!("M=D\n");
            self.target_descriptor.write(&move_value_to_stack.into_bytes());

            let set_stack_pointer = format!("@{}\n", STACK_POINTER);
            self.target_descriptor.write(&set_stack_pointer.into_bytes());

            let bump_stack_pointer = format!("M=M+1\n");
            self.target_descriptor.write(&bump_stack_pointer.into_bytes());
        } else if segment.starts_with("local") || segment.starts_with("argument") ||
        segment.starts_with("this") || segment.starts_with("that") || segment.starts_with("temp") {
            let code = format!(
                "@{index}
D=A // save shift from base to D register
@{local_base}
D=D+M // save shift + base_address to D register
A=D // set memory to shift + base_address
D=M // save content of memory to D register
@{stack_pointer} // set addr to stack_pointer
A=M // move to this cell
M=D // set content of this cell in stack to be conent of memory segment
@{stack_pointer}
M=M+1 // bump stack_pointe, so it points to new empty mem_cell
",
                index=index,
                local_base=MEMORY_SEGMENT_BASE.get::<str>(&segment).unwrap(),
                stack_pointer=STACK_POINTER
            );
            self.target_descriptor.write(&code.into_bytes());

        } else if segment.starts_with("static") {
            let code = format!(
                    "@Foo.{index}
D=M // save static var to D reg
@{stack_pointer}
M=D // go to current stack pointer
A=M // follow pointer to current free cell
M=D // fill this cell with static var value
@{stack_pointer}
M=M+1 // bump stack pointer
",
                index=index,
                stack_pointer=STACK_POINTER
            );
            self.target_descriptor.write(&code.into_bytes());
        } else if segment.starts_with("pointer") {
            let code = format!(
                "@{segment}
D=M // put this/that pointer base into D

@{stack_pointer}
A=M // Follow stack pointer to current free memory cell
M=D // Set value of this cell to be this/that

@{stack_pointer}
M=M+1 // bump stack pointer
",
                segment=if *index == (0 as usize) {
                    MEMORY_SEGMENT_BASE.get::<str>("this").unwrap()
                } else {
                    MEMORY_SEGMENT_BASE.get::<str>("that").unwrap()
                },
                stack_pointer=STACK_POINTER
            );

            self.target_descriptor.write(&code.into_bytes());
        }
    }

    // Writes assembly for push and pop commands
    pub fn write_pop(&mut self, raw : &String, segment : &String, index : &usize) {
        let helper_comment = format!("// {}\n", raw);
        self.target_descriptor.write(&helper_comment.into_bytes());

        if segment.starts_with("this") || segment.starts_with("that") ||
            segment.starts_with("local") || segment.starts_with("argument") || segment.starts_with("temp") {
                // works for local segment
                let code = format!(
                    "@{index}
D=A // save shift from base to D register
@{local_base}
D=D+M // save shift + base_address to D register
@{tmp_register}
M=D // save pop target to @R13
@{stack_pointer} // set addr to stack_pointer
M=M-1 // unbump stack_pointer, so it points to last real value
A=M // follow stack pointer and see what we have there
D=M // put
@{tmp_register}
A=M // jump to target we saved in R13
M=D // put value popped out of a stack to target memory cell
",
                    index=index,
                    local_base=MEMORY_SEGMENT_BASE.get::<str>(&segment).unwrap(),
                    tmp_register="R13",
                    stack_pointer=STACK_POINTER
                );
                self.target_descriptor.write(&code.into_bytes());
            } else if segment.starts_with("static") {
                let code = format!(
                    "@{stack_pointer}
M=M-1 // unbump stack pointer
A=M // follow pointer
D=M // save it in D register
@Foo.{index}
M=D // save D reg value in static var
",
                    index=index,
                    stack_pointer=STACK_POINTER
                );
                self.target_descriptor.write(&code.into_bytes());
            } else if segment.starts_with("pointer") {
                let code = format!(
                    "@{stack_pointer}
M=M-1 // unbump stack pointer to point to last real value
A=M // Follow stack pointer to memory cell
D=M // Set D register to contain required value

@{segment}
M=D // put D reg value to this/that
",
                    segment=if *index == (0 as usize) {
                        MEMORY_SEGMENT_BASE.get::<str>("this").unwrap()
                    } else {
                        MEMORY_SEGMENT_BASE.get::<str>("that").unwrap()
                    },
                    stack_pointer=STACK_POINTER
                );

                self.target_descriptor.write(&code.into_bytes());
            }
    }
}
<commit_msg>draft of arithmetic operation<commit_after>use std::io::{ Write, LineWriter, Error };
use std::result::Result;
use std::fs::File;
use std::collections::HashMap;

static STACK_POINTER: &'static str = "SP";

lazy_static! {
    static ref MEMORY_SEGMENT_BASE: HashMap<&'static str, &'static str> = {
        let mut map = HashMap::new();
        map.insert("local", "LCL");
        map.insert("argument", "ARG");
        map.insert("this", "THIS");
        map.insert("that", "THAT");
        map.insert("temp", "5"); // this is very special segment
        map
    };
}

pub struct CodeWriter {
    target_descriptor: LineWriter<File>
}

impl CodeWriter {
    // Opens the output file, and gets ready to write into it
    pub fn new(target_file : String) -> Result<Self, Error> {
        let file = File::create(target_file)?;
        let line_writer = LineWriter::new(file);

        Ok( CodeWriter{ target_descriptor: line_writer } )
    }

    // Writes to the file assembly code which represents current arithmetic command
    pub fn write_arithmetic(&mut self, raw : &String, opcode : &String) {
        let helper_comment = format!("// {}\n", raw);
        self.target_descriptor.write(&helper_comment.into_bytes());

        let code = format!(
            "@{stack_pointer}
M=M-1
A=M
D=M // take first argument for operation

@{register1}
M=D

@{stack_pointer}
M=M-1
A=M
D=M // take second argument for operation

@{register1}
D=D-M // perform your action

@{stack_pointer}
A=M // move to memory cell pointed by stack_pointer
M=D // put operation result to this cell",
            stack_pointer=STACK_POINTER,
            register1="R13"
        );
        self.target_descriptor.write(&code.into_bytes());
    }

    // Writes assembly for push and pop commands
    pub fn write_push(&mut self, raw : &String, segment : &String, index : &usize) {
        let helper_comment = format!("// {}\n", raw);
        self.target_descriptor.write(&helper_comment.into_bytes());

        if segment.starts_with("constant") {
            let at = format!("@{}\n", index);
            self.target_descriptor.write(&at.into_bytes());

            let action = format!("D=A\n");
            self.target_descriptor.write(&action.into_bytes());

            let set_stack_pointer = format!("@{}\n", STACK_POINTER);
            self.target_descriptor.write(&set_stack_pointer.into_bytes());

            let move_address_to_current_stack_pointer = format!("A=M\n");
            self.target_descriptor.write(&move_address_to_current_stack_pointer.into_bytes());

            let move_value_to_stack = format!("M=D\n");
            self.target_descriptor.write(&move_value_to_stack.into_bytes());

            let set_stack_pointer = format!("@{}\n", STACK_POINTER);
            self.target_descriptor.write(&set_stack_pointer.into_bytes());

            let bump_stack_pointer = format!("M=M+1\n");
            self.target_descriptor.write(&bump_stack_pointer.into_bytes());
        } else if segment.starts_with("local") || segment.starts_with("argument") ||
        segment.starts_with("this") || segment.starts_with("that") || segment.starts_with("temp") {
            let code = format!(
                "@{index}
D=A // save shift from base to D register
@{local_base}
D=D+M // save shift + base_address to D register
A=D // set memory to shift + base_address
D=M // save content of memory to D register
@{stack_pointer} // set addr to stack_pointer
A=M // move to this cell
M=D // set content of this cell in stack to be conent of memory segment
@{stack_pointer}
M=M+1 // bump stack_pointe, so it points to new empty mem_cell
",
                index=index,
                local_base=MEMORY_SEGMENT_BASE.get::<str>(&segment).unwrap(),
                stack_pointer=STACK_POINTER
            );
            self.target_descriptor.write(&code.into_bytes());

        } else if segment.starts_with("static") {
            let code = format!(
                    "@Foo.{index}
D=M // save static var to D reg
@{stack_pointer}
M=D // go to current stack pointer
A=M // follow pointer to current free cell
M=D // fill this cell with static var value
@{stack_pointer}
M=M+1 // bump stack pointer
",
                index=index,
                stack_pointer=STACK_POINTER
            );
            self.target_descriptor.write(&code.into_bytes());
        } else if segment.starts_with("pointer") {
            let code = format!(
                "@{segment}
D=M // put this/that pointer base into D

@{stack_pointer}
A=M // Follow stack pointer to current free memory cell
M=D // Set value of this cell to be this/that

@{stack_pointer}
M=M+1 // bump stack pointer
",
                segment=if *index == (0 as usize) {
                    MEMORY_SEGMENT_BASE.get::<str>("this").unwrap()
                } else {
                    MEMORY_SEGMENT_BASE.get::<str>("that").unwrap()
                },
                stack_pointer=STACK_POINTER
            );

            self.target_descriptor.write(&code.into_bytes());
        }
    }

    // Writes assembly for push and pop commands
    pub fn write_pop(&mut self, raw : &String, segment : &String, index : &usize) {
        let helper_comment = format!("// {}\n", raw);
        self.target_descriptor.write(&helper_comment.into_bytes());

        if segment.starts_with("this") || segment.starts_with("that") ||
            segment.starts_with("local") || segment.starts_with("argument") || segment.starts_with("temp") {
                // works for local segment
                let code = format!(
                    "@{index}
D=A // save shift from base to D register
@{local_base}
D=D+M // save shift + base_address to D register
@{tmp_register}
M=D // save pop target to @R13
@{stack_pointer} // set addr to stack_pointer
M=M-1 // unbump stack_pointer, so it points to last real value
A=M // follow stack pointer and see what we have there
D=M // put
@{tmp_register}
A=M // jump to target we saved in R13
M=D // put value popped out of a stack to target memory cell
",
                    index=index,
                    local_base=MEMORY_SEGMENT_BASE.get::<str>(&segment).unwrap(),
                    tmp_register="R13",
                    stack_pointer=STACK_POINTER
                );
                self.target_descriptor.write(&code.into_bytes());
            } else if segment.starts_with("static") {
                let code = format!(
                    "@{stack_pointer}
M=M-1 // unbump stack pointer
A=M // follow pointer
D=M // save it in D register
@Foo.{index}
M=D // save D reg value in static var
",
                    index=index,
                    stack_pointer=STACK_POINTER
                );
                self.target_descriptor.write(&code.into_bytes());
            } else if segment.starts_with("pointer") {
                let code = format!(
                    "@{stack_pointer}
M=M-1 // unbump stack pointer to point to last real value
A=M // Follow stack pointer to memory cell
D=M // Set D register to contain required value

@{segment}
M=D // put D reg value to this/that
",
                    segment=if *index == (0 as usize) {
                        MEMORY_SEGMENT_BASE.get::<str>("this").unwrap()
                    } else {
                        MEMORY_SEGMENT_BASE.get::<str>("that").unwrap()
                    },
                    stack_pointer=STACK_POINTER
                );

                self.target_descriptor.write(&code.into_bytes());
            }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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 capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;
use calculator_capnp::calculator;
use gj::Promise;

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

impl calculator::function::Server for PowerFunction {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, ::capnp::Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(::capnp::Error::failed("Wrong number of parameters".to_string()))
        } else {
            results.get().set_value(params.get(0).powf(params.get(1)));
            Promise::ok(results)
        }
    }
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} client HOST:PORT", args[0]);
        return;
    }

    ::gj::EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let (reader, writer) = try!(::gj::io::tcp::Stream::connect(addr).wait(wait_scope)).split();
        let network =
            Box::new(twoparty::VatNetwork::new(reader, writer,
                                               rpc_twoparty_capnp::Side::Client,
                                               Default::default()));
        let mut rpc_system = rpc::System::new(network, None);
        let calculator: calculator::Client = rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server);

        {
            println!("Evaluating a literal...");
            let mut request = calculator.evaluate_request();
            request.get().init_expression().set_literal(123.0);
            let value = request.send().pipeline.get_value();
            let request = value.read_request();
            try!(request.send().promise.then(|response|{
                assert_eq!(pry!(response.get()).get_value(), 123.0);
                Promise::ok(())
            }).wait(wait_scope));
            println!("PASS");
        }

        {
            // Make a request to evaluate 123 + 45 - 67.
            //
            // The Calculator interface requires that we first call getOperator() to
            // get the addition and subtraction functions, then call evaluate() to use
            // them.  But, once again, we can get both functions, call evaluate(), and
            // then read() the result -- four RPCs -- in the time of *one* network
            // round trip, because of promise pipelining.

            println!("Using add and subtract... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let subtract = {
                // Get the "subtract" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Subtract);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 123 + 45 - 67.
            let mut request = calculator.evaluate_request();

            {
                let mut subtract_call = request.get().init_expression().init_call();
                subtract_call.set_function(subtract);
                let mut subtract_params = subtract_call.init_params(2);
                subtract_params.borrow().get(1).set_literal(67.0);

                let mut add_call = subtract_params.get(0).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(123.0);
                add_params.get(1).set_literal(45.0);
            }

            // Send the evaluate() request, read() the result, and wait for read() to
            // finish.
            let eval_promise = request.send();
            let read_promise = eval_promise.pipeline.get_value().read_request().send();

            let response = try!(read_promise.promise.wait(wait_scope));
            assert_eq!(try!(response.get()).get_value(), 101.0);

            println!("PASS");
        }

        {
            // Make a request to evaluate 4 * 6, then use the result in two more
            // requests that add 3 and 5.
            //
            // Since evaluate() returns its result wrapped in a `Value`, we can pass
            // that `Value` back to the server in subsequent requests before the first
            // `evaluate()` has actually returned.  Thus, this example again does only
            // one network round trip.

            println!("Pipelining eval() calls... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                // Get the "multiply" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 4 * 6
            let mut request = calculator.evaluate_request();

            {
                let mut multiply_call = request.get().init_expression().init_call();
                multiply_call.set_function(multiply);
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(0).set_literal(4.0);
                multiply_params.borrow().get(1).set_literal(6.0);
            }

            let multiply_result = request.send().pipeline.get_value();

            // Use the result in two calls that add 3 and add 5.
            let mut add3_request = calculator.evaluate_request();
            {
                let mut add3_call = add3_request.get().init_expression().init_call();
                add3_call.set_function(add.clone());
                let mut add3_params = add3_call.init_params(2);
                add3_params.borrow().get(0).set_previous_result(multiply_result.clone());
                add3_params.borrow().get(1).set_literal(3.0);
            }

            let add3_promise = add3_request.send().pipeline.get_value().read_request().send();

            let mut add5_request = calculator.evaluate_request();
            {
                let mut add5_call = add5_request.get().init_expression().init_call();
                add5_call.set_function(add);
                let mut add5_params = add5_call.init_params(2);
                add5_params.borrow().get(0).set_previous_result(multiply_result);
                add5_params.get(1).set_literal(5.0);
            }

            let add5_promise = add5_request.send().pipeline.get_value().read_request().send();

            // Now wait for the results.
            assert!(try!(try!(add3_promise.promise.wait(wait_scope)).get()).get_value() == 27.0);
            assert!(try!(try!(add5_promise.promise.wait(wait_scope)).get()).get_value() == 29.0);

            println!("PASS")
        }

        {
            // Our calculator interface supports defining functions.  Here we use it
            // to define two functions and then make calls to them as follows:
            //
            //   f(x, y) = x * 100 + y
            //   g(x) = f(x, x + 1) * 2;
            //   f(12, 34)
            //   g(21)
            //
            // Once again, the whole thing takes only one network round trip.

            println!("Defining functions... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            let f = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(2);
                    {
                        let mut add_call = def_function_params.init_body().init_call();
                        add_call.set_function(add.clone());
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(1).set_parameter(1);

                        let mut multiply_call = add_params.get(0).init_call();
                        multiply_call.set_function(multiply.clone());
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(0).set_parameter(0);
                        multiply_params.get(1).set_literal(100.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let g = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(1);
                    {
                        let mut multiply_call = def_function_params.init_body().init_call();
                        multiply_call.set_function(multiply);
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(1).set_literal(2.0);

                        let mut f_call = multiply_params.get(0).init_call();
                        f_call.set_function(f.clone());
                        let mut f_params = f_call.init_params(2);
                        f_params.borrow().get(0).set_parameter(0);

                        let mut add_call = f_params.get(1).init_call();
                        add_call.set_function(add);
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(0).set_parameter(0);
                        add_params.get(1).set_literal(1.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let mut f_eval_request = calculator.evaluate_request();
            {
                let mut f_call = f_eval_request.get().init_expression().init_call();
                f_call.set_function(f);
                let mut f_params = f_call.init_params(2);
                f_params.borrow().get(0).set_literal(12.0);
                f_params.get(1).set_literal(34.0);
            }
            let f_eval_promise = f_eval_request.send().pipeline.get_value().read_request().send();

            let mut g_eval_request = calculator.evaluate_request();
            {
                let mut g_call = g_eval_request.get().init_expression().init_call();
                g_call.set_function(g);
                g_call.init_params(1).get(0).set_literal(21.0);
            }
            let g_eval_promise = g_eval_request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(f_eval_promise.promise.wait(wait_scope)).get()).get_value() == 1234.0);
            assert!(try!(try!(g_eval_promise.promise.wait(wait_scope)).get()).get_value() == 4244.0);

            println!("PASS")
        }

        {
            // Make a request that will call back to a function defined locally.
            //
            // Specifically, we will compute 2^(4 + 5).  However, exponent is not
            // defined by the Calculator server.  So, we'll implement the Function
            // interface locally and pass it to the server for it to use when
            // evaluating the expression.
            //
            // This example requires two network round trips to complete, because the
            // server calls back to the client once before finishing.  In this
            // particular case, this could potentially be optimized by using a tail
            // call on the server side -- see CallContext::tailCall().  However, to
            // keep the example simpler, we haven't implemented this optimization in
            // the sample server.

            println!("Using a callback... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let mut request = calculator.evaluate_request();
            {
                let mut pow_call = request.get().init_expression().init_call();
                pow_call.set_function(
                    calculator::function::ToClient::new(PowerFunction).from_server::<LocalClient>());
                let mut pow_params = pow_call.init_params(2);
                pow_params.borrow().get(0).set_literal(2.0);

                let mut add_call = pow_params.get(1).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(4.0);
                add_params.get(1).set_literal(5.0);
            }

            let response_promise = request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(response_promise.promise.wait(wait_scope)).get()).get_value() == 512.0);

            println!("PASS");
        }

        Ok(())
    }).expect("top level error");
}
<commit_msg>add missing calculator-client comment<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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 capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;
use calculator_capnp::calculator;
use gj::Promise;

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

impl calculator::function::Server for PowerFunction {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, ::capnp::Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(::capnp::Error::failed("Wrong number of parameters".to_string()))
        } else {
            results.get().set_value(params.get(0).powf(params.get(1)));
            Promise::ok(results)
        }
    }
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} client HOST:PORT", args[0]);
        return;
    }

    ::gj::EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let (reader, writer) = try!(::gj::io::tcp::Stream::connect(addr).wait(wait_scope)).split();
        let network =
            Box::new(twoparty::VatNetwork::new(reader, writer,
                                               rpc_twoparty_capnp::Side::Client,
                                               Default::default()));
        let mut rpc_system = rpc::System::new(network, None);
        let calculator: calculator::Client = rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server);

        {
            // Make a request that just evaluates the literal value 123.
            //
            // What's interesting here is that evaluate() returns a "Value", which is
            // another interface and therefore points back to an object living on the
            // server.  We then have to call read() on that object to read it.
            // However, even though we are making two RPC's, this block executes in
            // *one* network round trip because of promise pipelining:  we do not wait
            // for the first call to complete before we send the second call to the
            // server.

            println!("Evaluating a literal...");
            let mut request = calculator.evaluate_request();
            request.get().init_expression().set_literal(123.0);
            let value = request.send().pipeline.get_value();
            let request = value.read_request();
            try!(request.send().promise.then(|response|{
                assert_eq!(pry!(response.get()).get_value(), 123.0);
                Promise::ok(())
            }).wait(wait_scope));
            println!("PASS");
        }

        {
            // Make a request to evaluate 123 + 45 - 67.
            //
            // The Calculator interface requires that we first call getOperator() to
            // get the addition and subtraction functions, then call evaluate() to use
            // them.  But, once again, we can get both functions, call evaluate(), and
            // then read() the result -- four RPCs -- in the time of *one* network
            // round trip, because of promise pipelining.

            println!("Using add and subtract... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let subtract = {
                // Get the "subtract" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Subtract);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 123 + 45 - 67.
            let mut request = calculator.evaluate_request();

            {
                let mut subtract_call = request.get().init_expression().init_call();
                subtract_call.set_function(subtract);
                let mut subtract_params = subtract_call.init_params(2);
                subtract_params.borrow().get(1).set_literal(67.0);

                let mut add_call = subtract_params.get(0).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(123.0);
                add_params.get(1).set_literal(45.0);
            }

            // Send the evaluate() request, read() the result, and wait for read() to
            // finish.
            let eval_promise = request.send();
            let read_promise = eval_promise.pipeline.get_value().read_request().send();

            let response = try!(read_promise.promise.wait(wait_scope));
            assert_eq!(try!(response.get()).get_value(), 101.0);

            println!("PASS");
        }

        {
            // Make a request to evaluate 4 * 6, then use the result in two more
            // requests that add 3 and 5.
            //
            // Since evaluate() returns its result wrapped in a `Value`, we can pass
            // that `Value` back to the server in subsequent requests before the first
            // `evaluate()` has actually returned.  Thus, this example again does only
            // one network round trip.

            println!("Pipelining eval() calls... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                // Get the "multiply" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 4 * 6
            let mut request = calculator.evaluate_request();

            {
                let mut multiply_call = request.get().init_expression().init_call();
                multiply_call.set_function(multiply);
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(0).set_literal(4.0);
                multiply_params.borrow().get(1).set_literal(6.0);
            }

            let multiply_result = request.send().pipeline.get_value();

            // Use the result in two calls that add 3 and add 5.
            let mut add3_request = calculator.evaluate_request();
            {
                let mut add3_call = add3_request.get().init_expression().init_call();
                add3_call.set_function(add.clone());
                let mut add3_params = add3_call.init_params(2);
                add3_params.borrow().get(0).set_previous_result(multiply_result.clone());
                add3_params.borrow().get(1).set_literal(3.0);
            }

            let add3_promise = add3_request.send().pipeline.get_value().read_request().send();

            let mut add5_request = calculator.evaluate_request();
            {
                let mut add5_call = add5_request.get().init_expression().init_call();
                add5_call.set_function(add);
                let mut add5_params = add5_call.init_params(2);
                add5_params.borrow().get(0).set_previous_result(multiply_result);
                add5_params.get(1).set_literal(5.0);
            }

            let add5_promise = add5_request.send().pipeline.get_value().read_request().send();

            // Now wait for the results.
            assert!(try!(try!(add3_promise.promise.wait(wait_scope)).get()).get_value() == 27.0);
            assert!(try!(try!(add5_promise.promise.wait(wait_scope)).get()).get_value() == 29.0);

            println!("PASS")
        }

        {
            // Our calculator interface supports defining functions.  Here we use it
            // to define two functions and then make calls to them as follows:
            //
            //   f(x, y) = x * 100 + y
            //   g(x) = f(x, x + 1) * 2;
            //   f(12, 34)
            //   g(21)
            //
            // Once again, the whole thing takes only one network round trip.

            println!("Defining functions... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            let f = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(2);
                    {
                        let mut add_call = def_function_params.init_body().init_call();
                        add_call.set_function(add.clone());
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(1).set_parameter(1);

                        let mut multiply_call = add_params.get(0).init_call();
                        multiply_call.set_function(multiply.clone());
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(0).set_parameter(0);
                        multiply_params.get(1).set_literal(100.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let g = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(1);
                    {
                        let mut multiply_call = def_function_params.init_body().init_call();
                        multiply_call.set_function(multiply);
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(1).set_literal(2.0);

                        let mut f_call = multiply_params.get(0).init_call();
                        f_call.set_function(f.clone());
                        let mut f_params = f_call.init_params(2);
                        f_params.borrow().get(0).set_parameter(0);

                        let mut add_call = f_params.get(1).init_call();
                        add_call.set_function(add);
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(0).set_parameter(0);
                        add_params.get(1).set_literal(1.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let mut f_eval_request = calculator.evaluate_request();
            {
                let mut f_call = f_eval_request.get().init_expression().init_call();
                f_call.set_function(f);
                let mut f_params = f_call.init_params(2);
                f_params.borrow().get(0).set_literal(12.0);
                f_params.get(1).set_literal(34.0);
            }
            let f_eval_promise = f_eval_request.send().pipeline.get_value().read_request().send();

            let mut g_eval_request = calculator.evaluate_request();
            {
                let mut g_call = g_eval_request.get().init_expression().init_call();
                g_call.set_function(g);
                g_call.init_params(1).get(0).set_literal(21.0);
            }
            let g_eval_promise = g_eval_request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(f_eval_promise.promise.wait(wait_scope)).get()).get_value() == 1234.0);
            assert!(try!(try!(g_eval_promise.promise.wait(wait_scope)).get()).get_value() == 4244.0);

            println!("PASS")
        }

        {
            // Make a request that will call back to a function defined locally.
            //
            // Specifically, we will compute 2^(4 + 5).  However, exponent is not
            // defined by the Calculator server.  So, we'll implement the Function
            // interface locally and pass it to the server for it to use when
            // evaluating the expression.
            //
            // This example requires two network round trips to complete, because the
            // server calls back to the client once before finishing.  In this
            // particular case, this could potentially be optimized by using a tail
            // call on the server side -- see CallContext::tailCall().  However, to
            // keep the example simpler, we haven't implemented this optimization in
            // the sample server.

            println!("Using a callback... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let mut request = calculator.evaluate_request();
            {
                let mut pow_call = request.get().init_expression().init_call();
                pow_call.set_function(
                    calculator::function::ToClient::new(PowerFunction).from_server::<LocalClient>());
                let mut pow_params = pow_call.init_params(2);
                pow_params.borrow().get(0).set_literal(2.0);

                let mut add_call = pow_params.get(1).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(4.0);
                add_params.get(1).set_literal(5.0);
            }

            let response_promise = request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(response_promise.promise.wait(wait_scope)).get()).get_value() == 512.0);

            println!("PASS");
        }

        Ok(())
    }).expect("top level error");
}
<|endoftext|>


<commit_before>#![feature(test)]
#![cfg_attr(all(feature="i128_support", feature="nightly"), allow(stable_features))] // stable since 2018-03-27
#![cfg_attr(all(feature="i128_support", feature="nightly"), feature(i128_type, i128))]

extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 1000;

use std::mem::size_of;
use test::Bencher;
use std::time::Duration;

use rand::{Rng, FromEntropy};
use rand::rngs::SmallRng;
use rand::distributions::*;

macro_rules! distr_int {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0 as $ty;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum.wrapping_add(x);
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr_float {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0.0;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum += x;
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr_duration {
    ($fnn:ident, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = Duration::new(0, 0);
                for _ in 0..::RAND_BENCH_N {
                    let x: Duration = distr.sample(&mut rng);
                    accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999));
                }
                accum
            });
            b.bytes = size_of::<Duration>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0u32;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum.wrapping_add(x as u32);
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

// uniform
distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100));
distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000));
distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000));
distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123));
#[cfg(feature = "i128_support")]
distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789));

distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319));
distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319));

distr_duration!(distr_uniform_duration_largest, Uniform::new(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999)));
distr_duration!(distr_uniform_duration_large, Uniform::new(Duration::new(0, 0), Duration::new(u64::max_value()/1000, 1_000_000_000/2)));
distr_duration!(distr_uniform_duration_one, Uniform::new(Duration::new(0, 0), Duration::new(1, 0)));
distr_duration!(distr_uniform_duration_variety, Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954)));

// standard
distr_int!(distr_standard_i8, i8, Standard);
distr_int!(distr_standard_i16, i16, Standard);
distr_int!(distr_standard_i32, i32, Standard);
distr_int!(distr_standard_i64, i64, Standard);
#[cfg(feature = "i128_support")]
distr_int!(distr_standard_i128, i128, Standard);

distr!(distr_standard_bool, bool, Standard);
distr!(distr_standard_alphanumeric, char, Alphanumeric);
distr!(distr_standard_codepoint, char, Standard);

distr_float!(distr_standard_f32, f32, Standard);
distr_float!(distr_standard_f64, f64, Standard);
distr_float!(distr_open01_f32, f32, Open01);
distr_float!(distr_open01_f64, f64, Open01);
distr_float!(distr_openclosed01_f32, f32, OpenClosed01);
distr_float!(distr_openclosed01_f64, f64, OpenClosed01);

// distributions
distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56));
distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56));
distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56));
distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0));
distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0));
distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9));
distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
distr_int!(distr_poisson, u64, Poisson::new(4.0));
distr!(distr_bernoulli, bool, Bernoulli::new(0.18));

// Weighted
distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap());
distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap());

// construct and sample from a range
macro_rules! gen_range_int {
    ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();

            b.iter(|| {
                let mut high = $high;
                let mut accum: $ty = 0;
                for _ in 0..::RAND_BENCH_N {
                    accum = accum.wrapping_add(rng.gen_range($low, high));
                    // force recalculation of range each time
                    high = high.wrapping_add(1) & std::$ty::MAX;
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

gen_range_int!(gen_range_i8, i8, -20i8, 100);
gen_range_int!(gen_range_i16, i16, -500i16, 2000);
gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000);
gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123);
#[cfg(feature = "i128_support")]
gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789);

// construct and sample from a floating-point range
macro_rules! gen_range_float {
    ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();

            b.iter(|| {
                let mut high = $high;
                let mut low = $low;
                let mut accum: $ty = 0.0;
                for _ in 0..::RAND_BENCH_N {
                    accum += rng.gen_range(low, high);
                    // force recalculation of range each time
                    low += 0.9;
                    high += 1.1;
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0);
gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12);

#[bench]
fn dist_iter(b: &mut Bencher) {
    let mut rng = SmallRng::from_entropy();
    let distr = Normal::new(-2.71828, 3.14159);
    let mut iter = distr.sample_iter(&mut rng);

    b.iter(|| {
        let mut accum = 0.0;
        for _ in 0..::RAND_BENCH_N {
            accum += iter.next().unwrap();
        }
        accum
    });
    b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
}
<commit_msg>Improve benches for uniform duration<commit_after>#![feature(test)]
#![cfg_attr(all(feature="i128_support", feature="nightly"), allow(stable_features))] // stable since 2018-03-27
#![cfg_attr(all(feature="i128_support", feature="nightly"), feature(i128_type, i128))]

extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 1000;

use std::mem::size_of;
use test::Bencher;
use std::time::Duration;

use rand::{Rng, FromEntropy};
use rand::rngs::SmallRng;
use rand::distributions::*;

macro_rules! distr_int {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0 as $ty;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum.wrapping_add(x);
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr_float {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0.0;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum += x;
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr_duration {
    ($fnn:ident, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = Duration::new(0, 0);
                for _ in 0..::RAND_BENCH_N {
                    let x: Duration = distr.sample(&mut rng);
                    accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999));
                }
                accum
            });
            b.bytes = size_of::<Duration>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0u32;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum.wrapping_add(x as u32);
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

// uniform
distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100));
distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000));
distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000));
distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123));
#[cfg(feature = "i128_support")]
distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789));

distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319));
distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319));

distr_duration!(distr_uniform_duration_largest,
    Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))
);
distr_duration!(distr_uniform_duration_large,
    Uniform::new(Duration::new(0, 0), Duration::new(u64::max_value() / 1000, 1_000_000_000 / 2))
);
distr_duration!(distr_uniform_duration_one,
    Uniform::new(Duration::new(0, 0), Duration::new(1, 0))
);
distr_duration!(distr_uniform_duration_variety,
    Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954))
);
distr_duration!(distr_uniform_duration_edge,
    Uniform::new_inclusive(Duration::new(u64::max_value() / 10, 999_999_999), Duration::new((u64::max_value() / 10) + 1, 0))
);

// standard
distr_int!(distr_standard_i8, i8, Standard);
distr_int!(distr_standard_i16, i16, Standard);
distr_int!(distr_standard_i32, i32, Standard);
distr_int!(distr_standard_i64, i64, Standard);
#[cfg(feature = "i128_support")]
distr_int!(distr_standard_i128, i128, Standard);

distr!(distr_standard_bool, bool, Standard);
distr!(distr_standard_alphanumeric, char, Alphanumeric);
distr!(distr_standard_codepoint, char, Standard);

distr_float!(distr_standard_f32, f32, Standard);
distr_float!(distr_standard_f64, f64, Standard);
distr_float!(distr_open01_f32, f32, Open01);
distr_float!(distr_open01_f64, f64, Open01);
distr_float!(distr_openclosed01_f32, f32, OpenClosed01);
distr_float!(distr_openclosed01_f64, f64, OpenClosed01);

// distributions
distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56));
distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56));
distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56));
distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0));
distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0));
distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9));
distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
distr_int!(distr_poisson, u64, Poisson::new(4.0));
distr!(distr_bernoulli, bool, Bernoulli::new(0.18));

// Weighted
distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap());
distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap());
distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap());

// construct and sample from a range
macro_rules! gen_range_int {
    ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();

            b.iter(|| {
                let mut high = $high;
                let mut accum: $ty = 0;
                for _ in 0..::RAND_BENCH_N {
                    accum = accum.wrapping_add(rng.gen_range($low, high));
                    // force recalculation of range each time
                    high = high.wrapping_add(1) & std::$ty::MAX;
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

gen_range_int!(gen_range_i8, i8, -20i8, 100);
gen_range_int!(gen_range_i16, i16, -500i16, 2000);
gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000);
gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123);
#[cfg(feature = "i128_support")]
gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789);

// construct and sample from a floating-point range
macro_rules! gen_range_float {
    ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = SmallRng::from_entropy();

            b.iter(|| {
                let mut high = $high;
                let mut low = $low;
                let mut accum: $ty = 0.0;
                for _ in 0..::RAND_BENCH_N {
                    accum += rng.gen_range(low, high);
                    // force recalculation of range each time
                    low += 0.9;
                    high += 1.1;
                }
                accum
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0);
gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12);

#[bench]
fn dist_iter(b: &mut Bencher) {
    let mut rng = SmallRng::from_entropy();
    let distr = Normal::new(-2.71828, 3.14159);
    let mut iter = distr.sample_iter(&mut rng);

    b.iter(|| {
        let mut accum = 0.0;
        for _ in 0..::RAND_BENCH_N {
            accum += iter.next().unwrap();
        }
        accum
    });
    b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::marker::PhantomData;
use std::mem;
use std::net::Ipv6Addr;
use std::ptr;
use std::slice;

use types::{
    AresError,
    hostent,
};
use utils::ares_error;

/// The result of a successful lookup for an AAAA record.
pub struct AAAAResults {
    hostent: *mut hostent,
}

impl AAAAResults {
    /// Obtain an `AAAAResults` from the response to an AAAA lookup.
    pub fn parse_from(data: &[u8]) -> Result<AAAAResults, AresError> {
        let mut hostent: *mut hostent = ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_aaaa_reply(
                data.as_ptr(),
                data.len() as libc::c_int,
                &mut hostent as *mut *mut _ as *mut *mut c_ares_sys::Struct_hostent,
                ptr::null_mut(),
                ptr::null_mut())
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let result = AAAAResults::new(hostent);
            Ok(result)
        }
    }
    fn new(hostent: *mut hostent) -> AAAAResults {
        AAAAResults {
            hostent: hostent,
        }
    }

    /// Returns an iterator over the `Ipv6Address` values in this `AResult`.
    pub fn iter(&self) -> AAAAResultsIterator {
        AAAAResultsIterator {
            next: unsafe { (*self.hostent).h_addr_list },
            phantom: PhantomData,
        }
    }
}

pub struct AAAAResultsIntoIterator {
    next: *mut *mut libc::c_char,

    // Access to the IP addresses is all through the `next` pointer, but we
    // need to keep the AAAAResults around so that this points to valid memory.
    #[allow(dead_code)]
    a_result: AAAAResults,
}

pub struct AAAAResultsIterator<'a> {
    next: *mut *mut libc::c_char,

    // We need the phantom data to make sure that the `next` pointer remains
    // valid through the lifetime of this structure.
    phantom: PhantomData<&'a AAAAResults>,
}

impl IntoIterator for AAAAResults {
    type Item = Ipv6Addr;
    type IntoIter = AAAAResultsIntoIterator;

    fn into_iter(self) -> Self::IntoIter {
        AAAAResultsIntoIterator {
            next: unsafe { (*self.hostent).h_addr_list },
            a_result: self,
        }
    }
}

impl<'a> IntoIterator for &'a AAAAResults {
    type Item = Ipv6Addr;
    type IntoIter = AAAAResultsIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        AAAAResultsIterator {
            next: unsafe { (*self.hostent).h_addr_list },
            phantom: PhantomData,
        }
    }
}

unsafe fn ipv6_addr_from_ptr(h_addr: *mut libc::c_char) -> Ipv6Addr {
    Ipv6Addr::new(
        ((*h_addr as u16) << 8) + *h_addr.offset(1) as u16,
        ((*h_addr.offset(2) as u16) << 8) + *h_addr.offset(3) as u16,
        ((*h_addr.offset(4) as u16) << 8) + *h_addr.offset(5) as u16,
        ((*h_addr.offset(6) as u16) << 8) + *h_addr.offset(7) as u16,
        ((*h_addr.offset(8) as u16) << 8) + *h_addr.offset(9) as u16,
        ((*h_addr.offset(10) as u16) << 8) + *h_addr.offset(11) as u16,
        ((*h_addr.offset(12) as u16) << 8) + *h_addr.offset(13) as u16,
        ((*h_addr.offset(14) as u16) << 8) + *h_addr.offset(15) as u16)
}

impl Iterator for AAAAResultsIntoIterator {
    type Item = Ipv6Addr;
    fn next(&mut self) -> Option<Ipv6Addr> {
        unsafe {
            let h_addr = *(self.next);
            if h_addr.is_null() {
                None
            } else {
                self.next = self.next.offset(1);
                let ip_addr = ipv6_addr_from_ptr(h_addr);
                Some(ip_addr)
            }
        }
    }
}

impl<'a> Iterator for AAAAResultsIterator<'a> {
    type Item = Ipv6Addr;
    fn next(&mut self) -> Option<Ipv6Addr> {
        unsafe {
            let h_addr = *(self.next);
            if h_addr.is_null() {
                None
            } else {
                self.next = self.next.offset(1);
                let ip_addr = ipv6_addr_from_ptr(h_addr);
                Some(ip_addr)
            }
        }
    }
}

impl Drop for AAAAResults {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_hostent(
                self.hostent as *mut c_ares_sys::Struct_hostent);
        }
    }
}

pub unsafe extern "C" fn query_aaaa_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<AAAAResults, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let data = slice::from_raw_parts(abuf, alen as usize);
        AAAAResults::parse_from(data)
    };
    let handler: Box<F> = mem::transmute(arg);
    handler(result);
}
<commit_msg>Missed one in the rename<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::marker::PhantomData;
use std::mem;
use std::net::Ipv6Addr;
use std::ptr;
use std::slice;

use types::{
    AresError,
    hostent,
};
use utils::ares_error;

/// The result of a successful lookup for an AAAA record.
pub struct AAAAResults {
    hostent: *mut hostent,
}

impl AAAAResults {
    /// Obtain an `AAAAResults` from the response to an AAAA lookup.
    pub fn parse_from(data: &[u8]) -> Result<AAAAResults, AresError> {
        let mut hostent: *mut hostent = ptr::null_mut();
        let parse_status = unsafe {
            c_ares_sys::ares_parse_aaaa_reply(
                data.as_ptr(),
                data.len() as libc::c_int,
                &mut hostent as *mut *mut _ as *mut *mut c_ares_sys::Struct_hostent,
                ptr::null_mut(),
                ptr::null_mut())
        };
        if parse_status != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(parse_status))
        } else {
            let result = AAAAResults::new(hostent);
            Ok(result)
        }
    }
    fn new(hostent: *mut hostent) -> AAAAResults {
        AAAAResults {
            hostent: hostent,
        }
    }

    /// Returns an iterator over the `Ipv6Address` values in this
    /// `AAAAResults`.
    pub fn iter(&self) -> AAAAResultsIterator {
        AAAAResultsIterator {
            next: unsafe { (*self.hostent).h_addr_list },
            phantom: PhantomData,
        }
    }
}

pub struct AAAAResultsIntoIterator {
    next: *mut *mut libc::c_char,

    // Access to the IP addresses is all through the `next` pointer, but we
    // need to keep the AAAAResults around so that this points to valid memory.
    #[allow(dead_code)]
    a_result: AAAAResults,
}

pub struct AAAAResultsIterator<'a> {
    next: *mut *mut libc::c_char,

    // We need the phantom data to make sure that the `next` pointer remains
    // valid through the lifetime of this structure.
    phantom: PhantomData<&'a AAAAResults>,
}

impl IntoIterator for AAAAResults {
    type Item = Ipv6Addr;
    type IntoIter = AAAAResultsIntoIterator;

    fn into_iter(self) -> Self::IntoIter {
        AAAAResultsIntoIterator {
            next: unsafe { (*self.hostent).h_addr_list },
            a_result: self,
        }
    }
}

impl<'a> IntoIterator for &'a AAAAResults {
    type Item = Ipv6Addr;
    type IntoIter = AAAAResultsIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        AAAAResultsIterator {
            next: unsafe { (*self.hostent).h_addr_list },
            phantom: PhantomData,
        }
    }
}

unsafe fn ipv6_addr_from_ptr(h_addr: *mut libc::c_char) -> Ipv6Addr {
    Ipv6Addr::new(
        ((*h_addr as u16) << 8) + *h_addr.offset(1) as u16,
        ((*h_addr.offset(2) as u16) << 8) + *h_addr.offset(3) as u16,
        ((*h_addr.offset(4) as u16) << 8) + *h_addr.offset(5) as u16,
        ((*h_addr.offset(6) as u16) << 8) + *h_addr.offset(7) as u16,
        ((*h_addr.offset(8) as u16) << 8) + *h_addr.offset(9) as u16,
        ((*h_addr.offset(10) as u16) << 8) + *h_addr.offset(11) as u16,
        ((*h_addr.offset(12) as u16) << 8) + *h_addr.offset(13) as u16,
        ((*h_addr.offset(14) as u16) << 8) + *h_addr.offset(15) as u16)
}

impl Iterator for AAAAResultsIntoIterator {
    type Item = Ipv6Addr;
    fn next(&mut self) -> Option<Ipv6Addr> {
        unsafe {
            let h_addr = *(self.next);
            if h_addr.is_null() {
                None
            } else {
                self.next = self.next.offset(1);
                let ip_addr = ipv6_addr_from_ptr(h_addr);
                Some(ip_addr)
            }
        }
    }
}

impl<'a> Iterator for AAAAResultsIterator<'a> {
    type Item = Ipv6Addr;
    fn next(&mut self) -> Option<Ipv6Addr> {
        unsafe {
            let h_addr = *(self.next);
            if h_addr.is_null() {
                None
            } else {
                self.next = self.next.offset(1);
                let ip_addr = ipv6_addr_from_ptr(h_addr);
                Some(ip_addr)
            }
        }
    }
}

impl Drop for AAAAResults {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_hostent(
                self.hostent as *mut c_ares_sys::Struct_hostent);
        }
    }
}

pub unsafe extern "C" fn query_aaaa_callback<F>(
    arg: *mut libc::c_void,
    status: libc::c_int,
    _timeouts: libc::c_int,
    abuf: *mut libc::c_uchar,
    alen: libc::c_int)
    where F: FnOnce(Result<AAAAResults, AresError>) + 'static {
    let result = if status != c_ares_sys::ARES_SUCCESS {
        Err(ares_error(status))
    } else {
        let data = slice::from_raw_parts(abuf, alen as usize);
        AAAAResults::parse_from(data)
    };
    let handler: Box<F> = mem::transmute(arg);
    handler(result);
}
<|endoftext|>


<commit_before>use std::simd::u64x2;
use std::mem::{size_of, zeroed};

use stack::Stack;

extern "C" {
  #[link_name = "lwt_bootstrap"]
  pub fn bootstrap();
  #[link_name = "lwt_swapcontext"]
  pub fn swapcontext(save: *mut Registers, restore: *mut Registers);
  #[link_name = "lwt_get_sp_limit"]
  pub fn get_sp_limit() -> *const u8;
  #[link_name = "lwt_set_sp_limit"]
  pub fn set_sp_limit(limit: *const u8);
  #[link_name = "lwt_abort"]
  pub fn abort() -> !;
}

#[allow(non_camel_case_types)]
pub type uintptr_t = u64;

#[repr(C)]
#[allow(dead_code)]
pub struct Registers {
  rbx: u64,
  rsp: u64,
  rbp: u64,
  rdi: u64,
  r12: u64,
  r13: u64,
  r14: u64,
  r15: u64,
  ip:  u64,
  xmm0: u64x2,
  xmm1: u64x2,
  xmm2: u64x2,
  xmm3: u64x2,
  xmm4: u64x2,
  xmm5: u64x2,
}

impl Registers {
  pub fn new() -> Registers {
    unsafe {
      Registers {
        ip: abort as u64,
        .. zeroed()
      }
    }
  }
}

pub fn initialise_call_frame(stack: &mut Stack, init: uintptr_t, args: &[uintptr_t]) -> Registers {
  let sp = stack.top() as *mut uintptr_t;
  let sp = align_down_mut(sp, 16);
  let sp = offset_mut(sp, -1);
  unsafe {
    *sp = 0;
  }

  let mut regs = Registers {
    rbp: 0,
    rsp: sp as uintptr_t,
    ip: bootstrap as uintptr_t,
    rbx: init,
    .. Registers::new()
  };

  match into_fields!(regs { rdi, r12, r13, r14, r15 } <- args.iter().cloned()) {
    Some(mut args) => if args.next().is_some() {
      panic!("too many arguments")
    },
    None => {}
  }

  regs
}

#[inline]
fn align_down_mut<T>(sp: *mut T, n: uint) -> *mut T {
  let sp = (sp as uint) & !(n - 1);
  sp as *mut T
}

// ptr::offset_mmut is positive ints only
#[inline]
pub fn offset_mut<T>(ptr: *mut T, count: int) -> *mut T {
  (ptr as int + count * (size_of::<T>() as int)) as *mut T
}
<commit_msg>u64 -> uintptr_t<commit_after>use std::simd::u64x2;
use std::mem::{size_of, zeroed};

use stack::Stack;

extern "C" {
  #[link_name = "lwt_bootstrap"]
  pub fn bootstrap();
  #[link_name = "lwt_swapcontext"]
  pub fn swapcontext(save: *mut Registers, restore: *mut Registers);
  #[link_name = "lwt_get_sp_limit"]
  pub fn get_sp_limit() -> *const u8;
  #[link_name = "lwt_set_sp_limit"]
  pub fn set_sp_limit(limit: *const u8);
  #[link_name = "lwt_abort"]
  pub fn abort() -> !;
}

#[allow(non_camel_case_types)]
pub type uintptr_t = u64;

#[repr(C)]
#[allow(dead_code)]
pub struct Registers {
  rbx: u64,
  rsp: u64,
  rbp: u64,
  rdi: u64,
  r12: u64,
  r13: u64,
  r14: u64,
  r15: u64,
  ip:  u64,
  xmm0: u64x2,
  xmm1: u64x2,
  xmm2: u64x2,
  xmm3: u64x2,
  xmm4: u64x2,
  xmm5: u64x2,
}

impl Registers {
  pub fn new() -> Registers {
    unsafe {
      Registers {
        ip: abort as uintptr_t,
        .. zeroed()
      }
    }
  }
}

pub fn initialise_call_frame(stack: &mut Stack, init: uintptr_t, args: &[uintptr_t]) -> Registers {
  let sp = stack.top() as *mut uintptr_t;
  let sp = align_down_mut(sp, 16);
  let sp = offset_mut(sp, -1);
  unsafe {
    *sp = 0;
  }

  let mut regs = Registers {
    rbp: 0,
    rsp: sp as uintptr_t,
    ip: bootstrap as uintptr_t,
    rbx: init,
    .. Registers::new()
  };

  match into_fields!(regs { rdi, r12, r13, r14, r15 } <- args.iter().cloned()) {
    Some(mut args) => if args.next().is_some() {
      panic!("too many arguments")
    },
    None => {}
  }

  regs
}

#[inline]
fn align_down_mut<T>(sp: *mut T, n: uint) -> *mut T {
  let sp = (sp as uint) & !(n - 1);
  sp as *mut T
}

// ptr::offset_mmut is positive ints only
#[inline]
pub fn offset_mut<T>(ptr: *mut T, count: int) -> *mut T {
  (ptr as int + count * (size_of::<T>() as int)) as *mut T
}
<|endoftext|>