<commit_before>extern crate cgmath;
#[macro_use]
extern crate clap;
extern crate collision;
extern crate futures;
extern crate grpcio;
extern crate point_viewer;
extern crate point_viewer_grpc;
extern crate protobuf;

use cgmath::Point3;
use collision::Aabb3;
use futures::{Stream, Future, Sink};
use futures::sync::oneshot;
use grpcio::{Environment, RpcContext, ServerBuilder, ServerStreamingSink, UnarySink, WriteFlags};
use point_viewer::InternalIterator;
use point_viewer::octree::{read_meta_proto, NodeId, Octree, OnDiskOctree};
use point_viewer_grpc::proto;
use point_viewer_grpc::proto_grpc;
use protobuf::Message;
use std::{io, thread};
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use futures::sync::mpsc;

#[derive(Clone)]
struct OctreeService {
    octree: Arc<OnDiskOctree>,
    meta: point_viewer::proto::Meta,
}

impl proto_grpc::Octree for OctreeService {
    fn get_meta(
        &self,
        ctx: RpcContext,
        req: proto::GetMetaRequest,
        sink: UnarySink<proto::GetMetaReply>,
    ) {
        let mut resp = proto::GetMetaReply::new();
        resp.set_meta(self.meta.clone());
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_node_data(
        &self,
        ctx: RpcContext,
        req: proto::GetNodeDataRequest,
        sink: UnarySink<proto::GetNodeDataReply>,
    ) {
        let data = self.octree
            .get_node_data(&NodeId::from_str(&req.id))
            .unwrap();
        let mut resp = proto::GetNodeDataReply::new();
        resp.mut_node()
            .set_position_encoding(data.meta.position_encoding.to_proto());
        resp.mut_node().set_num_points(data.meta.num_points);
        resp.set_position(data.position);
        resp.set_color(data.color);
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_points_in_box(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInBoxRequest,
        resp: ServerStreamingSink<proto::GetPointsInBoxReply>,
    ) {
        use std::thread;

        // This creates a async-aware (tx, rx) pair that can wake up the event loop when new data
        // is piped through it.
        let (tx, rx) = mpsc::channel(4);
        let octree = self.octree.clone();
        thread::spawn(move || {
            // This is the secret sauce connecting an OS thread to a event-based receiver. Calling
            // wait() on this turns the event aware, i.e. async 'tx' into a blocking 'tx' that will
            // make this thread block when the event loop is not quick enough with piping out data.
            let mut tx = tx.wait();

            let bounding_box = {
                let bounding_box = req.bounding_box.clone().unwrap();
                let min = bounding_box.min.unwrap();
                let max = bounding_box.max.unwrap();
                Aabb3::new(
                    Point3::new(min.x, min.y, min.z),
                    Point3::new(max.x, max.y, max.z),
                )
            };
            let mut reply = proto::GetPointsInBoxReply::new();

            // Computing the protobuf size is very expensive.
            // We compute the byte size of a Vector3f in the reply proto once outside the loop.
            let bytes_per_point = {
                let mut reply = proto::GetPointsInBoxReply::new();
                let initial_proto_size = reply.compute_size();
                let mut v = point_viewer::proto::Vector3f::new();
                v.set_x(1.);
                v.set_y(1.);
                v.set_z(1.);
                reply.mut_points().push(v);
                let final_proto_size = reply.compute_size();
                final_proto_size - initial_proto_size
            };
            // Proto message must be below 4 MB.
            let max_message_size = 4 * 1024 * 1024;
            let mut reply_size = 0;
            octree.points_in_box(&bounding_box).for_each(|p| {
                let mut v = point_viewer::proto::Vector3f::new();
                v.set_x(p.position.x);
                v.set_y(p.position.y);
                v.set_z(p.position.z);
                reply.mut_points().push(v);

                reply_size += bytes_per_point;
                if reply_size > max_message_size - bytes_per_point {
                    tx.send((reply.clone(), WriteFlags::default())).unwrap();
                    reply.mut_points().clear();
                    reply_size = 0;
                }
            });
        });

        // TODO(sirver): I did not figure out how to return meaningful errors. At least we return
        // any error.
        let rx = rx.map_err(|_| grpcio::Error::RemoteStopped);
        let f = resp
            .send_all(rx)
            .map(|_| {})
            .map_err(|e| println!("failed to reply: {:?}", e));
        ctx.spawn(f)
    }
}

fn main() {
    let matches = clap::App::new("octree_server")
        .args(&[
            clap::Arg::with_name("port")
                .help("Port to listen on for connections. [50051]")
                .long("port")
                .takes_value(true),
            clap::Arg::with_name("octree_directory")
                .help("Input directory of the octree directory to serve.")
                .index(1)
                .required(true),
        ])
        .get_matches();

    let port = value_t!(matches, "port", u16).unwrap_or(50051);
    let octree_directory = PathBuf::from(matches.value_of("octree_directory").unwrap());

    let env = Arc::new(Environment::new(1));
    let meta = read_meta_proto(&octree_directory).unwrap();
    let octree = Arc::new(OnDiskOctree::new(octree_directory).unwrap());

    let service = proto_grpc::create_octree(OctreeService { octree, meta });
    let mut server = ServerBuilder::new(env)
        .register_service(service)
        .bind("0.0.0.0" /* ip to bind to */, port)
        .build()
        .unwrap();
    server.start();
    for &(ref host, port) in server.bind_addrs() {
        println!("listening on {}:{}", host, port);
    }
    let (tx, rx) = oneshot::channel();
    thread::spawn(move || {
        println!("Press ENTER to exit...");
        let _ = io::stdin().read(&mut [0]).unwrap();
        tx.send(())
    });
    let _ = rx.wait();
    let _ = server.shutdown().wait();
}
<commit_msg>Fix a bug in octree server: it never send the last few points. (#150)<commit_after>extern crate cgmath;
#[macro_use]
extern crate clap;
extern crate collision;
extern crate futures;
extern crate grpcio;
extern crate point_viewer;
extern crate point_viewer_grpc;
extern crate protobuf;

use cgmath::Point3;
use collision::Aabb3;
use futures::{Stream, Future, Sink};
use futures::sync::oneshot;
use grpcio::{Environment, RpcContext, ServerBuilder, ServerStreamingSink, UnarySink, WriteFlags};
use point_viewer::InternalIterator;
use point_viewer::octree::{read_meta_proto, NodeId, Octree, OnDiskOctree};
use point_viewer_grpc::proto;
use point_viewer_grpc::proto_grpc;
use protobuf::Message;
use std::{io, thread};
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use futures::sync::mpsc;

#[derive(Clone)]
struct OctreeService {
    octree: Arc<OnDiskOctree>,
    meta: point_viewer::proto::Meta,
}

impl proto_grpc::Octree for OctreeService {
    fn get_meta(
        &self,
        ctx: RpcContext,
        req: proto::GetMetaRequest,
        sink: UnarySink<proto::GetMetaReply>,
    ) {
        let mut resp = proto::GetMetaReply::new();
        resp.set_meta(self.meta.clone());
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_node_data(
        &self,
        ctx: RpcContext,
        req: proto::GetNodeDataRequest,
        sink: UnarySink<proto::GetNodeDataReply>,
    ) {
        let data = self.octree
            .get_node_data(&NodeId::from_str(&req.id))
            .unwrap();
        let mut resp = proto::GetNodeDataReply::new();
        resp.mut_node()
            .set_position_encoding(data.meta.position_encoding.to_proto());
        resp.mut_node().set_num_points(data.meta.num_points);
        resp.set_position(data.position);
        resp.set_color(data.color);
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_points_in_box(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInBoxRequest,
        resp: ServerStreamingSink<proto::GetPointsInBoxReply>,
    ) {
        use std::thread;

        // This creates a async-aware (tx, rx) pair that can wake up the event loop when new data
        // is piped through it.
        let (tx, rx) = mpsc::channel(4);
        let octree = self.octree.clone();
        thread::spawn(move || {
            // This is the secret sauce connecting an OS thread to a event-based receiver. Calling
            // wait() on this turns the event aware, i.e. async 'tx' into a blocking 'tx' that will
            // make this thread block when the event loop is not quick enough with piping out data.
            let mut tx = tx.wait();

            let bounding_box = {
                let bounding_box = req.bounding_box.clone().unwrap();
                let min = bounding_box.min.unwrap();
                let max = bounding_box.max.unwrap();
                Aabb3::new(
                    Point3::new(min.x, min.y, min.z),
                    Point3::new(max.x, max.y, max.z),
                )
            };
            let mut reply = proto::GetPointsInBoxReply::new();

            // Computing the protobuf size is very expensive.
            // We compute the byte size of a Vector3f in the reply proto once outside the loop.
            let bytes_per_point = {
                let mut reply = proto::GetPointsInBoxReply::new();
                let initial_proto_size = reply.compute_size();
                let mut v = point_viewer::proto::Vector3f::new();
                v.set_x(1.);
                v.set_y(1.);
                v.set_z(1.);
                reply.mut_points().push(v);
                let final_proto_size = reply.compute_size();
                final_proto_size - initial_proto_size
            };
            // Proto message must be below 4 MB.
            let max_message_size = 4 * 1024 * 1024;
            let mut reply_size = 0;
            octree.points_in_box(&bounding_box).for_each(|p| {
                let mut v = point_viewer::proto::Vector3f::new();
                v.set_x(p.position.x);
                v.set_y(p.position.y);
                v.set_z(p.position.z);
                reply.mut_points().push(v);

                reply_size += bytes_per_point;
                if reply_size > max_message_size - bytes_per_point {
                    tx.send((reply.clone(), WriteFlags::default())).unwrap();
                    reply.mut_points().clear();
                    reply_size = 0;
                }
            });
            tx.send((reply, WriteFlags::default())).unwrap();
        });

        // TODO(sirver): I did not figure out how to return meaningful errors. At least we return
        // any error.
        let rx = rx.map_err(|_| grpcio::Error::RemoteStopped);
        let f = resp
            .send_all(rx)
            .map(|_| {})
            .map_err(|e| println!("failed to reply: {:?}", e));
        ctx.spawn(f)
    }
}

fn main() {
    let matches = clap::App::new("octree_server")
        .args(&[
            clap::Arg::with_name("port")
                .help("Port to listen on for connections. [50051]")
                .long("port")
                .takes_value(true),
            clap::Arg::with_name("octree_directory")
                .help("Input directory of the octree directory to serve.")
                .index(1)
                .required(true),
        ])
        .get_matches();

    let port = value_t!(matches, "port", u16).unwrap_or(50051);
    let octree_directory = PathBuf::from(matches.value_of("octree_directory").unwrap());

    let env = Arc::new(Environment::new(1));
    let meta = read_meta_proto(&octree_directory).unwrap();
    let octree = Arc::new(OnDiskOctree::new(octree_directory).unwrap());

    let service = proto_grpc::create_octree(OctreeService { octree, meta });
    let mut server = ServerBuilder::new(env)
        .register_service(service)
        .bind("0.0.0.0" /* ip to bind to */, port)
        .build()
        .unwrap();
    server.start();
    for &(ref host, port) in server.bind_addrs() {
        println!("listening on {}:{}", host, port);
    }
    let (tx, rx) = oneshot::channel();
    thread::spawn(move || {
        println!("Press ENTER to exit...");
        let _ = io::stdin().read(&mut [0]).unwrap();
        tx.send(())
    });
    let _ = rx.wait();
    let _ = server.shutdown().wait();
}
<|endoftext|>


<commit_before>use itertools::Itertools;

struct HumbleNumberSeq {
    seq: Vec<u64>,
    current_h: u64,
    index: usize,
    next2: u64,
    next3: u64,
    next5: u64,
    next7: u64,
    last2: usize,
    last3: usize,
    last5: usize,
    last7: usize,
}

impl HumbleNumberSeq {
    fn new(max_number_of_numbers: usize) -> HumbleNumberSeq {
        HumbleNumberSeq {
            seq: vec![0; max_number_of_numbers],
            current_h: 1,
            index: 0,
            next2: 2,
            next3: 3,
            next5: 5,
            next7: 7,
            last2: 0,
            last3: 0,
            last5: 0,
            last7: 0,
        }
    }
}

impl Iterator for HumbleNumberSeq {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        // Direct generation, with u64 it's good up to ~19 digits

        // if reached the max # of numbers, return None
        if self.index >= self.seq.len() {
            return None;
        }

        // this wil be returned
        self.seq[self.index] = self.current_h;
        self.index += 1;

        if self.current_h == self.next2 {
            self.last2 += 1;
            self.next2 = self.seq[self.last2] * 2;
        }

        if self.current_h == self.next3 {
            self.last3 += 1;
            self.next3 = self.seq[self.last3] * 3;
        }

        if self.current_h == self.next5 {
            self.last5 += 1;
            self.next5 = self.seq[self.last5] * 5;
        }

        if self.current_h == self.next7 {
            self.last7 += 1;
            self.next7 = self.seq[self.last7] * 7;
        }

        // store next number
        self.current_h = *vec![self.next2, self.next3, self.next5, self.next7]
            .iter()
            .min()
            .unwrap();

        // return latest number
        Some(self.seq[self.index - 1])
    }
}

fn main() {
    let seq_iter = HumbleNumberSeq::new(50);
    println!("First 50 Humble number");
    for (i, x) in seq_iter.enumerate() {
        if i % 10 == 9 {
            println!("{:>3}", x);
        } else {
            print!("{:>3}, ", x);
        }
    }

    let seq_iter = HumbleNumberSeq::new(85000);
    println!("\nOf the first 85.000 humble numbers");
    for (key, group) in &seq_iter.into_iter().group_by(|e| (*e).to_string().len()) {
        if key < 20 {
            println!("{:>5} have  {:>3} digits", group.count(), key);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_humble() {
        let seq_iter = HumbleNumberSeq::new(50);
        let result = seq_iter.skip(10).take(10).collect::<Vec<_>>();
        assert_eq!(result, vec![12, 14, 15, 16, 18, 20, 21, 24, 25, 27])
    }
}
<commit_msg>Dynamic vector resizing in iterator<commit_after>use itertools::Itertools;

struct HumbleNumbers {
    seq: Vec<u64>,
    current_h: u64,
    index: usize,
    next2: u64,
    next3: u64,
    next5: u64,
    next7: u64,
    last2: usize,
    last3: usize,
    last5: usize,
    last7: usize,
}

impl HumbleNumbers {
    fn new() -> HumbleNumbers {
        HumbleNumbers {
            seq: vec![0; 50],
            current_h: 1,
            index: 0,
            next2: 2,
            next3: 3,
            next5: 5,
            next7: 7,
            last2: 0,
            last3: 0,
            last5: 0,
            last7: 0,
        }
    }
}

impl Iterator for HumbleNumbers {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        // Direct generation, with u64 it's good up to ~19 digits, ~81000 humble numbers

        // if reached the max # of numbers, increase the vector
        if self.index >= self.seq.len() {
            self.seq.resize(self.seq.len() * 2, 0);
        }

        // this wil be returned
        self.seq[self.index] = self.current_h;
        self.index += 1;

        if self.current_h == self.next2 {
            self.last2 += 1;
            // check for overflow
            self.next2 = match self.seq[self.last2].checked_mul(2) {
                Some(n) => n,
                _ => return None,
            };
        }

        if self.current_h == self.next3 {
            self.last3 += 1;
            self.next3 = self.seq[self.last3] * 3;
        }

        if self.current_h == self.next5 {
            self.last5 += 1;
            self.next5 = self.seq[self.last5] * 5;
        }

        if self.current_h == self.next7 {
            self.last7 += 1;
            self.next7 = self.seq[self.last7] * 7;
        }

        // store next number
        self.current_h = *vec![self.next2, self.next3, self.next5, self.next7]
            .iter()
            .min()
            .unwrap();

        // return latest number
        Some(self.seq[self.index - 1])
    }
}

fn main() {
    let seq_iter = HumbleNumbers::new().take(50);
    println!("First 50 Humble number");
    for (i, x) in seq_iter.enumerate() {
        if i % 10 == 9 {
            println!("{:>3}", x);
        } else {
            print!("{:>3}, ", x);
        }
    }

    let seq_iter = HumbleNumbers::new();
    println!("\nOf the first ~81.000 humble numbers");
    for (key, group) in &seq_iter.into_iter().group_by(|e| (*e).to_string().len()) {
        if key < 20 {
            println!("{:>5} have  {:>3} digits", group.count(), key);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_humble() {
        let seq_iter = HumbleNumbers::new();
        let result = seq_iter.skip(10).take(10).collect::<Vec<_>>();
        assert_eq!(result, vec![12, 14, 15, 16, 18, 20, 21, 24, 25, 27])
    }
}
<|endoftext|>


<commit_before>use super::super::format_field::FormatField;
use super::super::formatter::{get_it_at, warn_incomplete_conv, Base, FormatPrimitive, InPrefix};
use super::base_conv;
use super::base_conv::RadixDef;

// if the memory, copy, and comparison cost of chars
//  becomes an issue, we can always operate in vec<u8> here
//  rather than just at de_hex

pub struct FloatAnalysis {
    pub len_important: usize,
    // none means no decimal point.
    pub decimal_pos: Option<usize>,
    pub follow: Option<char>,
}
fn has_enough_digits(
    hex_input: bool,
    hex_output: bool,
    string_position: usize,
    starting_position: usize,
    limit: usize,
) -> bool {
    // -1s are for rounding
    if hex_output {
        if hex_input {
            ((string_position - 1) - starting_position >= limit)
        } else {
            false //undecidable without converting
        }
    } else {
        if hex_input {
            ((((string_position - 1) - starting_position) * 9) / 8 >= limit)
        } else {
            ((string_position - 1) - starting_position >= limit)
        }
    }
}

impl FloatAnalysis {
    pub fn analyze(
        str_in: &str,
        inprefix: &InPrefix,
        max_sd_opt: Option<usize>,
        max_after_dec_opt: Option<usize>,
        hex_output: bool,
    ) -> FloatAnalysis {
        // this fn assumes
        // the input string
        // has no leading spaces or 0s
        let mut str_it = get_it_at(inprefix.offset, str_in);
        let mut ret = FloatAnalysis {
            len_important: 0,
            decimal_pos: None,
            follow: None,
        };
        let hex_input = match inprefix.radix_in {
            Base::Hex => true,
            Base::Ten => false,
            Base::Octal => {
                panic!("this should never happen: floats should never receive octal input");
            }
        };
        let mut i = 0;
        let mut pos_before_first_nonzero_after_decimal: Option<usize> = None;
        while let Some(c) = str_it.next() {
            match c {
                e @ '0'..='9' | e @ 'A'..='F' | e @ 'a'..='f' => {
                    if !hex_input {
                        match e {
                            '0'..='9' => {}
                            _ => {
                                warn_incomplete_conv(str_in);
                                break;
                            }
                        }
                    }
                    if ret.decimal_pos.is_some() && pos_before_first_nonzero_after_decimal.is_none()
                        && e != '0'
                    {
                        pos_before_first_nonzero_after_decimal = Some(i - 1);
                    }
                    if let Some(max_sd) = max_sd_opt {
                        if i == max_sd {
                            // follow is used in cases of %g
                            // where the character right after the last
                            // sd is considered is rounded affecting
                            // the previous digit in 1/2 of instances
                            ret.follow = Some(e);
                        } else if ret.decimal_pos.is_some() && i > max_sd {
                            break;
                        }
                    }
                    if let Some(max_after_dec) = max_after_dec_opt {
                        if let Some(p) = ret.decimal_pos {
                            if has_enough_digits(hex_input, hex_output, i, p, max_after_dec) {
                                break;
                            }
                        }
                    } else if let Some(max_sd) = max_sd_opt {
                        if let Some(p) = pos_before_first_nonzero_after_decimal {
                            if has_enough_digits(hex_input, hex_output, i, p, max_sd) {
                                break;
                            }
                        }
                    }
                }
                '.' => {
                    if ret.decimal_pos.is_none() {
                        ret.decimal_pos = Some(i);
                    } else {
                        warn_incomplete_conv(str_in);
                        break;
                    }
                }
                _ => {
                    warn_incomplete_conv(str_in);
                    break;
                }
            };
            i += 1;
        }
        ret.len_important = i;
        ret
    }
}

fn de_hex(src: &str, before_decimal: bool) -> String {
    let rten = base_conv::RadixTen;
    let rhex = base_conv::RadixHex;
    if before_decimal {
        base_conv::base_conv_str(src, &rhex, &rten)
    } else {
        let as_arrnum_hex = base_conv::str_to_arrnum(src, &rhex);
        let s = format!(
            "{}",
            base_conv::base_conv_float(&as_arrnum_hex, rhex.get_max(), rten.get_max())
        );
        if s.len() > 2 {
            String::from(&s[2..])
        } else {
            // zero
            s
        }
    }
}

// takes a string in,
// truncates to a position,
// bumps the last digit up one,
// and if the digit was nine
// propagate to the next, etc.
fn _round_str_from(in_str: &str, position: usize) -> (String, bool) {
    let mut it = in_str[0..position].chars();
    let mut rev = String::new();
    let mut i = position;
    let mut finished_in_dec = false;
    while let Some(c) = it.next_back() {
        i -= 1;
        match c {
            '9' => {
                rev.push('0');
            }
            e => {
                rev.push(((e as u8) + 1) as char);
                finished_in_dec = true;
                break;
            }
        }
    }
    let mut fwd = String::from(&in_str[0..i]);
    for ch in rev.chars().rev() {
        fwd.push(ch);
    }
    (fwd, finished_in_dec)
}

fn round_terminal_digit(
    before_dec: String,
    after_dec: String,
    position: usize,
) -> (String, String) {
    if position < after_dec.len() {
        let digit_at_pos: char;
        {
            digit_at_pos = (&after_dec[position..=position])
                .chars()
                .next()
                .expect("");
        }
        match digit_at_pos {
            '5'..='9' => {
                let (new_after_dec, finished_in_dec) = _round_str_from(&after_dec, position);
                if finished_in_dec {
                    return (before_dec, new_after_dec);
                } else {
                    let (new_before_dec, _) = _round_str_from(&before_dec, before_dec.len());
                    return (new_before_dec, new_after_dec);
                }
                // TODO
            }
            _ => {}
        }
    }
    (before_dec, after_dec)
}

pub fn get_primitive_dec(
    inprefix: &InPrefix,
    str_in: &str,
    analysis: &FloatAnalysis,
    last_dec_place: usize,
    sci_mode: Option<bool>,
) -> FormatPrimitive {
    let mut f: FormatPrimitive = Default::default();

    // add negative sign section
    if inprefix.sign == -1 {
        f.prefix = Some(String::from("-"));
    }

    // assign the digits before and after the decimal points
    // to separate slices. If no digits after decimal point,
    // assign 0
    let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
        Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
        None => (&str_in[..], "0"),
    };
    if first_segment_raw.len() == 0 {
        first_segment_raw = "0";
    }
    // convert to string, de_hexifying if input is in hex.
    let (first_segment, second_segment) = match inprefix.radix_in {
        Base::Hex => (
            de_hex(first_segment_raw, true),
            de_hex(second_segment_raw, false),
        ),
        _ => (
            String::from(first_segment_raw),
            String::from(second_segment_raw),
        ),
    };
    let (pre_dec_unrounded, post_dec_unrounded, mantissa) = if sci_mode.is_some() {
        if first_segment.len() > 1 {
            let mut post_dec = String::from(&first_segment[1..]);
            post_dec.push_str(&second_segment);
            (
                String::from(&first_segment[0..1]),
                post_dec,
                first_segment.len() as isize - 1,
            )
        } else {
            match first_segment.chars().next() {
                Some('0') => {
                    let mut it = second_segment.chars().enumerate();
                    let mut m: isize = 0;
                    let mut pre = String::from("0");
                    let mut post = String::from("0");
                    while let Some((i, c)) = it.next() {
                        match c {
                            '0' => {}
                            _ => {
                                m = ((i as isize) + 1) * -1;
                                pre = String::from(&second_segment[i..=i]);
                                post = String::from(&second_segment[i + 1..]);
                                break;
                            }
                        }
                    }
                    (pre, post, m)
                }
                Some(_) => (first_segment, second_segment, 0),
                None => {
                    panic!("float_common: no chars in first segment.");
                }
            }
        }
    } else {
        (first_segment, second_segment, 0)
    };

    let (pre_dec_draft, post_dec_draft) =
        round_terminal_digit(pre_dec_unrounded, post_dec_unrounded, last_dec_place - 1);

    f.pre_decimal = Some(pre_dec_draft);
    f.post_decimal = Some(post_dec_draft);
    if let Some(capitalized) = sci_mode {
        let si_ind = if capitalized { 'E' } else { 'e' };
        f.suffix = Some(if mantissa >= 0 {
            format!("{}+{:02}", si_ind, mantissa)
        } else {
            // negative sign is considered in format!s
            // leading zeroes
            format!("{}{:03}", si_ind, mantissa)
        });
    }

    f
}

pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
    let mut final_str = String::new();
    match prim.prefix {
        Some(ref prefix) => {
            final_str.push_str(&prefix);
        }
        None => {}
    }
    match prim.pre_decimal {
        Some(ref pre_decimal) => {
            final_str.push_str(&pre_decimal);
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    let decimal_places = field.second_field.unwrap_or(6);
    match prim.post_decimal {
        Some(ref post_decimal) => {
            if post_decimal.len() > 0 && decimal_places > 0 {
                final_str.push('.');
                let len_avail = post_decimal.len() as u32;

                if decimal_places >= len_avail {
                    // println!("dec {}, len avail {}", decimal_places, len_avail);
                    final_str.push_str(post_decimal);

                    if *field.field_char != 'g' && *field.field_char != 'G' {
                        let diff = decimal_places - len_avail;
                        for _ in 0..diff {
                            final_str.push('0');
                        }
                    }
                } else {
                    // println!("printing to only {}", decimal_places);
                    final_str.push_str(&post_decimal[0..decimal_places as usize]);
                }
            }
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    match prim.suffix {
        Some(ref suffix) => {
            final_str.push_str(suffix);
        }
        None => {}
    }

    final_str
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (negation instead of * -1)<commit_after>use super::super::format_field::FormatField;
use super::super::formatter::{get_it_at, warn_incomplete_conv, Base, FormatPrimitive, InPrefix};
use super::base_conv;
use super::base_conv::RadixDef;

// if the memory, copy, and comparison cost of chars
//  becomes an issue, we can always operate in vec<u8> here
//  rather than just at de_hex

pub struct FloatAnalysis {
    pub len_important: usize,
    // none means no decimal point.
    pub decimal_pos: Option<usize>,
    pub follow: Option<char>,
}
fn has_enough_digits(
    hex_input: bool,
    hex_output: bool,
    string_position: usize,
    starting_position: usize,
    limit: usize,
) -> bool {
    // -1s are for rounding
    if hex_output {
        if hex_input {
            ((string_position - 1) - starting_position >= limit)
        } else {
            false //undecidable without converting
        }
    } else {
        if hex_input {
            ((((string_position - 1) - starting_position) * 9) / 8 >= limit)
        } else {
            ((string_position - 1) - starting_position >= limit)
        }
    }
}

impl FloatAnalysis {
    pub fn analyze(
        str_in: &str,
        inprefix: &InPrefix,
        max_sd_opt: Option<usize>,
        max_after_dec_opt: Option<usize>,
        hex_output: bool,
    ) -> FloatAnalysis {
        // this fn assumes
        // the input string
        // has no leading spaces or 0s
        let mut str_it = get_it_at(inprefix.offset, str_in);
        let mut ret = FloatAnalysis {
            len_important: 0,
            decimal_pos: None,
            follow: None,
        };
        let hex_input = match inprefix.radix_in {
            Base::Hex => true,
            Base::Ten => false,
            Base::Octal => {
                panic!("this should never happen: floats should never receive octal input");
            }
        };
        let mut i = 0;
        let mut pos_before_first_nonzero_after_decimal: Option<usize> = None;
        while let Some(c) = str_it.next() {
            match c {
                e @ '0'..='9' | e @ 'A'..='F' | e @ 'a'..='f' => {
                    if !hex_input {
                        match e {
                            '0'..='9' => {}
                            _ => {
                                warn_incomplete_conv(str_in);
                                break;
                            }
                        }
                    }
                    if ret.decimal_pos.is_some() && pos_before_first_nonzero_after_decimal.is_none()
                        && e != '0'
                    {
                        pos_before_first_nonzero_after_decimal = Some(i - 1);
                    }
                    if let Some(max_sd) = max_sd_opt {
                        if i == max_sd {
                            // follow is used in cases of %g
                            // where the character right after the last
                            // sd is considered is rounded affecting
                            // the previous digit in 1/2 of instances
                            ret.follow = Some(e);
                        } else if ret.decimal_pos.is_some() && i > max_sd {
                            break;
                        }
                    }
                    if let Some(max_after_dec) = max_after_dec_opt {
                        if let Some(p) = ret.decimal_pos {
                            if has_enough_digits(hex_input, hex_output, i, p, max_after_dec) {
                                break;
                            }
                        }
                    } else if let Some(max_sd) = max_sd_opt {
                        if let Some(p) = pos_before_first_nonzero_after_decimal {
                            if has_enough_digits(hex_input, hex_output, i, p, max_sd) {
                                break;
                            }
                        }
                    }
                }
                '.' => {
                    if ret.decimal_pos.is_none() {
                        ret.decimal_pos = Some(i);
                    } else {
                        warn_incomplete_conv(str_in);
                        break;
                    }
                }
                _ => {
                    warn_incomplete_conv(str_in);
                    break;
                }
            };
            i += 1;
        }
        ret.len_important = i;
        ret
    }
}

fn de_hex(src: &str, before_decimal: bool) -> String {
    let rten = base_conv::RadixTen;
    let rhex = base_conv::RadixHex;
    if before_decimal {
        base_conv::base_conv_str(src, &rhex, &rten)
    } else {
        let as_arrnum_hex = base_conv::str_to_arrnum(src, &rhex);
        let s = format!(
            "{}",
            base_conv::base_conv_float(&as_arrnum_hex, rhex.get_max(), rten.get_max())
        );
        if s.len() > 2 {
            String::from(&s[2..])
        } else {
            // zero
            s
        }
    }
}

// takes a string in,
// truncates to a position,
// bumps the last digit up one,
// and if the digit was nine
// propagate to the next, etc.
fn _round_str_from(in_str: &str, position: usize) -> (String, bool) {
    let mut it = in_str[0..position].chars();
    let mut rev = String::new();
    let mut i = position;
    let mut finished_in_dec = false;
    while let Some(c) = it.next_back() {
        i -= 1;
        match c {
            '9' => {
                rev.push('0');
            }
            e => {
                rev.push(((e as u8) + 1) as char);
                finished_in_dec = true;
                break;
            }
        }
    }
    let mut fwd = String::from(&in_str[0..i]);
    for ch in rev.chars().rev() {
        fwd.push(ch);
    }
    (fwd, finished_in_dec)
}

fn round_terminal_digit(
    before_dec: String,
    after_dec: String,
    position: usize,
) -> (String, String) {
    if position < after_dec.len() {
        let digit_at_pos: char;
        {
            digit_at_pos = (&after_dec[position..=position])
                .chars()
                .next()
                .expect("");
        }
        match digit_at_pos {
            '5'..='9' => {
                let (new_after_dec, finished_in_dec) = _round_str_from(&after_dec, position);
                if finished_in_dec {
                    return (before_dec, new_after_dec);
                } else {
                    let (new_before_dec, _) = _round_str_from(&before_dec, before_dec.len());
                    return (new_before_dec, new_after_dec);
                }
                // TODO
            }
            _ => {}
        }
    }
    (before_dec, after_dec)
}

pub fn get_primitive_dec(
    inprefix: &InPrefix,
    str_in: &str,
    analysis: &FloatAnalysis,
    last_dec_place: usize,
    sci_mode: Option<bool>,
) -> FormatPrimitive {
    let mut f: FormatPrimitive = Default::default();

    // add negative sign section
    if inprefix.sign == -1 {
        f.prefix = Some(String::from("-"));
    }

    // assign the digits before and after the decimal points
    // to separate slices. If no digits after decimal point,
    // assign 0
    let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
        Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
        None => (&str_in[..], "0"),
    };
    if first_segment_raw.len() == 0 {
        first_segment_raw = "0";
    }
    // convert to string, de_hexifying if input is in hex.
    let (first_segment, second_segment) = match inprefix.radix_in {
        Base::Hex => (
            de_hex(first_segment_raw, true),
            de_hex(second_segment_raw, false),
        ),
        _ => (
            String::from(first_segment_raw),
            String::from(second_segment_raw),
        ),
    };
    let (pre_dec_unrounded, post_dec_unrounded, mantissa) = if sci_mode.is_some() {
        if first_segment.len() > 1 {
            let mut post_dec = String::from(&first_segment[1..]);
            post_dec.push_str(&second_segment);
            (
                String::from(&first_segment[0..1]),
                post_dec,
                first_segment.len() as isize - 1,
            )
        } else {
            match first_segment.chars().next() {
                Some('0') => {
                    let mut it = second_segment.chars().enumerate();
                    let mut m: isize = 0;
                    let mut pre = String::from("0");
                    let mut post = String::from("0");
                    while let Some((i, c)) = it.next() {
                        match c {
                            '0' => {}
                            _ => {
                                m = -((i as isize) + 1);
                                pre = String::from(&second_segment[i..=i]);
                                post = String::from(&second_segment[i + 1..]);
                                break;
                            }
                        }
                    }
                    (pre, post, m)
                }
                Some(_) => (first_segment, second_segment, 0),
                None => {
                    panic!("float_common: no chars in first segment.");
                }
            }
        }
    } else {
        (first_segment, second_segment, 0)
    };

    let (pre_dec_draft, post_dec_draft) =
        round_terminal_digit(pre_dec_unrounded, post_dec_unrounded, last_dec_place - 1);

    f.pre_decimal = Some(pre_dec_draft);
    f.post_decimal = Some(post_dec_draft);
    if let Some(capitalized) = sci_mode {
        let si_ind = if capitalized { 'E' } else { 'e' };
        f.suffix = Some(if mantissa >= 0 {
            format!("{}+{:02}", si_ind, mantissa)
        } else {
            // negative sign is considered in format!s
            // leading zeroes
            format!("{}{:03}", si_ind, mantissa)
        });
    }

    f
}

pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
    let mut final_str = String::new();
    match prim.prefix {
        Some(ref prefix) => {
            final_str.push_str(&prefix);
        }
        None => {}
    }
    match prim.pre_decimal {
        Some(ref pre_decimal) => {
            final_str.push_str(&pre_decimal);
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    let decimal_places = field.second_field.unwrap_or(6);
    match prim.post_decimal {
        Some(ref post_decimal) => {
            if post_decimal.len() > 0 && decimal_places > 0 {
                final_str.push('.');
                let len_avail = post_decimal.len() as u32;

                if decimal_places >= len_avail {
                    // println!("dec {}, len avail {}", decimal_places, len_avail);
                    final_str.push_str(post_decimal);

                    if *field.field_char != 'g' && *field.field_char != 'G' {
                        let diff = decimal_places - len_avail;
                        for _ in 0..diff {
                            final_str.push('0');
                        }
                    }
                } else {
                    // println!("printing to only {}", decimal_places);
                    final_str.push_str(&post_decimal[0..decimal_places as usize]);
                }
            }
        }
        None => {
            panic!(
                "error, format primitives provided to int, will, incidentally under correct \
                 behavior, always have a pre_dec value."
            );
        }
    }
    match prim.suffix {
        Some(ref suffix) => {
            final_str.push_str(suffix);
        }
        None => {}
    }

    final_str
}
<|endoftext|>


<commit_before>fn fix_price(num: f64) -> f64 {
    match num {
        0.96...1.00 => 1.00,
        0.91...0.96 => 0.98,
        0.86...0.91 => 0.94,
        0.81...0.86 => 0.90,
        0.76...0.81 => 0.86,
        0.71...0.76 => 0.82,
        0.66...0.71 => 0.78,
        0.61...0.66 => 0.74,
        0.56...0.61 => 0.70,
        0.51...0.56 => 0.66,
        0.46...0.51 => 0.62,
        0.41...0.46 => 0.58,
        0.36...0.41 => 0.54,
        0.31...0.36 => 0.50,
        0.26...0.31 => 0.44,
        0.21...0.26 => 0.38,
        0.16...0.21 => 0.32,
        0.11...0.16 => 0.26,
        0.06...0.11 => 0.18,
        0.00...0.06 => 0.10,
        // panics on invalid value
        _ => unreachable!(),
    }
}

fn main() {
    let mut n: f64 = 0.04;
    while n <= 1.00 {
        println!("{:.2} => {}", n, fix_price(n));
        n += 0.04;
    }
}

// typically this could be included in the match as those check for exhaustiveness already
// by explicitly listing all remaining ranges / values instead of a catch-all underscore (_)
// but f64::NaN, f64::INFINITY and f64::NEG_INFINITY can't be matched like this
#[test]
fn exhaustiveness_check() {
    let mut input_price = 0.;
    while input_price <= 1. {
        fix_price(input_price);
        input_price += 0.01;
    }
}
<commit_msg>use integer patterns over floating point<commit_after>fn fix_price(num: f64) -> f64 {
    let cents = (num.fract() * 100_f64) as u16;

    match cents {
        96...101 => 1.00,
        91...96 => 0.98,
        86...91 => 0.94,
        81...86 => 0.90,
        76...81 => 0.86,
        71...76 => 0.82,
        66...71 => 0.78,
        61...66 => 0.74,
        56...61 => 0.70,
        51...56 => 0.66,
        46...51 => 0.62,
        41...46 => 0.58,
        36...41 => 0.54,
        31...36 => 0.50,
        26...31 => 0.44,
        21...26 => 0.38,
        16...21 => 0.32,
        11...16 => 0.26,
        06...11 => 0.18,
        00...06 => 0.10,
        // panics on invalid value
        _ => panic!("price out of range"),
    }
}

fn main() {
    let mut n: f64 = 0.04;
    while n <= 1.00 {
        println!("{:.2} => {:.2}", n, fix_price(n));
        n += 0.04;
    }
}

// typically this could be included in the match as those check for exhaustiveness already
// by explicitly listing all remaining ranges / values instead of a catch-all underscore (_)
// but f64::NaN, f64::INFINITY and f64::NEG_INFINITY can't be matched like this
#[test]
fn exhaustiveness_check() {
    let mut input_price = 0.;
    while input_price <= 1. {
        fix_price(input_price);
        input_price += 0.01;
    }
}
<|endoftext|>


<commit_before>use super::ssz::{ Encodable, SszStream };

/// The value of the "type" field of SpecialRecord.
///
/// Note: this value must serialize to a u8 and therefore must not be greater than 255.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SpecialRecordKind {
    Logout = 0,
    CasperSlashing = 1,
    RandaoChange = 2,
}

/// The structure used in the `BeaconBlock.specials` field.
#[derive(Debug, PartialEq, Clone)]
pub struct SpecialRecord {
    pub kind: SpecialRecordKind,
    pub data: Vec<u8>,
}

impl SpecialRecord {
    pub fn logout(data: &[u8]) -> Self {
        Self {
            kind: SpecialRecordKind::Logout,
            data: data.to_vec(),
        }
    }

    pub fn casper_slashing(data: &[u8]) -> Self {
        Self {
            kind: SpecialRecordKind::CasperSlashing,
            data: data.to_vec(),
        }
    }

    pub fn randao_change(data: &[u8]) -> Self {
        Self {
            kind: SpecialRecordKind::RandaoChange,
            data: data.to_vec(),
        }
    }
}

impl Encodable for SpecialRecord {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&self.kind);
        s.append_vec(&self.data);
    }
}

impl Encodable for SpecialRecordKind {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&(*self as u8));
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    pub fn test_special_record_ssz() {
        let s = SpecialRecord::logout(&vec![]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![0, 0, 0, 0, 0]);

        let s = SpecialRecord::casper_slashing(&vec![]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![1, 0, 0, 0, 0]);

        let s = SpecialRecord::randao_change(&vec![]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![2, 0, 0, 0, 0]);

        let s = SpecialRecord::randao_change(&vec![42, 43, 44]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![2, 0, 0, 0, 3, 42, 43, 44]);
    }
}
<commit_msg>Change SpecialRecord to use u8 instead of enum<commit_after>use super::ssz::{
    Encodable,
    Decodable,
    DecodeError,
    SszStream,
};

/// The value of the "type" field of SpecialRecord.
///
/// Note: this value must serialize to a u8 and therefore must not be greater than 255.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SpecialRecordKind {
    Logout = 0,
    CasperSlashing = 1,
    RandaoChange = 2,
}

/// The structure used in the `BeaconBlock.specials` field.
#[derive(Debug, PartialEq, Clone)]
pub struct SpecialRecord {
    pub kind: u8,
    pub data: Vec<u8>,
}

impl SpecialRecord {
    pub fn logout(data: &[u8]) -> Self {
        Self {
            kind: SpecialRecordKind::Logout as u8,
            data: data.to_vec(),
        }
    }

    pub fn casper_slashing(data: &[u8]) -> Self {
        Self {
            kind: SpecialRecordKind::CasperSlashing as u8,
            data: data.to_vec(),
        }
    }

    pub fn randao_change(data: &[u8]) -> Self {
        Self {
            kind: SpecialRecordKind::RandaoChange as u8,
            data: data.to_vec(),
        }
    }

    /// Match `self.kind` to a `SpecialRecordKind`.
    ///
    /// Returns `None` if `self.kind` is an unknown value.
    fn resolve_kind(&self) -> Option<SpecialRecordKind> {
        match self.kind {
            x if x == SpecialRecordKind::Logout as u8
                => Some(SpecialRecordKind::Logout),
            x if x == SpecialRecordKind::CasperSlashing as u8
                => Some(SpecialRecordKind::CasperSlashing),
            x if x == SpecialRecordKind::RandaoChange as u8
                => Some(SpecialRecordKind::RandaoChange),
            _ => None
        }
    }
}

impl Encodable for SpecialRecord {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&self.kind);
        s.append_vec(&self.data);
    }
}

impl Decodable for SpecialRecord {
    fn ssz_decode(bytes: &[u8], i: usize)
        -> Result<(Self, usize), DecodeError>
    {
        let (kind, i) = u8::ssz_decode(bytes, i)?;
        let (data, i) = Decodable::ssz_decode(bytes, i)?;
        Ok((SpecialRecord{kind, data}, i))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    pub fn test_special_record_ssz_encode() {
        let s = SpecialRecord::logout(&vec![]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![0, 0, 0, 0, 0]);

        let s = SpecialRecord::casper_slashing(&vec![]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![1, 0, 0, 0, 0]);

        let s = SpecialRecord::randao_change(&vec![]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![2, 0, 0, 0, 0]);

        let s = SpecialRecord::randao_change(&vec![42, 43, 44]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        assert_eq!(ssz, vec![2, 0, 0, 0, 3, 42, 43, 44]);
    }

    #[test]
    pub fn test_special_record_ssz_encode_decode() {
        let s = SpecialRecord::randao_change(&vec![13, 16, 14]);
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(&s);
        let ssz = ssz_stream.drain();
        let (s_decoded, _) = SpecialRecord::ssz_decode(&ssz, 0).unwrap();
        assert_eq!(s, s_decoded);
    }

    #[test]
    pub fn test_special_record_resolve_kind() {
        let s = SpecialRecord::logout(&vec![]);
        assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::Logout));

        let s = SpecialRecord::casper_slashing(&vec![]);
        assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::CasperSlashing));

        let s = SpecialRecord::randao_change(&vec![]);
        assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::RandaoChange));

