<commit_before>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(core,no_std)]

extern crate core;
extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;

use core::prelude::*;
use hil::Controller;

pub struct Firestorm {
    chip: &'static mut sam4l::chip::Sam4l,
    console: drivers::console::Console<sam4l::usart::USART>,
    gpio: drivers::gpio::GPIO<[&'static mut hil::gpio::GPIOPin; 14]>,
    tmp006: drivers::tmp006::TMP006<sam4l::i2c::I2CDevice>
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    pub fn with_driver<F, R>(&mut self, driver_num: usize, mut f: F) -> R where
            F: FnMut(Option<&mut hil::Driver>) -> R {

        f(match driver_num {
            0 => Some(&mut self.console),
            1 => Some(&mut self.gpio),
            2 => Some(&mut self.tmp006),
            _ => None
        })
    }

}

static mut FIRESTORM_BUF : [u8; 152] = [0; 152];
static mut CHIP_BUF : [u8; 924] = [0; 924];

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    // Just test that CHIP_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : sam4l::chip::Sam4l = mem::transmute(CHIP_BUF);

    let chip : &'static mut sam4l::chip::Sam4l = mem::transmute(&mut CHIP_BUF);
    *chip = sam4l::chip::Sam4l::new();
    sam4l::chip::INTERRUPT_QUEUE = Some(&mut chip.queue);

    // Just test that FIRESTORM_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : Firestorm = mem::transmute(FIRESTORM_BUF);

    let firestorm : &'static mut Firestorm = mem::transmute(&mut FIRESTORM_BUF);
    *firestorm = Firestorm {
        chip: chip,
        console: drivers::console::Console::new(&mut chip.usarts[3]),
        gpio: drivers::gpio::GPIO::new(
            [ &mut chip.pc10, &mut chip.pc19, &mut chip.pc13
            , &mut chip.pa09, &mut chip.pa17, &mut chip.pc20
            , &mut chip.pa19, &mut chip.pa14, &mut chip.pa16
            , &mut chip.pa13, &mut chip.pa11, &mut chip.pa10
            , &mut chip.pa12, &mut chip.pc09]),
        tmp006: drivers::tmp006::TMP006::new(&mut chip.i2c[2]),
    };

    chip.usarts[3].configure(sam4l::usart::USARTParams {
        client: &mut firestorm.console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    chip.pb09.configure(Some(sam4l::gpio::PeripheralFunction::A));
    chip.pb10.configure(Some(sam4l::gpio::PeripheralFunction::A));

    chip.pa21.configure(Some(sam4l::gpio::PeripheralFunction::E));
    chip.pa22.configure(Some(sam4l::gpio::PeripheralFunction::E));

    firestorm.console.initialize();
    firestorm
}

<commit_msg>inline FIRESTORM_ and CHIP_ buffers in platform init function<commit_after>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(core,no_std)]

extern crate core;
extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;

use core::prelude::*;
use hil::Controller;

pub struct Firestorm {
    chip: &'static mut sam4l::chip::Sam4l,
    console: drivers::console::Console<sam4l::usart::USART>,
    gpio: drivers::gpio::GPIO<[&'static mut hil::gpio::GPIOPin; 14]>,
    tmp006: drivers::tmp006::TMP006<sam4l::i2c::I2CDevice>
}

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    pub fn with_driver<F, R>(&mut self, driver_num: usize, mut f: F) -> R where
            F: FnMut(Option<&mut hil::Driver>) -> R {

        f(match driver_num {
            0 => Some(&mut self.console),
            1 => Some(&mut self.gpio),
            2 => Some(&mut self.tmp006),
            _ => None
        })
    }

}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    static mut CHIP_BUF : [u8; 924] = [0; 924];
    // Just test that CHIP_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : sam4l::chip::Sam4l = mem::transmute(CHIP_BUF);

    let chip : &'static mut sam4l::chip::Sam4l = mem::transmute(&mut CHIP_BUF);
    *chip = sam4l::chip::Sam4l::new();
    sam4l::chip::INTERRUPT_QUEUE = Some(&mut chip.queue);

    static mut FIRESTORM_BUF : [u8; 152] = [0; 152];
    // Just test that FIRESTORM_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : Firestorm = mem::transmute(FIRESTORM_BUF);

    let firestorm : &'static mut Firestorm = mem::transmute(&mut FIRESTORM_BUF);
    *firestorm = Firestorm {
        chip: chip,
        console: drivers::console::Console::new(&mut chip.usarts[3]),
        gpio: drivers::gpio::GPIO::new(
            [ &mut chip.pc10, &mut chip.pc19, &mut chip.pc13
            , &mut chip.pa09, &mut chip.pa17, &mut chip.pc20
            , &mut chip.pa19, &mut chip.pa14, &mut chip.pa16
            , &mut chip.pa13, &mut chip.pa11, &mut chip.pa10
            , &mut chip.pa12, &mut chip.pc09]),
        tmp006: drivers::tmp006::TMP006::new(&mut chip.i2c[2]),
    };

    chip.usarts[3].configure(sam4l::usart::USARTParams {
        client: &mut firestorm.console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    chip.pb09.configure(Some(sam4l::gpio::PeripheralFunction::A));
    chip.pb10.configure(Some(sam4l::gpio::PeripheralFunction::A));

    chip.pa21.configure(Some(sam4l::gpio::PeripheralFunction::E));
    chip.pa22.configure(Some(sam4l::gpio::PeripheralFunction::E));

    firestorm.console.initialize();
    firestorm
}

<|endoftext|>


<commit_before>use std::fs::File;
use std::path::Path;
use std::io::prelude::*;
use pest::prelude::*;
use std::collections::VecDeque;

impl_rdp! {
    grammar! {
        chunk = _{ soi ~ structdef* ~ eoi }

        structdef   =  { name ~ derive? ~ ["{"] ~ fieldlist? ~ ["}"] }
        fieldlist   =  { field ~ (fieldsep ~ field)* ~ fieldsep* }
        field       =  { var | function }
        fieldsep    = _{ [","] }

        rettype     = { name }
        derive      = { [":"] ~ name }
        callback    = { ["[callback]"] }
        retexp      = { ["->"] ~ name }
        var         = { name ~ name }
        varlist     = { var ~ ([","] ~ var)* }
        function    = { callback? ~ name ~ ["("] ~ varlist? ~ [")"] ~ retexp? }

        name = @{
            (['a'..'z'] | ['A'..'Z'] | ["_"]) ~ (['a'..'z'] | ['A'..'Z'] | ["_"] | ['0'..'9'])*
        }

       comment = _{
            ["//"] ~ (!(["\r"] | ["\n"]) ~ any)* ~ (["\n"] | ["\r\n"] | ["\r"] | eoi)
        }

        whitespace = _{ [" "] | ["\t"] | ["\u{000C}"] | ["\r"] | ["\n"] }
    }

    process! {
        process(&self) -> Vec<Struct<'input>> {
            (structs: _chunk()) => {
                structs
            },
        }

        _chunk(&self) -> Vec<Struct<'input>> {
            (_: structdef, sdef: _structdef(), mut tail: _chunk()) => {
                println!("push push");
                tail.push(sdef);
                tail
            },

            () => Vec::new(),
        }

        _structdef(&self) -> Struct<'input> {
            (&name: name, inherit: _derive(), list: _fieldlist()) => {
                let t = Struct {
                    name: name,
                    inherit: inherit,
                    entries: list.into_iter().collect::<Vec<_>>(),
                };

                println!("Created struct {:?}", t);

                t
            },
        }

        _derive(&self) -> Option<&'input str> {
            (_: derive, &name: name) => Some(name),
            () => None,
        }

        _fieldlist(&self) -> VecDeque<StructEntry<'input>> {
            (_: fieldlist, entries: _fieldentries()) => {
                entries
            },

            () => VecDeque::new(),
        }

        _fieldentries(&self) -> VecDeque<StructEntry<'input>> {
            (_: field, entry: _fieldentry(), mut tail: _fieldentries()) => {
                println!("_fieldentries");
                tail.push_front(entry);
                tail
            },

            () => {
                println!("_fieldentries::new");
                VecDeque::new()
            }
        }

        _fieldentry(&self) -> StructEntry<'input> {
            (_: function, func: _funcentry()) => {
                func
            },

            (_: var, &vtype: name, &name: name) => {
                StructEntry::Var(Variable {
                    name: name,
                    vtype: vtype,
                })
            },
        }

        _funcentry(&self) -> StructEntry<'input> {
            (callback: _callback(), &name: name, func_args: _func_args_list(), ret_value: _returnvalue()) => {
                StructEntry::Function(Function {
                    name: name,
                    function_args: func_args.into_iter().collect::<Vec<_>>(),
                    return_val: ret_value,
                    callback: callback,
                })
            }
        }

        _callback(&self) -> bool {
            (_: callback) => true,
            () => false,
        }

        _returnvalue(&self) -> Option<&'input str> {
            (_: retexp, &name: name) => Some(name),
            () => None,
        }

        _func_args_list(&self) -> VecDeque<Variable<'input>> {
            (_: var, &name: name, &atype: name, mut tail: _func_args_list()) => {
                tail.push_front(Variable {
                    name: name,
                    vtype: atype,
                });

                tail
            },

            (_: varlist, tail: _func_args_list()) => tail,
            () => VecDeque::new(),
        }
    }
}

#[derive(Debug)]
pub struct Variable<'a> {
    pub name: &'a str,
    pub vtype: &'a str,
}

#[derive(Debug)]
pub struct Function<'a> {
    pub name: &'a str,
    pub function_args: Vec<Variable<'a>>,
    pub return_val: Option<&'a str>,
    pub callback: bool,
}

#[derive(Debug)]
pub enum StructEntry<'a> {
    Var(Variable<'a>),
    Function(Function<'a>),
}

#[derive(Debug)]
pub struct Struct<'a> {
    pub name: &'a str,
    pub inherit: Option<&'a str>,
    pub entries: Vec<StructEntry<'a>>,
}

impl<'a> Struct<'a> {
    fn new() -> Struct<'a> {
        Struct {
            name: "",
            inherit: None,
            entries: Vec::new(),
        }
    }
}

#[derive(Debug)]
pub struct ApiDef<'a> {
    pub text: String,
    pub entries: Vec<Struct<'a>>,
}

impl<'a> ApiDef<'a> {
    pub fn parse_file<P: AsRef<Path>>(&'a mut self, path: P) {
        let mut file = File::open(path).unwrap();
        file.read_to_string(&mut self.text).unwrap();

        let mut parser = Rdp::new(StringInput::new(&self.text));

        parser.chunk();

        if !parser.end() {
            let expected = parser.expected();
            panic!("Failed to parse {:?} - {}", parser.expected(), &self.text[expected.1..]);
        }

        //let mut struct_def = Struct::new();
        //let mut state = State::StructDef;

        // We could do this using process! instead the parser instead but as the rules
        // are quite simple we just do a basic state machine istead

        parser.process();

        for token in parser.queue() {
            println!("{:?}", token);
        }

        /*
        let mut queue = parser.queue().iter();

        loop {
            match queue.next() {
                Some(token) => {
                    match token.rule {
                        Rule::structdef => {
                            let mut struct_def = Struct::new();
                            let t: i32 = queue;
                        }

                        _ => (),

                    }
                }

                None => { break },
            }
        }
        */

        /*

        for token in queue {
            println!("{:?}", token);

            match token.rule {
                Rule::name => {
                    match state {
                        State::StructDef => struct_def.name = &self.text[token.start..token.end],
                        State::Derive => struct_def.inherit = Some(&self.text[token.start..token.end]),
                        _ => (),
                    }
                }

                Rule::structdef => {
                    println!("{:?}", struct_def);
                    struct_def = Struct::new();
                    state = State::StructDef;
                },

                Rule::derive => state = State::Derive,

                _ => (),
            }
        */

            /*
            match token.rule {
                Rule::structdef => {
                    let t = parser.process_struct();
                    println!("{:?}", t);
                }

                _ => (),
            }

            let s = Struct {
                name: &self.text[0..3],
                inharit: None,
                entries: Vec::new(),
            };

            self.entries.push(s);
            */

            /*
            match token.rule {
            }
            */
        //}

        // build up tokens here
    }
}
<commit_msg>Fully working parsing now<commit_after>use std::fs::File;
use std::path::Path;
use std::io::prelude::*;
use pest::prelude::*;
use std::collections::VecDeque;

impl_rdp! {
    grammar! {
        chunk = _{ soi ~ structdef* ~ eoi }

        structdef   =  { name ~ derive? ~ ["{"] ~ fieldlist? ~ ["}"] }
        fieldlist   =  { field ~ (fieldsep ~ field)* ~ fieldsep* }
        field       =  { var | function }
        fieldsep    = _{ [","] }

        rettype     = { name }
        derive      = { [":"] ~ name }
        callback    = { ["[callback]"] }
        retexp      = { ["->"] ~ name }
        var         = { name ~ name }
        varlist     = { var ~ ([","] ~ var)* }
        function    = { callback? ~ name ~ ["("] ~ varlist? ~ [")"] ~ retexp? }

        name = @{
            (['a'..'z'] | ['A'..'Z'] | ["_"]) ~ (['a'..'z'] | ['A'..'Z'] | ["_"] | ['0'..'9'])*
        }

       comment = _{
            ["//"] ~ (!(["\r"] | ["\n"]) ~ any)* ~ (["\n"] | ["\r\n"] | ["\r"] | eoi)
        }

        whitespace = _{ [" "] | ["\t"] | ["\u{000C}"] | ["\r"] | ["\n"] }
    }

    process! {
        process(&self) -> Vec<Struct<'input>> {
            (structs: _chunk()) => {
                structs.into_iter().collect::<Vec<_>>()
            },
        }

        _chunk(&self) -> VecDeque<Struct<'input>> {
            (_: structdef, sdef: _structdef(), mut tail: _chunk()) => {
                println!("push push");
                tail.push_front(sdef);
                tail
            },

            () => VecDeque::new(),
        }

        _structdef(&self) -> Struct<'input> {
            (&name: name, inherit: _derive(), list: _fieldentries()) => {
                Struct {
                    name: name,
                    inherit: inherit,
                    entries: list.into_iter().collect::<Vec<_>>(),
                }
            },
        }

        _derive(&self) -> Option<&'input str> {
            (_: derive, &name: name) => Some(name),
            () => None,
        }

        _fieldentries(&self) -> VecDeque<StructEntry<'input>> {
            (_: field, entry: _fieldentry(), mut tail: _fieldentries()) => {
                tail.push_front(entry);
                tail
            },

            (_: fieldlist, entries: _fieldentries()) => entries,
            () => VecDeque::new(),
        }

        _fieldentry(&self) -> StructEntry<'input> {
            (_: function, func: _funcentry()) => func,

            (_: var, &vtype: name, &name: name) => {
                StructEntry::Var(Variable {
                    name: name,
                    vtype: vtype,
                })
            },
        }

        _funcentry(&self) -> StructEntry<'input> {
            (callback: _callback(), &name: name, func_args: _func_args_list(), ret_value: _returnvalue()) => {
                StructEntry::Function(Function {
                    name: name,
                    function_args: func_args.into_iter().collect::<Vec<_>>(),
                    return_val: ret_value,
                    callback: callback,
                })
            }
        }

        _callback(&self) -> bool {
            (_: callback) => true,
            () => false,
        }

        _returnvalue(&self) -> Option<&'input str> {
            (_: retexp, &name: name) => Some(name),
            () => None,
        }

        _func_args_list(&self) -> VecDeque<Variable<'input>> {
            (_: var, &name: name, &atype: name, mut tail: _func_args_list()) => {
                tail.push_front(Variable {
                    name: name,
                    vtype: atype,
                });

                tail
            },

            (_: varlist, tail: _func_args_list()) => tail,
            () => VecDeque::new(),
        }
    }
}