        let s = SpecialRecord { kind: 88, data: vec![] };
        assert_eq!(s.resolve_kind(), None);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std::rand::*;
use std::i32;

pub struct FastRand {
    state : u32
}

impl Rng for FastRand {
    #[inline]
    fn next(&mut self) -> u32 {
        let a = 1664525;
        let c = 1013904223;
        self.state = a * self.state + c;
        self.state
    }
}

impl FastRand {
    pub fn new() -> FastRand {
        FastRand {state : 1013904223}
    }

    #[inline]
    pub fn nextLessThan(&mut self, range : u32) -> u32 {
        self.next() % range
    }

    #[inline]
    pub fn nextDouble(&mut self, range : f64) -> f64 {
        use std::u32;
        self.next() as f64 * range / (u32::max_value as f64)
    }
}

#[inline]
pub fn div(a : i32, b: i32) -> i32 {
    if (b == 0) { return i32::max_value }
    if (a == i32::min_value && b == -1) {
        return i32::max_value;
    }
    return a / b;
}

#[inline]
pub fn modulus(a : i32, b: i32) -> i32 {
    if (b == 0) { return i32::max_value }
    if (a == i32::min_value && b == -1) {
        return i32::max_value;
    }
    return a % b;
}

pub static WORDS : [&'static str, .. 13] = [
    "foo ", "bar ", "baz ", "qux ", "quux ", "corge ", "grault ", "garply ", "waldo ", "fred ",
    "plugh ", "xyzzy ", "thud "];

<commit_msg>update for new Rng trait<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std::rand::*;
use std::i32;

pub struct FastRand {
    state : u32
}

impl Rng for FastRand {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        let a = 1664525;
        let c = 1013904223;
        self.state = a * self.state + c;
        self.state
    }
}