#[derive(Debug)]
pub struct Variable<'a> {
    pub name: &'a str,
    pub vtype: &'a str,
}

#[derive(Debug)]
pub struct Function<'a> {
    pub name: &'a str,
    pub function_args: Vec<Variable<'a>>,
    pub return_val: Option<&'a str>,
    pub callback: bool,
}

#[derive(Debug)]
pub enum StructEntry<'a> {
    Var(Variable<'a>),
    Function(Function<'a>),
}

#[derive(Debug)]
pub struct Struct<'a> {
    pub name: &'a str,
    pub inherit: Option<&'a str>,
    pub entries: Vec<StructEntry<'a>>,
}

#[derive(Debug)]
pub struct ApiDef<'a> {
    pub text: String,
    pub entries: Vec<Struct<'a>>,
}

impl<'a> ApiDef<'a> {
    pub fn parse_file<P: AsRef<Path>>(&'a mut self, path: P) {
        let mut file = File::open(path).unwrap();
        file.read_to_string(&mut self.text).unwrap();

        let mut parser = Rdp::new(StringInput::new(&self.text));

        parser.chunk();

        if !parser.end() {
            let expected = parser.expected();
            panic!("Failed to parse {:?} - {}", parser.expected(), &self.text[expected.1..]);
        }

        let t = parser.process();

        println!("API {:?}", t);
    }
}
<|endoftext|>


<commit_before>//! Work with las headers and the information contained therin.
//!
//! Headers are very important, as they describe the layout of points in the file, as well as the
//! scaling and offset of the data in each point. Working with headers is generally a low-level
//! operation, and downstream users should prefer to use the builder methods of `Writer` to
//! configure behavior.

use std::io::{Read, Write};
use std::fmt;
use std::iter::repeat;

use byteorder::{LittleEndian, ReadBytesExt};
use time;

use Result;
use error::Error;
use io::read_full;

/// This constant value is the bytes in your normal header. There are worlds where people put crap
/// into headers that don't belong there, so we have to guard against this.
pub const DEFAULT_BYTES_IN_HEADER: u16 = 227;

/// A las header.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Header {
    /// The las file signature.
    ///
    /// Should always be "LASF".
    pub file_signature: [u8; 4],
    /// A numeric identifier for this file.
    pub file_source_id: u16,
    /// What is the reference system for the timestamps in each point data record? This field was
    /// added in las 1.2.
    pub gps_time_type: GpsTimeType,
    /// The first of four parts of the project id.
    pub guid_data_1: u32,
    /// The second of four parts of the project id.
    pub guid_data_2: u16,
    /// The third of four parts of the project id.
    pub guid_data_3: u16,
    /// The fourth of four parts of the project id.
    pub guid_data_4: [u8; 8],
    /// The las format version.
    pub version: Version,
    /// Generally the hardware system that created the las file.
    ///
    /// Can also be the algorithm that produced the lasfile. This field is poorly defined.
    pub system_identifier: [u8; 32],
    /// The software the generated the las file.
    pub generating_software: [u8; 32],
    /// The day of the year, indexed to 1.
    pub file_creation_day_of_year: u16,
    /// The year of file creation.
    pub file_creation_year: u16,
    /// The size of the las header.
    ///
    /// Softwares are technically allowed to add custom extensions to the las header, which would
    /// then affect this header size, but that is discouraged as such support is not universal.
    pub header_size: u16,
    /// The byte offset to the beginning of point data.
    ///
    /// Includes the size of the header and the variable length records.
    pub offset_to_point_data: u32,
    /// The number of variable length records.
    pub number_of_variable_length_records: u32,
    /// The point data format.
    pub point_data_format: PointFormat,
    /// The length of one point data record, in bytes.
    pub point_data_record_length: u16,
    /// The total number of point records.
    pub number_of_point_records: u32,
    /// The number of point records of each return number.
    ///
    /// This only supports five returns per pulse.
    pub number_of_points_by_return: [u32; 5],
    /// The x scale factor for each point.
    pub x_scale_factor: f64,
    /// The y scale factor for each point.
    pub y_scale_factor: f64,
    /// The z scale factor for each point.
    pub z_scale_factor: f64,
    /// The x offset for each point.
    pub x_offset: f64,
    /// The y offset for each point.
    pub y_offset: f64,
    /// The z offset for each point.
    pub z_offset: f64,
    /// The maximum x value.
    pub x_max: f64,
    /// The minimum x value.
    pub x_min: f64,
    /// The maximum y value.
    pub y_max: f64,
    /// The minimum y value.
    pub y_min: f64,
    /// The maximum z value.
    pub z_max: f64,
    /// The minimum z value.
    pub z_min: f64,
}

impl Header {
    /// Reads a header from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use las::header::Header;
    /// let ref mut file = File::open("data/1.0_0.las").unwrap();
    /// let header = Header::read_from(file);
    /// ```
    pub fn read_from<R: Read>(reader: &mut R) -> Result<Header> {
        let mut header = Header::new();
        try!(read_full(reader, &mut header.file_signature));
        header.file_source_id = try!(reader.read_u16::<LittleEndian>());
        let global_encoding = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_1 = try!(reader.read_u32::<LittleEndian>());
        header.guid_data_2 = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_3 = try!(reader.read_u16::<LittleEndian>());
        try!(read_full(reader, &mut header.guid_data_4));
        let version_major = try!(reader.read_u8());
        let version_minor = try!(reader.read_u8());
        header.version = Version::new(version_major, version_minor);
        try!(read_full(reader, &mut header.system_identifier));
        try!(read_full(reader, &mut header.generating_software));
        header.file_creation_day_of_year = try!(reader.read_u16::<LittleEndian>());
        header.file_creation_year = try!(reader.read_u16::<LittleEndian>());
        header.header_size = try!(reader.read_u16::<LittleEndian>());
        header.offset_to_point_data = try!(reader.read_u32::<LittleEndian>());
        header.number_of_variable_length_records = try!(reader.read_u32::<LittleEndian>());
        header.point_data_format = try!(PointFormat::from_u8(try!(reader.read_u8())));
        header.point_data_record_length = try!(reader.read_u16::<LittleEndian>());
        header.number_of_point_records = try!(reader.read_u32::<LittleEndian>());
        for n in &mut header.number_of_points_by_return {
            *n = try!(reader.read_u32::<LittleEndian>());
        }
        header.x_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.y_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.z_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.x_offset = try!(reader.read_f64::<LittleEndian>());
        header.y_offset = try!(reader.read_f64::<LittleEndian>());
        header.z_offset = try!(reader.read_f64::<LittleEndian>());
        header.x_max = try!(reader.read_f64::<LittleEndian>());
        header.x_min = try!(reader.read_f64::<LittleEndian>());
        header.y_max = try!(reader.read_f64::<LittleEndian>());
        header.y_min = try!(reader.read_f64::<LittleEndian>());
        header.z_max = try!(reader.read_f64::<LittleEndian>());
        header.z_min = try!(reader.read_f64::<LittleEndian>());

        if header.version.has_gps_time_type() {
            header.gps_time_type = GpsTimeType::from_global_encoding(global_encoding);
        }

        Ok(header)
    }