impl FastRand {
    pub fn new() -> FastRand {
        FastRand {state : 1013904223}
    }

    #[inline]
    pub fn nextLessThan(&mut self, range : u32) -> u32 {
        self.next_u32() % range
    }

    #[inline]
    pub fn nextDouble(&mut self, range : f64) -> f64 {
        use std::u32;
        self.next_u32() as f64 * range / (u32::max_value as f64)
    }
}

#[inline]
pub fn div(a : i32, b: i32) -> i32 {
    if (b == 0) { return i32::max_value }
    if (a == i32::min_value && b == -1) {
        return i32::max_value;
    }
    return a / b;
}

#[inline]
pub fn modulus(a : i32, b: i32) -> i32 {
    if (b == 0) { return i32::max_value }
    if (a == i32::min_value && b == -1) {
        return i32::max_value;
    }
    return a % b;
}

pub static WORDS : [&'static str, .. 13] = [
    "foo ", "bar ", "baz ", "qux ", "quux ", "corge ", "grault ", "garply ", "waldo ", "fred ",
    "plugh ", "xyzzy ", "thud "];

<|endoftext|>


<commit_before>use cairo;
use gio;
use glib;
use librsvg;
use rsvg_internals;

use gio::MemoryInputStreamExt;
use glib::Cast;