    /// Creates a new, empty header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Header;
    /// let header = Header::new();
    /// ```
    pub fn new() -> Header {
        let name_and_version = format!("las-rs {}", env!("CARGO_PKG_VERSION")).into_bytes();
        let mut generating_software = [0; 32];
        for (c, b) in name_and_version.iter()
                                      .chain(repeat(&0).take(generating_software.len() -
                                                             name_and_version.len()))
                                      .zip(generating_software.iter_mut()) {
            *b = *c;
        }
        let now = time::now();
        Header {
            file_signature: *b"LASF",
            file_source_id: 0,
            gps_time_type: GpsTimeType::Week,
            guid_data_1: 0,
            guid_data_2: 0,
            guid_data_3: 0,
            guid_data_4: [0; 8],
            version: Version::new(1, 0),
            system_identifier: [0; 32],
            generating_software: generating_software,
            file_creation_day_of_year: now.tm_yday as u16,
            file_creation_year: now.tm_year as u16,
            header_size: 0,
            offset_to_point_data: 0,
            number_of_variable_length_records: 0,
            point_data_format: PointFormat(0),
            point_data_record_length: 0,
            number_of_point_records: 0,
            number_of_points_by_return: [0; 5],
            x_scale_factor: 1.0,
            y_scale_factor: 1.0,
            z_scale_factor: 1.0,
            x_offset: 0.0,
            y_offset: 0.0,
            z_offset: 0.0,
            x_max: 0.0,
            x_min: 0.0,
            y_max: 0.0,
            y_min: 0.0,
            z_max: 0.0,
            z_min: 0.0,
        }
    }
}

/// A wrapper around the u8 of a point data format.
///
/// Formats have powers, so we encapsulate that through this struct.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PointFormat(pub u8);

impl PointFormat {
    /// Creates a point data format for this u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert!(PointFormat::from_u8(0).is_ok());
    /// assert!(PointFormat::from_u8(1).is_ok());
    /// assert!(PointFormat::from_u8(127).is_err());
    /// ```
    pub fn from_u8(n: u8) -> Result<PointFormat> {
        if n < 4 {
            Ok(PointFormat(n))
        } else {
            Err(Error::InvalidPointFormat(n))
        }
    }

    /// Returns true if this point data format has time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert!(!PointFormat::from_u8(0).unwrap().has_time());
    /// assert!(PointFormat::from_u8(1).unwrap().has_time());
    /// ```
    pub fn has_time(&self) -> bool {
        self.0 == 1 || self.0 == 3
    }

    /// Returns true if this point data format has color.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert!(!PointFormat::from_u8(0).unwrap().has_color());
    /// assert!(PointFormat::from_u8(2).unwrap().has_color());
    /// ```
    pub fn has_color(&self) -> bool {
        self.0 == 2 || self.0 == 3
    }

    /// Returns the record length for this point data format.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert_eq!(20, PointFormat::from_u8(0).unwrap().record_length());
    /// ```
    pub fn record_length(&self) -> u16 {
        match self.0 {
            0 => 20,
            1 => 28,
            2 => 26,
            3 => 34,
            _ => unreachable!(),
        }
    }
}

impl fmt::Display for PointFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// The las format version.
///
/// Various "powers" were added to the las format with new versions, and this struct should be used
/// to check for the presence/absence of powers.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Version {
    /// The las major verison. Should be 1.
    pub major: u8,
    /// The las minor version.
    pub minor: u8,
}

impl Version {
    /// Creates a new version.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Version;
    /// let version = Version::new(1, 2);
    /// ```
    pub fn new(major: u8, minor: u8) -> Version {
        Version { major: major, minor: minor }
    }

    /// Returns true if this las version has the gps time type field.
    ///
    /// GPS time type is in the global encoding flags, and was added in las 1.2.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Version;
    /// assert!(!Version::new(1, 1).has_gps_time_type());
    /// assert!(Version::new(1, 2).has_gps_time_type());
    /// ```
    pub fn has_gps_time_type(&self) -> bool {
        self.minor >= 2
    }
}

/// The meaning of GPS time in point records.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum GpsTimeType {
    /// The GPS time in records is GPS week time. This is always true for versions 1.0 and 1.1.
    Week,
    /// The time stamp is standard GPS time minus 1e9, called adjusted standard GPS time. This
    /// adjustment is to improve the floating point resolution.
    AdjustedStandard,
}

impl GpsTimeType {
    /// Returns this time type as a global encoding mask.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::GpsTimeType;
    /// assert_eq!(0, GpsTimeType::Week.as_mask());
    /// assert_eq!(1, GpsTimeType::AdjustedStandard.as_mask());
    /// ```
    pub fn as_mask(&self) -> u16 {
        match *self {
            GpsTimeType::Week => 0,
            GpsTimeType::AdjustedStandard => 1,
        }
    }

    fn from_global_encoding(global_encoding: u16) -> GpsTimeType {
        if global_encoding & 1 == 1 {
            GpsTimeType::AdjustedStandard
        } else {
            GpsTimeType::Week
        }
    }
}
<commit_msg>Remove unused import in header<commit_after>//! Work with las headers and the information contained therin.
//!
//! Headers are very important, as they describe the layout of points in the file, as well as the
//! scaling and offset of the data in each point. Working with headers is generally a low-level
//! operation, and downstream users should prefer to use the builder methods of `Writer` to
//! configure behavior.

use std::io::Read;
use std::fmt;
use std::iter::repeat;

use byteorder::{LittleEndian, ReadBytesExt};
use time;

use Result;
use error::Error;
use io::read_full;

/// This constant value is the bytes in your normal header. There are worlds where people put crap
/// into headers that don't belong there, so we have to guard against this.
pub const DEFAULT_BYTES_IN_HEADER: u16 = 227;

/// A las header.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Header {
    /// The las file signature.
    ///
    /// Should always be "LASF".
    pub file_signature: [u8; 4],
    /// A numeric identifier for this file.
    pub file_source_id: u16,
    /// What is the reference system for the timestamps in each point data record? This field was
    /// added in las 1.2.
    pub gps_time_type: GpsTimeType,
    /// The first of four parts of the project id.
    pub guid_data_1: u32,
    /// The second of four parts of the project id.
    pub guid_data_2: u16,
    /// The third of four parts of the project id.
    pub guid_data_3: u16,
    /// The fourth of four parts of the project id.
    pub guid_data_4: [u8; 8],
    /// The las format version.
    pub version: Version,
    /// Generally the hardware system that created the las file.
    ///
    /// Can also be the algorithm that produced the lasfile. This field is poorly defined.
    pub system_identifier: [u8; 32],
    /// The software the generated the las file.
    pub generating_software: [u8; 32],
    /// The day of the year, indexed to 1.
    pub file_creation_day_of_year: u16,
    /// The year of file creation.
    pub file_creation_year: u16,
    /// The size of the las header.
    ///
    /// Softwares are technically allowed to add custom extensions to the las header, which would
    /// then affect this header size, but that is discouraged as such support is not universal.
    pub header_size: u16,
    /// The byte offset to the beginning of point data.
    ///
    /// Includes the size of the header and the variable length records.
    pub offset_to_point_data: u32,
    /// The number of variable length records.
    pub number_of_variable_length_records: u32,
    /// The point data format.
    pub point_data_format: PointFormat,
    /// The length of one point data record, in bytes.
    pub point_data_record_length: u16,
    /// The total number of point records.
    pub number_of_point_records: u32,
    /// The number of point records of each return number.
    ///
    /// This only supports five returns per pulse.
    pub number_of_points_by_return: [u32; 5],
    /// The x scale factor for each point.
    pub x_scale_factor: f64,
    /// The y scale factor for each point.
    pub y_scale_factor: f64,
    /// The z scale factor for each point.
    pub z_scale_factor: f64,
    /// The x offset for each point.
    pub x_offset: f64,
    /// The y offset for each point.
    pub y_offset: f64,
    /// The z offset for each point.
    pub z_offset: f64,
    /// The maximum x value.
    pub x_max: f64,
    /// The minimum x value.
    pub x_min: f64,
    /// The maximum y value.
    pub y_max: f64,
    /// The minimum y value.
    pub y_min: f64,
    /// The maximum z value.
    pub z_max: f64,
    /// The minimum z value.
    pub z_min: f64,
}