use librsvg::{CairoRenderer, Loader, RenderingError, SvgHandle};

use std::fs::File;
use std::io::BufReader;
use std::path::Path;

use self::rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

mod compare_surfaces;

use crate::compare_surfaces::{compare_surfaces, BufferDiff};

fn load_svg(input: &'static [u8]) -> SvgHandle {
    let stream = gio::MemoryInputStream::new();
    stream.add_bytes(&glib::Bytes::from_static(input));

    Loader::new()
        .read_stream(&stream.upcast(), None, None)
        .unwrap()
}

#[derive(Copy, Clone)]
struct SurfaceSize(i32, i32);

fn render_to_viewport<F: FnOnce(&cairo::Context)>(
    svg: &SvgHandle,
    surface_size: SurfaceSize,
    cr_transform: F,
    viewport: cairo::Rectangle,
) -> Result<SharedImageSurface, RenderingError> {
    let renderer = CairoRenderer::new(svg);

    let SurfaceSize(width, height) = surface_size;

    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height).unwrap();

    let res = {
        let cr = cairo::Context::new(&output);
        cr_transform(&cr);
        Ok(renderer.render_element_to_viewport(&cr, None, &viewport)?)
    };

    res.and_then(|_| Ok(SharedImageSurface::new(output, SurfaceType::SRgb)?))
}

#[test]
fn render_to_viewport_with_different_size() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(128, 128),
        |_cr| (),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 128.0,
            height: 128.0,
        },
    ).unwrap();

    let fixture_path = Path::new("tests/fixtures/rect-48x48-rendered-128x128.png");
    let mut fixture_file = BufReader::new(File::open(fixture_path).unwrap());

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::new(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(&output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}

#[test]
fn render_to_offsetted_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |_cr| (),
        cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 48.0,
            height: 48.0,
        },
    ).unwrap();

    let mut output_file = File::create(Path::new("output.png")).unwrap();
    output_surf.clone().into_image_surface().unwrap().write_to_png(&mut output_file).unwrap();

    let fixture_path = Path::new("tests/fixtures/rect-48x48-offsetted-100x100-10x20.png");
    let mut fixture_file = BufReader::new(File::open(fixture_path).unwrap());

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::new(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(&output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let mut output_file = File::create(Path::new("diff.png")).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}

#[test]
fn render_to_viewport_with_transform() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <g transform="translate(-10, -10)">
    <path fill="blue" d="M 18 18 l 32 0 l 0 32 l -32 0 z"/>
  </g>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |cr| cr.translate(10.0, 20.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 48.0,
            height: 48.0,
        },
    ).unwrap();

    let mut output_file = File::create(Path::new("output.png")).unwrap();
    output_surf.clone().into_image_surface().unwrap().write_to_png(&mut output_file).unwrap();

    let fixture_path = Path::new("tests/fixtures/rect-48x48-offsetted-100x100-10x20.png");
    let mut fixture_file = BufReader::new(File::open(fixture_path).unwrap());

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::new(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(&output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let mut output_file = File::create(Path::new("diff.png")).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}

#[test]
fn clip_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <clipPath id="one" clipPathUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5"/>
    </clipPath>
  </defs>
  <g clip-path="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    ).unwrap();

    let mut output_file = File::create(Path::new("output.png")).unwrap();
    output_surf.clone().into_image_surface().unwrap().write_to_png(&mut output_file).unwrap();

    let fixture_path = Path::new("tests/fixtures/clip-on-transformed-viewport-200x200.png");
    let mut fixture_file = BufReader::new(File::open(fixture_path).unwrap());

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::new(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(&output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let mut output_file = File::create(Path::new("diff.png")).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}

#[test]
fn mask_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <mask id="one" maskContentUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5" fill="white"/>
    </mask>
  </defs>
  <g mask="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    ).unwrap();

    let mut output_file = File::create(Path::new("output.png")).unwrap();
    output_surf.clone().into_image_surface().unwrap().write_to_png(&mut output_file).unwrap();

    let fixture_path = Path::new("tests/fixtures/mask-on-transformed-viewport-200x200.png");
    let mut fixture_file = BufReader::new(File::open(fixture_path).unwrap());

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::new(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(&output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let mut output_file = File::create(Path::new("diff.png")).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}
<commit_msg>tests/render_to_viewport.rs: Extract function to compare the test results<commit_after>use cairo;
use gio;
use glib;
use librsvg;
use rsvg_internals;

use gio::MemoryInputStreamExt;
use glib::Cast;

use librsvg::{CairoRenderer, Loader, RenderingError, SvgHandle};

use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

use self::rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

mod compare_surfaces;

use crate::compare_surfaces::{compare_surfaces, BufferDiff};

fn load_svg(input: &'static [u8]) -> SvgHandle {
    let stream = gio::MemoryInputStream::new();
    stream.add_bytes(&glib::Bytes::from_static(input));

    Loader::new()
        .read_stream(&stream.upcast(), None, None)
        .unwrap()
}

#[derive(Copy, Clone)]
struct SurfaceSize(i32, i32);

fn render_to_viewport<F: FnOnce(&cairo::Context)>(
    svg: &SvgHandle,
    surface_size: SurfaceSize,
    cr_transform: F,
    viewport: cairo::Rectangle,
) -> Result<SharedImageSurface, RenderingError> {
    let renderer = CairoRenderer::new(svg);

    let SurfaceSize(width, height) = surface_size;

    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height).unwrap();

    let res = {
        let cr = cairo::Context::new(&output);
        cr_transform(&cr);
        Ok(renderer.render_element_to_viewport(&cr, None, &viewport)?)
    };

    res.and_then(|_| Ok(SharedImageSurface::new(output, SurfaceType::SRgb)?))
}

fn test_result(output_surf: &SharedImageSurface, output_base_name: &str, fixture_filename: &str) {
    let output_path = PathBuf::from(&format!("{}-out.png", output_base_name));
    let fixture_path = PathBuf::from(&format!("tests/fixtures/{}", fixture_filename));

    let mut output_file = File::create(output_path).unwrap();
    output_surf
        .clone()
        .into_image_surface()
        .unwrap()
        .write_to_png(&mut output_file)
        .unwrap();

    let file =
        File::open(fixture_path).expect("cannot find {} - are you in the librsvg_crate directory?");

    let mut fixture_file = BufReader::new(file);

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::new(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let diff_path = PathBuf::from(format!("{}-diff.png", output_base_name));
            let mut output_file = File::create(diff_path).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}

#[test]
fn render_to_viewport_with_different_size() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(128, 128),
        |_cr| (),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 128.0,
            height: 128.0,
        },
    )
    .unwrap();

    test_result(
        &output_surf,
        "render_to_viewport_with_different_size",
        "rect-48x48-rendered-128x128.png",
    );
}