impl Header {
    /// Reads a header from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use las::header::Header;
    /// let ref mut file = File::open("data/1.0_0.las").unwrap();
    /// let header = Header::read_from(file);
    /// ```
    pub fn read_from<R: Read>(reader: &mut R) -> Result<Header> {
        let mut header = Header::new();
        try!(read_full(reader, &mut header.file_signature));
        header.file_source_id = try!(reader.read_u16::<LittleEndian>());
        let global_encoding = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_1 = try!(reader.read_u32::<LittleEndian>());
        header.guid_data_2 = try!(reader.read_u16::<LittleEndian>());
        header.guid_data_3 = try!(reader.read_u16::<LittleEndian>());
        try!(read_full(reader, &mut header.guid_data_4));
        let version_major = try!(reader.read_u8());
        let version_minor = try!(reader.read_u8());
        header.version = Version::new(version_major, version_minor);
        try!(read_full(reader, &mut header.system_identifier));
        try!(read_full(reader, &mut header.generating_software));
        header.file_creation_day_of_year = try!(reader.read_u16::<LittleEndian>());
        header.file_creation_year = try!(reader.read_u16::<LittleEndian>());
        header.header_size = try!(reader.read_u16::<LittleEndian>());
        header.offset_to_point_data = try!(reader.read_u32::<LittleEndian>());
        header.number_of_variable_length_records = try!(reader.read_u32::<LittleEndian>());
        header.point_data_format = try!(PointFormat::from_u8(try!(reader.read_u8())));
        header.point_data_record_length = try!(reader.read_u16::<LittleEndian>());
        header.number_of_point_records = try!(reader.read_u32::<LittleEndian>());
        for n in &mut header.number_of_points_by_return {
            *n = try!(reader.read_u32::<LittleEndian>());
        }
        header.x_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.y_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.z_scale_factor = try!(reader.read_f64::<LittleEndian>());
        header.x_offset = try!(reader.read_f64::<LittleEndian>());
        header.y_offset = try!(reader.read_f64::<LittleEndian>());
        header.z_offset = try!(reader.read_f64::<LittleEndian>());
        header.x_max = try!(reader.read_f64::<LittleEndian>());
        header.x_min = try!(reader.read_f64::<LittleEndian>());
        header.y_max = try!(reader.read_f64::<LittleEndian>());
        header.y_min = try!(reader.read_f64::<LittleEndian>());
        header.z_max = try!(reader.read_f64::<LittleEndian>());
        header.z_min = try!(reader.read_f64::<LittleEndian>());

        if header.version.has_gps_time_type() {
            header.gps_time_type = GpsTimeType::from_global_encoding(global_encoding);
        }

        Ok(header)
    }

    /// Creates a new, empty header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Header;
    /// let header = Header::new();
    /// ```
    pub fn new() -> Header {
        let name_and_version = format!("las-rs {}", env!("CARGO_PKG_VERSION")).into_bytes();
        let mut generating_software = [0; 32];
        for (c, b) in name_and_version.iter()
                                      .chain(repeat(&0).take(generating_software.len() -
                                                             name_and_version.len()))
                                      .zip(generating_software.iter_mut()) {
            *b = *c;
        }
        let now = time::now();
        Header {
            file_signature: *b"LASF",
            file_source_id: 0,
            gps_time_type: GpsTimeType::Week,
            guid_data_1: 0,
            guid_data_2: 0,
            guid_data_3: 0,
            guid_data_4: [0; 8],
            version: Version::new(1, 0),
            system_identifier: [0; 32],
            generating_software: generating_software,
            file_creation_day_of_year: now.tm_yday as u16,
            file_creation_year: now.tm_year as u16,
            header_size: 0,
            offset_to_point_data: 0,
            number_of_variable_length_records: 0,
            point_data_format: PointFormat(0),
            point_data_record_length: 0,
            number_of_point_records: 0,
            number_of_points_by_return: [0; 5],
            x_scale_factor: 1.0,
            y_scale_factor: 1.0,
            z_scale_factor: 1.0,
            x_offset: 0.0,
            y_offset: 0.0,
            z_offset: 0.0,
            x_max: 0.0,
            x_min: 0.0,
            y_max: 0.0,
            y_min: 0.0,
            z_max: 0.0,
            z_min: 0.0,
        }
    }
}

/// A wrapper around the u8 of a point data format.
///
/// Formats have powers, so we encapsulate that through this struct.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PointFormat(pub u8);

impl PointFormat {
    /// Creates a point data format for this u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert!(PointFormat::from_u8(0).is_ok());
    /// assert!(PointFormat::from_u8(1).is_ok());
    /// assert!(PointFormat::from_u8(127).is_err());
    /// ```
    pub fn from_u8(n: u8) -> Result<PointFormat> {
        if n < 4 {
            Ok(PointFormat(n))
        } else {
            Err(Error::InvalidPointFormat(n))
        }
    }

    /// Returns true if this point data format has time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert!(!PointFormat::from_u8(0).unwrap().has_time());
    /// assert!(PointFormat::from_u8(1).unwrap().has_time());
    /// ```
    pub fn has_time(&self) -> bool {
        self.0 == 1 || self.0 == 3
    }

    /// Returns true if this point data format has color.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert!(!PointFormat::from_u8(0).unwrap().has_color());
    /// assert!(PointFormat::from_u8(2).unwrap().has_color());
    /// ```
    pub fn has_color(&self) -> bool {
        self.0 == 2 || self.0 == 3
    }

    /// Returns the record length for this point data format.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::PointFormat;
    /// assert_eq!(20, PointFormat::from_u8(0).unwrap().record_length());
    /// ```
    pub fn record_length(&self) -> u16 {
        match self.0 {
            0 => 20,
            1 => 28,
            2 => 26,
            3 => 34,
            _ => unreachable!(),
        }
    }
}

impl fmt::Display for PointFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// The las format version.
///
/// Various "powers" were added to the las format with new versions, and this struct should be used
/// to check for the presence/absence of powers.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Version {
    /// The las major verison. Should be 1.
    pub major: u8,
    /// The las minor version.
    pub minor: u8,
}

impl Version {
    /// Creates a new version.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Version;
    /// let version = Version::new(1, 2);
    /// ```
    pub fn new(major: u8, minor: u8) -> Version {
        Version { major: major, minor: minor }
    }

    /// Returns true if this las version has the gps time type field.
    ///
    /// GPS time type is in the global encoding flags, and was added in las 1.2.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::Version;
    /// assert!(!Version::new(1, 1).has_gps_time_type());
    /// assert!(Version::new(1, 2).has_gps_time_type());
    /// ```
    pub fn has_gps_time_type(&self) -> bool {
        self.minor >= 2
    }
}

/// The meaning of GPS time in point records.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum GpsTimeType {
    /// The GPS time in records is GPS week time. This is always true for versions 1.0 and 1.1.
    Week,
    /// The time stamp is standard GPS time minus 1e9, called adjusted standard GPS time. This
    /// adjustment is to improve the floating point resolution.
    AdjustedStandard,
}

impl GpsTimeType {
    /// Returns this time type as a global encoding mask.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::header::GpsTimeType;
    /// assert_eq!(0, GpsTimeType::Week.as_mask());
    /// assert_eq!(1, GpsTimeType::AdjustedStandard.as_mask());
    /// ```
    pub fn as_mask(&self) -> u16 {
        match *self {
            GpsTimeType::Week => 0,
            GpsTimeType::AdjustedStandard => 1,
        }
    }

    fn from_global_encoding(global_encoding: u16) -> GpsTimeType {
        if global_encoding & 1 == 1 {
            GpsTimeType::AdjustedStandard
        } else {
            GpsTimeType::Week
        }
    }
}
<|endoftext|>


<commit_before>//! Convenience structs for commonly defined fields in headers.

use crate::algorithm::AlgorithmType;

/// A trait for any header than can conform to the
/// [JWT specification](https://tools.ietf.org/html/rfc7519#page-11).
pub trait JoseHeader {
    fn algorithm_type(&self) -> AlgorithmType;