#[test]
fn render_to_offsetted_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |_cr| (),
        cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 48.0,
            height: 48.0,
        },
    )
    .unwrap();

    test_result(
        &output_surf,
        "render_to_offseted_viewport",
        "rect-48x48-offsetted-100x100-10x20.png",
    );
}

#[test]
fn render_to_viewport_with_transform() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <g transform="translate(-10, -10)">
    <path fill="blue" d="M 18 18 l 32 0 l 0 32 l -32 0 z"/>
  </g>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |cr| cr.translate(10.0, 20.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 48.0,
            height: 48.0,
        },
    )
    .unwrap();

    test_result(
        &output_surf,
        "render_to_viewport_with_transform",
        "rect-48x48-offsetted-100x100-10x20.png",
    );
}

#[test]
fn clip_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <clipPath id="one" clipPathUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5"/>
    </clipPath>
  </defs>
  <g clip-path="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    test_result(
        &output_surf,
        "clip_on_transformed_viewport",
        "clip-on-transformed-viewport-200x200.png",
    );
}

#[test]
fn mask_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <mask id="one" maskContentUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5" fill="white"/>
    </mask>
  </defs>
  <g mask="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    test_result(
        &output_surf,
        "mask_on_transformed_viewport",
        "mask-on-transformed-viewport-200x200.png",
    );
}
<|endoftext|>


<commit_before>//! Store SBD messages on the filesystem.

use std::fs;
use std::path::{Path, PathBuf};

use walkdir;

use {Result, Error};
use mo::Message;
use storage;

const SBD_EXTENSION: &'static str = "sbd";

/// A structure for managing storing and retriving SBD messages on a filesystem.
///
/// Messages are stored in a directory hierarchy under a single root directory.
/// Message storage and retrieval are managed by a `Storage` object, which is
/// configured for a single root directory.
#[derive(Debug)]
pub struct Storage {
    root: PathBuf,
}

impl Storage {
    /// Opens a new storage for a given directory.
    ///
    /// # Errors
    ///
    /// If the directory does not exist, returns an `NotADirectory` error.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::storage::FilesystemStorage;
    /// let storage = FilesystemStorage::open("data").unwrap();
    /// assert!(FilesystemStorage::open("not/a/directory").is_err());
    /// ```
    pub fn open<P: AsRef<Path>>(root: P) -> Result<Storage> {
        let metadata = try!(fs::metadata(root.as_ref()));
        if !metadata.is_dir() {
            Err(Error::NotADirectory(root.as_ref().as_os_str().to_os_string()))
        } else {
            Ok(Storage { root: root.as_ref().to_path_buf() })
        }
    }

    /// Returns a `StorageIterator` over the messages in this storage.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::storage::FilesystemStorage;
    /// for message in FilesystemStorage::open("data").unwrap().iter() {
    ///     println!("{:?}", message);
    /// }
    /// ```
    pub fn iter(&self) -> StorageIterator {
        StorageIterator::new(&self)
    }
}

impl storage::Storage for Storage {
    fn store(&mut self, message: Message) -> Result<()> {
        let mut path_buf = self.root.clone();
        path_buf.push(message.imei());
        path_buf.push(message.time_of_session().format("%Y").to_string());
        path_buf.push(message.time_of_session().format("%m").to_string());
        try!(fs::create_dir_all(&path_buf));
        path_buf.push(message.time_of_session()
            .format(&format!("%y%m%d_%H%M%S.{}", SBD_EXTENSION))
            .to_string());
        let mut file = try!(fs::File::create(&path_buf));
        try!(message.write_to(&mut file));
        Ok(())
    }

    fn messages(&self) -> Result<Vec<Message>> {
        self.iter().collect()
    }
}

/// An iterator over the messages in a `Storage`.
///
/// For now, this iterator will just return all messages with an `sbd` extension under the root of
/// the storage tree. We could try to get smarter and mirror the pattern logic for saving, but for
/// now that's more work and complexity than we need.
///
/// # Errors
///
/// This iterator's `Item` is a `sbd::Result<Message>`, because a file with an `sbd` extension
/// might not convert to a message successfully.
#[allow(missing_debug_implementations)]
pub struct StorageIterator {
    iter: walkdir::Iter,
}

impl StorageIterator {
    fn new(storage: &Storage) -> StorageIterator {
        StorageIterator { iter: walkdir::WalkDir::new(&storage.root).into_iter() }
    }
}

impl Iterator for StorageIterator {
    type Item = Result<Message>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .by_ref()
            .skip_while(|r| {
                r.as_ref()
                    .map(|d| d.path().extension().map(|e| e != SBD_EXTENSION).unwrap_or(true))
                    .unwrap_or(true)
            })
            .next()
            .map(|r| r.map_err(|e| Error::from(e)).and_then(|d| Message::from_path(d.path())))
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;

    extern crate tempdir;
    use self::tempdir::TempDir;

    use super::*;

    use mo::Message;
    use storage::Storage as StorageTrait;

    #[test]
    fn open() {
        Storage::open(TempDir::new("").unwrap().path()).unwrap();
    }

    #[test]
    fn no_directory() {
        assert!(Storage::open("not/a/real/directory").is_err());
    }