    fn key_id(&self) -> Option<&str> {
        None
    }

    fn type_(&self) -> Option<HeaderType> {
        None
    }

    fn content_type(&self) -> Option<HeaderContentType> {
        None
    }
}

/// Generic [JWT header](https://tools.ietf.org/html/rfc7519#page-11) with
/// defined fields for common fields.
#[derive(Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Header {
    #[serde(rename = "alg")]
    pub algorithm: AlgorithmType,

    #[serde(rename = "kid", skip_serializing_if = "Option::is_none")]
    pub key_id: Option<String>,

    #[serde(rename = "typ", skip_serializing_if = "Option::is_none")]
    pub type_: Option<HeaderType>,

    #[serde(rename = "cty", skip_serializing_if = "Option::is_none")]
    pub content_type: Option<HeaderContentType>,
}

impl JoseHeader for Header {
    fn algorithm_type(&self) -> AlgorithmType {
        self.algorithm
    }

    fn key_id(&self) -> Option<&str> {
        self.key_id.as_ref().map(|s| &**s)
    }

    fn type_(&self) -> Option<HeaderType> {
        self.type_
    }

    fn content_type(&self) -> Option<HeaderContentType> {
        self.content_type
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum HeaderType {
    #[serde(rename = "JWT")]
    JsonWebToken,
}

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum HeaderContentType {
    #[serde(rename = "JWT")]
    JsonWebToken,
}

#[cfg(test)]
mod tests {
    use crate::algorithm::AlgorithmType;
    use crate::header::{Header, HeaderType};
    use crate::{FromBase64, ToBase64};

    #[test]
    fn from_base64() {
        let enc = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
        let header = Header::from_base64(enc).unwrap();

        assert_eq!(header.type_.unwrap(), HeaderType::JsonWebToken);
        assert_eq!(header.algorithm, AlgorithmType::Hs256);

        let enc = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFLU0YzZyJ9";
        let header = Header::from_base64(enc).unwrap();

        assert_eq!(header.key_id.unwrap(), "1KSF3g".to_string());
        assert_eq!(header.algorithm, AlgorithmType::Rs256);
    }

    #[test]
    fn roundtrip() {
        let header: Header = Default::default();
        let enc = header.to_base64().unwrap();
        assert_eq!(header, Header::from_base64(&*enc).unwrap());
    }
}
<commit_msg>Add precomputed header type<commit_after>//! Convenience structs for commonly defined fields in headers.

use crate::algorithm::AlgorithmType;
use crate::error::Error;
use crate::ToBase64;
use std::borrow::Cow;

/// A trait for any header than can conform to the
/// [JWT specification](https://tools.ietf.org/html/rfc7519#page-11).
pub trait JoseHeader {
    fn algorithm_type(&self) -> AlgorithmType;

    fn key_id(&self) -> Option<&str> {
        None
    }

    fn type_(&self) -> Option<HeaderType> {
        None
    }

    fn content_type(&self) -> Option<HeaderContentType> {
        None
    }
}

/// Generic [JWT header](https://tools.ietf.org/html/rfc7519#page-11) with
/// defined fields for common fields.
#[derive(Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Header {
    #[serde(rename = "alg")]
    pub algorithm: AlgorithmType,

    #[serde(rename = "kid", skip_serializing_if = "Option::is_none")]
    pub key_id: Option<String>,

    #[serde(rename = "typ", skip_serializing_if = "Option::is_none")]
    pub type_: Option<HeaderType>,

    #[serde(rename = "cty", skip_serializing_if = "Option::is_none")]
    pub content_type: Option<HeaderContentType>,
}

impl JoseHeader for Header {
    fn algorithm_type(&self) -> AlgorithmType {
        self.algorithm
    }

    fn key_id(&self) -> Option<&str> {
        self.key_id.as_ref().map(|s| &**s)
    }

    fn type_(&self) -> Option<HeaderType> {
        self.type_
    }

    fn content_type(&self) -> Option<HeaderContentType> {
        self.content_type
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum HeaderType {
    #[serde(rename = "JWT")]
    JsonWebToken,
}

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum HeaderContentType {
    #[serde(rename = "JWT")]
    JsonWebToken,
}

pub struct PrecomputedAlgorithmOnlyHeader(pub AlgorithmType);

impl JoseHeader for PrecomputedAlgorithmOnlyHeader {
    fn algorithm_type(&self) -> AlgorithmType {
        let PrecomputedAlgorithmOnlyHeader(algorithm_type) = *self;
        algorithm_type
    }
}

impl ToBase64 for PrecomputedAlgorithmOnlyHeader {
    fn to_base64(&self) -> Result<Cow<'static, str>, Error> {
        let precomputed_str = match self.algorithm_type() {
            AlgorithmType::Hs256 => "eyJhbGciOiAiSFMyNTYifQ",
            AlgorithmType::Hs384 => "eyJhbGciOiAiSFMzODQifQ",
            AlgorithmType::Hs512 => "eyJhbGciOiAiSFM1MTIifQ",
            AlgorithmType::Rs256 => "eyJhbGciOiAiUlMyNTYifQ",
            AlgorithmType::Rs384 => "eyJhbGciOiAiUlMzODQifQ",
            AlgorithmType::Rs512 => "eyJhbGciOiAiUlM1MTIifQ",
            AlgorithmType::Es256 => "eyJhbGciOiAiRVMyNTYifQ",
            AlgorithmType::Es384 => "eyJhbGciOiAiRVMzODQifQ",
            AlgorithmType::Es512 => "eyJhbGciOiAiRVM1MTIifQ",
            AlgorithmType::Ps256 => "eyJhbGciOiAiUFMyNTYifQ",
            AlgorithmType::Ps384 => "eyJhbGciOiAiUFMzODQifQ",
            AlgorithmType::Ps512 => "eyJhbGciOiAiUFM1MTIifQ",
            AlgorithmType::None => "eyJhbGciOiAibm9uZSJ9Cg",
        };

        Ok(Cow::Borrowed(precomputed_str))
    }
}

#[cfg(test)]
mod tests {
    use crate::algorithm::AlgorithmType;
    use crate::header::{Header, HeaderType, PrecomputedAlgorithmOnlyHeader};
    use crate::{FromBase64, ToBase64};

    #[test]
    fn from_base64() {
        let enc = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
        let header = Header::from_base64(enc).unwrap();

        assert_eq!(header.type_.unwrap(), HeaderType::JsonWebToken);
        assert_eq!(header.algorithm, AlgorithmType::Hs256);

        let enc = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFLU0YzZyJ9";
        let header = Header::from_base64(enc).unwrap();

        assert_eq!(header.key_id.unwrap(), "1KSF3g".to_string());
        assert_eq!(header.algorithm, AlgorithmType::Rs256);
    }

    #[test]
    fn roundtrip() {
        let header: Header = Default::default();
        let enc = header.to_base64().unwrap();
        assert_eq!(header, Header::from_base64(&*enc).unwrap());
    }

    #[test]
    fn precomputed_headers() {
        let algorithms = [
            AlgorithmType::Hs256,
            AlgorithmType::Hs384,
            AlgorithmType::Hs512,
            AlgorithmType::Rs256,
            AlgorithmType::Rs384,
            AlgorithmType::Rs512,
            AlgorithmType::Es256,
            AlgorithmType::Es384,
            AlgorithmType::Es512,
            AlgorithmType::Ps256,
            AlgorithmType::Ps384,
            AlgorithmType::Ps512,
            AlgorithmType::None,
        ];

        for algorithm in algorithms.iter() {
            let precomputed = PrecomputedAlgorithmOnlyHeader(*algorithm);
            let precomputed_str = precomputed.to_base64().unwrap();

            let header = Header::from_base64(&*precomputed_str).unwrap();
            assert_eq!(*algorithm, header.algorithm);
        }
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}*", word, word);
                } else {
                    terms_url += &format!("{} ", word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<commit_msg>Fix warning spotted when enabling NLL<commit_after>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}*", word, word);
                } else {
                    terms_url += &format!("{} ", word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<|endoftext|>


<commit_before>use quickcheck_dep::{quickcheck, Arbitrary, TestResult};
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};

macro_rules! test_shrink {
    ($type:ty,
     $fn_name:ident,
     $($method:ident()).+
     $(, min=$min_value:literal)?
    ) => {
        quickcheck! {
            fn $fn_name(v: $type) -> TestResult {
                let method_value = v.$($method()).+;
                if method_value == 0 $(|| method_value == $min_value)? {
                    TestResult::discard()
                } else {
                    TestResult::from_bool(v.shrink().any(|shrunk|
                        if method_value > 0 {
                            shrunk.$($method()).+ < v.$($method()).+
                        } else {
                            shrunk.$($method()).+ > v.$($method()).+
                        }
                    ))
                }
            }
        }
    };
}

quickcheck! {
    fn date_roundtrip(d: Date) -> bool {
        Date::from_ordinal_date(d.year(), d.ordinal()) == Ok(d)
    }

    fn julian_day_roundtrip(d: Date) -> bool {
        Date::from_julian_day(d.to_julian_day()) == Ok(d)
    }

    fn duration_roundtrip(d: Duration) -> bool {
        Duration::new(d.whole_seconds(), d.subsec_nanoseconds()) == d
    }

    fn time_roundtrip(t: Time) -> bool {
        Time::from_hms_nano(t.hour(), t.minute(), t.second(), t.nanosecond()) == Ok(t)
    }

    fn primitive_date_time_roundtrip(a: PrimitiveDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()) == a
    }

    fn utc_offset_roundtrip(o: UtcOffset) -> bool {
        let (hours, minutes, seconds) = o.as_hms();
        UtcOffset::from_hms(hours, minutes, seconds) == Ok(o)
    }

    fn offset_date_time_roundtrip(a: OffsetDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()).assume_offset(a.offset()) == a
    }

    fn unix_timestamp_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool({
                // nanoseconds are not stored in the basic Unix timestamp
                let odt = odt - Duration::nanoseconds(odt.nanosecond().into());
                OffsetDateTime::from_unix_timestamp(odt.unix_timestamp()) == Ok(odt)
            })
        }
    }

    fn unix_timestamp_nanos_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool(
                OffsetDateTime::from_unix_timestamp_nanos(odt.unix_timestamp_nanos()) == Ok(odt)
            )
        }
    }

    fn weekday_supports_arbitrary(w: Weekday) -> bool {
        (1..=7).contains(&w.number_from_monday())
    }

    fn weekday_can_shrink(w: Weekday) -> bool {
        match w {
            Weekday::Monday => w.shrink().next() == None,
            _ => w.shrink().next() == Some(w.previous())
        }
    }

    fn month_supports_arbitrary(m: Month) -> bool {
        (1..=12).contains(&(m as u8))
    }

    fn month_can_shrink(m: Month) -> bool {
        match m {
            Month::January => m.shrink().next() == None,
            _ => m.shrink().next() == Some(m.previous())
        }
    }
}

test_shrink!(Date, date_can_shrink_year, year());
test_shrink!(Date, date_can_shrink_ordinal, ordinal(), min = 1);

test_shrink!(Duration, duration_can_shrink_seconds, whole_seconds());
test_shrink!(Duration, duration_can_shrink_ns, subsec_nanoseconds());

test_shrink!(Time, time_can_shrink_hour, hour());
test_shrink!(Time, time_can_shrink_minute, minute());
test_shrink!(Time, time_can_shrink_second, second());
test_shrink!(Time, time_can_shrink_nanosecond, nanosecond());

test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_year,
    year()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_hour,
    hour()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_minute,
    minute()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_second,
    second()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_nanosecond,
    nanosecond()
);

test_shrink!(UtcOffset, utc_offset_can_shrink, whole_seconds());

test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_offset,
    offset().whole_seconds()
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_year, year());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_hour, hour());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_minute, minute());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_second, second());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_nanosecond,
    nanosecond()
);
<commit_msg>Improved check for minimum value in quickcheck<commit_after>use quickcheck_dep::{quickcheck, Arbitrary, TestResult};
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};

macro_rules! test_shrink {
    ($type:ty,
     $fn_name:ident,
     $($method:ident()).+
     $(, min=$min_value:literal)?
    ) => {
        quickcheck! {
            fn $fn_name(v: $type) -> TestResult {
                let method_value = v.$($method()).+;
                if method_value == test_shrink!(@min_or_zero $($min_value)?) {
                    TestResult::discard()
                } else {
                    TestResult::from_bool(v.shrink().any(|shrunk|
                        if method_value > 0 {
                            shrunk.$($method()).+ < v.$($method()).+
                        } else {
                            shrunk.$($method()).+ > v.$($method()).+
                        }
                    ))
                }
            }
        }
    };
    (@min_or_zero) => { 0 };
    (@min_or_zero $min:literal) => { $min };
}

quickcheck! {
    fn date_roundtrip(d: Date) -> bool {
        Date::from_ordinal_date(d.year(), d.ordinal()) == Ok(d)
    }

    fn julian_day_roundtrip(d: Date) -> bool {
        Date::from_julian_day(d.to_julian_day()) == Ok(d)
    }

    fn duration_roundtrip(d: Duration) -> bool {
        Duration::new(d.whole_seconds(), d.subsec_nanoseconds()) == d
    }

    fn time_roundtrip(t: Time) -> bool {
        Time::from_hms_nano(t.hour(), t.minute(), t.second(), t.nanosecond()) == Ok(t)
    }

    fn primitive_date_time_roundtrip(a: PrimitiveDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()) == a
    }

    fn utc_offset_roundtrip(o: UtcOffset) -> bool {
        let (hours, minutes, seconds) = o.as_hms();
        UtcOffset::from_hms(hours, minutes, seconds) == Ok(o)
    }

    fn offset_date_time_roundtrip(a: OffsetDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()).assume_offset(a.offset()) == a
    }

    fn unix_timestamp_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool({
                // nanoseconds are not stored in the basic Unix timestamp
                let odt = odt - Duration::nanoseconds(odt.nanosecond().into());
                OffsetDateTime::from_unix_timestamp(odt.unix_timestamp()) == Ok(odt)
            })
        }
    }

    fn unix_timestamp_nanos_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool(
                OffsetDateTime::from_unix_timestamp_nanos(odt.unix_timestamp_nanos()) == Ok(odt)
            )
        }
    }

    fn weekday_supports_arbitrary(w: Weekday) -> bool {
        (1..=7).contains(&w.number_from_monday())
    }

    fn weekday_can_shrink(w: Weekday) -> bool {
        match w {
            Weekday::Monday => w.shrink().next() == None,
            _ => w.shrink().next() == Some(w.previous())
        }
    }

    fn month_supports_arbitrary(m: Month) -> bool {
        (1..=12).contains(&(m as u8))
    }

    fn month_can_shrink(m: Month) -> bool {
        match m {
            Month::January => m.shrink().next() == None,
            _ => m.shrink().next() == Some(m.previous())
        }
    }
}

test_shrink!(Date, date_can_shrink_year, year());
test_shrink!(Date, date_can_shrink_ordinal, ordinal(), min = 1);

test_shrink!(Duration, duration_can_shrink_seconds, whole_seconds());
test_shrink!(Duration, duration_can_shrink_ns, subsec_nanoseconds());

test_shrink!(Time, time_can_shrink_hour, hour());
test_shrink!(Time, time_can_shrink_minute, minute());
test_shrink!(Time, time_can_shrink_second, second());
test_shrink!(Time, time_can_shrink_nanosecond, nanosecond());

test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_year,
    year()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_hour,
    hour()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_minute,
    minute()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_second,
    second()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_nanosecond,
    nanosecond()
);