    #[test]
    fn file_is_error() {
        assert!(Storage::open("data/0-mo.sbd").is_err());
    }

    #[test]
    fn store() {
        let tempdir = TempDir::new("").unwrap();
        let mut storage = Storage::open(tempdir.path()).unwrap();
        let message = Message::from_path("data/0-mo.sbd").unwrap();
        storage.store(message).unwrap();
        let mut message_path = PathBuf::from(tempdir.path());
        message_path.push("300234063904190");
        message_path.push("2015");
        message_path.push("07");
        message_path.push("150709_181508.sbd");
        Message::from_path(message_path).unwrap();
    }

    #[test]
    fn iter() {
        let tempdir = TempDir::new("").unwrap();
        let mut storage = Storage::open(tempdir.path()).unwrap();
        assert_eq!(0, storage.iter().collect::<Vec<_>>().len());
        let message = Message::from_path("data/0-mo.sbd").unwrap();
        storage.store(message).unwrap();
        assert_eq!(1, storage.iter().collect::<Vec<_>>().len());
    }
}
<commit_msg>Specialize a imei message grab for filesystem<commit_after>//! Store SBD messages on the filesystem.

use std::fs;
use std::path::{Path, PathBuf};

use walkdir;

use {Result, Error};
use mo::Message;
use storage;

const SBD_EXTENSION: &'static str = "sbd";

/// A structure for managing storing and retriving SBD messages on a filesystem.
///
/// Messages are stored in a directory hierarchy under a single root directory.
/// Message storage and retrieval are managed by a `Storage` object, which is
/// configured for a single root directory.
#[derive(Debug)]
pub struct Storage {
    root: PathBuf,
}

impl Storage {
    /// Opens a new storage for a given directory.
    ///
    /// # Errors
    ///
    /// If the directory does not exist, returns an `NotADirectory` error.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::storage::FilesystemStorage;
    /// let storage = FilesystemStorage::open("data").unwrap();
    /// assert!(FilesystemStorage::open("not/a/directory").is_err());
    /// ```
    pub fn open<P: AsRef<Path>>(root: P) -> Result<Storage> {
        let metadata = try!(fs::metadata(root.as_ref()));
        if !metadata.is_dir() {
            Err(Error::NotADirectory(root.as_ref().as_os_str().to_os_string()))
        } else {
            Ok(Storage { root: root.as_ref().to_path_buf() })
        }
    }

    /// Returns a `StorageIterator` over the messages in this storage.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::storage::FilesystemStorage;
    /// for message in FilesystemStorage::open("data").unwrap().iter() {
    ///     println!("{:?}", message);
    /// }
    /// ```
    pub fn iter(&self) -> StorageIterator {
        StorageIterator::new(&self.root)
    }
}

impl storage::Storage for Storage {
    fn store(&mut self, message: Message) -> Result<()> {
        let mut path_buf = self.root.clone();
        path_buf.push(message.imei());
        path_buf.push(message.time_of_session().format("%Y").to_string());
        path_buf.push(message.time_of_session().format("%m").to_string());
        try!(fs::create_dir_all(&path_buf));
        path_buf.push(message.time_of_session()
            .format(&format!("%y%m%d_%H%M%S.{}", SBD_EXTENSION))
            .to_string());
        let mut file = try!(fs::File::create(&path_buf));
        try!(message.write_to(&mut file));
        Ok(())
    }

    fn messages(&self) -> Result<Vec<Message>> {
        self.iter().collect()
    }

    fn messages_from_imei(&self, imei: &str) -> Result<Vec<Message>> {
        let mut path = self.root.clone();
        path.push(imei);
        StorageIterator::new(&path).collect()
    }
}

/// An iterator over the messages in a `Storage`.
///
/// For now, this iterator will just return all messages with an `sbd` extension under the root of
/// the storage tree. We could try to get smarter and mirror the pattern logic for saving, but for
/// now that's more work and complexity than we need.
///
/// # Errors
///
/// This iterator's `Item` is a `sbd::Result<Message>`, because a file with an `sbd` extension
/// might not convert to a message successfully.
#[allow(missing_debug_implementations)]
pub struct StorageIterator {
    iter: walkdir::Iter,
}

impl StorageIterator {
    fn new(root: &Path) -> StorageIterator {
        StorageIterator { iter: walkdir::WalkDir::new(root).into_iter() }
    }
}

impl Iterator for StorageIterator {
    type Item = Result<Message>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .by_ref()
            .skip_while(|r| {
                r.as_ref()
                    .map(|d| d.path().extension().map(|e| e != SBD_EXTENSION).unwrap_or(true))
                    .unwrap_or(true)
            })
            .next()
            .map(|r| r.map_err(|e| Error::from(e)).and_then(|d| Message::from_path(d.path())))
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;

    extern crate tempdir;
    use self::tempdir::TempDir;

    use super::*;

    use mo::Message;
    use storage::Storage as StorageTrait;

    #[test]
    fn open() {
        Storage::open(TempDir::new("").unwrap().path()).unwrap();
    }

    #[test]
    fn no_directory() {
        assert!(Storage::open("not/a/real/directory").is_err());
    }

    #[test]
    fn file_is_error() {
        assert!(Storage::open("data/0-mo.sbd").is_err());
    }

    #[test]
    fn store() {
        let tempdir = TempDir::new("").unwrap();
        let mut storage = Storage::open(tempdir.path()).unwrap();
        let message = Message::from_path("data/0-mo.sbd").unwrap();
        storage.store(message).unwrap();
        let mut message_path = PathBuf::from(tempdir.path());
        message_path.push("300234063904190");
        message_path.push("2015");
        message_path.push("07");
        message_path.push("150709_181508.sbd");
        Message::from_path(message_path).unwrap();
    }

    #[test]
    fn iter() {
        let tempdir = TempDir::new("").unwrap();
        let mut storage = Storage::open(tempdir.path()).unwrap();
        assert_eq!(0, storage.iter().collect::<Vec<_>>().len());
        let message = Message::from_path("data/0-mo.sbd").unwrap();
        storage.store(message).unwrap();
        assert_eq!(1, storage.iter().collect::<Vec<_>>().len());
    }

    #[test]
    fn messages_from_imei() {
        let tempdir = TempDir::new("").unwrap();
        let mut storage = Storage::open(tempdir.path()).unwrap();
        let message = Message::from_path("data/0-mo.sbd").unwrap();
        storage.store(message.clone()).unwrap();
        let messages = storage.messages_from_imei("300234063904190").unwrap();
        assert_eq!(vec![message], messages);
        let messages = storage.messages_from_imei("300234063904191").unwrap();
        assert!(messages.is_empty());
    }

}
<|endoftext|>


<commit_before>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use std::io;

pub struct Simple<Io: io::Write> {
    buf: Io
}

impl<T : io::Write> Simple<T> {
    fn new(buf: T) -> Simple<T> {
        Simple { buf: buf }
    }
}

impl<T : io::Write> EventHandler for Simple<T> {
    fn trigger(&mut self, _event: Event) {
    }
}
impl<T : io::Write> Formatter for Simple<T> {}

#[cfg(test)]
mod tests {
    pub use super::*;
    pub use formatter::formatter::Formatter;

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(vec!(1u8));
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _ : &Formatter = &Simple::new(vec!(1u8)) as &Formatter;
    }

    #[cfg(test)]
    mod event_finished_runner {
        pub use super::*;
        use events::{Event, EventHandler};

        #[test]
        fn it_display_a_recap() {
            let mut s = Simple::new(vec!(1u8));
            s.trigger(Event::StartRunner)
        }
    }
}
<commit_msg> Display that tests started<commit_after>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io
}

impl<'a, T : io::Write> Simple<'a, T> {
    fn new<'b>(buf: &'b mut T) -> Simple<'b, T> {
        Simple { buf: buf }
    }
}

impl<'a, T : io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, _event: Event) {
        // ignore errors
        let _ = self.buf.write(b"Running tests...\n");
    }
}
impl<'a, T : io::Write> Formatter for Simple<'a, T> {}

#[cfg(test)]
mod tests {
    pub use super::*;
    pub use formatter::formatter::Formatter;

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec!(1u8));
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _ : &Formatter = &Simple::new(&mut vec!(1u8)) as &Formatter;
    }

    #[cfg(test)]
    mod event_finished_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use std::str;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::StartRunner);
            }

            assert_eq!("Running tests...\n", str::from_utf8(&v).unwrap());
        }
    }
}
<|endoftext|>