test_shrink!(UtcOffset, utc_offset_can_shrink, whole_seconds());

test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_offset,
    offset().whole_seconds()
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_year, year());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_hour, hour());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_minute, minute());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_second, second());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_nanosecond,
    nanosecond()
);
<|endoftext|>


<commit_before>use std::io::Result;
use self::super::{Github, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;

pub enum Filter {
  Assigned,
  Created,
  Mentioned,
  Subscribed,
  All
}

impl fmt::Display for Filter {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Filter::Assigned => "assigned",
      Filter::Created => "created",
      Filter::Mentioned => "mentioned",
      Filter::Subscribed => "subscribed",
      Filter::All => "all"
    })
  }
}

impl Default for Filter {
  fn default() -> Filter {
    Filter::Assigned
  }
}

pub enum Sort {
  Created,
  Updated,
  Comments
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created => "created",
      Sort::Updated => "updated",
      Sort::Comments => "comments"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub struct IssueRef<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: &'static i64
}

impl<'a> IssueRef<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str,
    number: &'static i64) -> IssueRef<'a> {
    IssueRef {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}{}", self.owner, self.repo, self.number, more)
  }

  // add a set of labels to this issue ref
  pub fn label(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.post(
      &self.path("/labels"),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }
}

pub struct Issues<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

/// an mutable issue list builder
pub struct IssuesListBuilder<'a> {
  issues: &'a Issues<'a>,
  state: State,
  sort: Sort,
  direction: SortDirection,
  assignee: Option<&'static str>,
  creator: Option<&'static str>,
  mentioned: Option<&'static str>,
  labels: Vec<&'static str>,
  since: Option<&'static str>
}

impl<'a> IssuesListBuilder<'a> {

  pub fn new(is: &'a Issues<'a>) -> IssuesListBuilder<'a> {
    IssuesListBuilder {
      issues: is,
      state: Default::default(),
      sort: Default::default(),
      direction: Default::default(),
      assignee: None,
      creator: None,
      mentioned: None,
      labels: vec![],
      since: None
    }
  }

  pub fn state(&mut self, state: State) -> &mut IssuesListBuilder<'a> {
    self.state = state;
    self
  }

  pub fn sort(&mut self, sort: Sort) -> &mut IssuesListBuilder<'a> {
    self.sort = sort;
    self
  }

  pub fn direction(&mut self, direction: SortDirection) -> &mut IssuesListBuilder<'a> {
    self.direction = direction;
    self
  }

  pub fn assignee(&mut self, assignee: &'static str) -> &mut IssuesListBuilder<'a> {
    self.assignee = Some(assignee);
    self
  }

  pub fn creator(&mut self, creator: &'static str) -> &mut IssuesListBuilder<'a> {
    self.creator = Some(creator);
    self
  }

  pub fn mentioned(&mut self, mentioned: &'static str) -> &mut IssuesListBuilder<'a> {
    self.mentioned = Some(mentioned);
    self
  }

  pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut IssuesListBuilder<'a> {
    self.labels = labels;
    self
  }

  pub fn since(&mut self, since: &'static str) -> &mut IssuesListBuilder<'a> {
    self.since = Some(since);
    self
  }

  pub fn get(&self) -> Result<Vec<Issue>> {
    let mut params = Vec::new();
    params.push(format!("state={}", self.state));
    params.push(format!("sort={}", self.sort));
    params.push(format!("direction={}", self.direction));
    if let Some(a) = self.assignee {
      params.push(format!("assignee={}", a));
    }
    if let Some(c) = self.creator {
      params.push(format!("creator={}", c));
    }
    if let Some(m) = self.mentioned {
      params.push(format!("mentioned={}", m));
    }
    if let Some(s) = self.since {
      params.push(format!("since={}", s));
    }
    if !self.labels.is_empty() {
      params.push(format!("labels={}", self.labels.join(",")));
    }
    println!("params {:?}", params);
    let url = self.issues.path(
      &format!("?{}", params.join("&"))
    );
    let body = try!(
      self.issues.github.get(
        &url
      )
    );
    Ok(json::decode::<Vec<Issue>>(&body).unwrap())
  }

}

impl<'a> Issues<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Issues<'a> {
    Issues {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: &'static i64) -> IssueRef {
    IssueRef::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }

  pub fn list(&self) -> IssuesListBuilder {
    IssuesListBuilder::new(self)
  }
}
<commit_msg>simpler name<commit_after>use std::io::Result;
use self::super::{Github, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;

pub enum Filter {
  Assigned,
  Created,
  Mentioned,
  Subscribed,
  All
}

impl fmt::Display for Filter {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Filter::Assigned => "assigned",
      Filter::Created => "created",
      Filter::Mentioned => "mentioned",
      Filter::Subscribed => "subscribed",
      Filter::All => "all"
    })
  }
}

impl Default for Filter {
  fn default() -> Filter {
    Filter::Assigned
  }
}

pub enum Sort {
  Created,
  Updated,
  Comments
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created => "created",
      Sort::Updated => "updated",
      Sort::Comments => "comments"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub struct IssueRef<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: &'static i64
}

impl<'a> IssueRef<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str,
    number: &'static i64) -> IssueRef<'a> {
    IssueRef {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}{}", self.owner, self.repo, self.number, more)
  }

  // add a set of labels to this issue ref
  pub fn label(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.post(
      &self.path("/labels"),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }
}

pub struct Issues<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
  issues: &'a Issues<'a>,
  state: State,
  sort: Sort,
  direction: SortDirection,
  assignee: Option<&'static str>,
  creator: Option<&'static str>,
  mentioned: Option<&'static str>,
  labels: Vec<&'static str>,
  since: Option<&'static str>
}

impl<'a> ListBuilder<'a> {

  pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
    ListBuilder {
      issues: is,
      state: Default::default(),
      sort: Default::default(),
      direction: Default::default(),
      assignee: None,
      creator: None,
      mentioned: None,
      labels: vec![],
      since: None
    }
  }

  pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
    self.state = state;
    self
  }

  pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
    self.sort = sort;
    self
  }

  pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
    self.direction = direction;
    self
  }

  pub fn assignee(&mut self, assignee: &'static str) -> &mut ListBuilder<'a> {
    self.assignee = Some(assignee);
    self
  }

  pub fn creator(&mut self, creator: &'static str) -> &mut ListBuilder<'a> {
    self.creator = Some(creator);
    self
  }

  pub fn mentioned(&mut self, mentioned: &'static str) -> &mut ListBuilder<'a> {
    self.mentioned = Some(mentioned);
    self
  }

  pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut ListBuilder<'a> {
    self.labels = labels;
    self
  }

  pub fn since(&mut self, since: &'static str) -> &mut ListBuilder<'a> {
    self.since = Some(since);
    self
  }

  pub fn get(&self) -> Result<Vec<Issue>> {
    let mut params = Vec::new();
    params.push(format!("state={}", self.state));
    params.push(format!("sort={}", self.sort));
    params.push(format!("direction={}", self.direction));
    if let Some(a) = self.assignee {
      params.push(format!("assignee={}", a));
    }
    if let Some(c) = self.creator {
      params.push(format!("creator={}", c));
    }
    if let Some(m) = self.mentioned {
      params.push(format!("mentioned={}", m));
    }
    if let Some(s) = self.since {
      params.push(format!("since={}", s));
    }
    if !self.labels.is_empty() {
      params.push(format!("labels={}", self.labels.join(",")));
    }
    println!("params {:?}", params);
    let url = self.issues.path(
      &format!("?{}", params.join("&"))
    );
    let body = try!(
      self.issues.github.get(
        &url
      )
    );
    Ok(json::decode::<Vec<Issue>>(&body).unwrap())
  }

}

impl<'a> Issues<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Issues<'a> {
    Issues {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: &'static i64) -> IssueRef {
    IssueRef::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }

  pub fn list(&self) -> ListBuilder {
    ListBuilder::new(self)
  }
}
<|endoftext|>