<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(test)]

extern crate compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display()));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("run-pass", "tests/run-pass".into());
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<commit_msg>Use -Zui-testing flag<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(test)]

extern crate compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing",
        host_libs().display()
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("run-pass", "tests/run-pass".into());
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<|endoftext|>


<commit_before>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let type_tags = to_osc_string(b",fdsih");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(h_bytes.iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::OscInt(x) => assert_eq!(i, x),
                    types::OscType::OscLong(x) => assert_eq!(l, x),
                    types::OscType::OscFloat(x) => assert_eq!(f, x),
                    types::OscType::OscDouble(x) => assert_eq!(d, x),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<commit_msg>Remove `Osc` prefix from types<commit_after>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let type_tags = to_osc_string(b",fdsih");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(h_bytes.iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<|endoftext|>


<commit_before>//! Easy file downloading
#![deny(rust_2018_idioms)]

use std::path::Path;
use url::Url;

mod errors;
pub use crate::errors::*;

#[derive(Debug, Copy, Clone)]
pub enum Backend {
    Curl,
    Reqwest,
}

#[derive(Debug, Copy, Clone)]
pub enum Event<'a> {
    ResumingPartialDownload,
    /// Received the Content-Length of the to-be downloaded data.
    DownloadContentLengthReceived(u64),
    /// Received some data.
    DownloadDataReceived(&'a [u8]),
}

fn download_with_backend(
    backend: Backend,
    url: &Url,
    resume_from: u64,
    callback: &dyn Fn(Event<'_>) -> Result<()>,
) -> Result<()> {
    match backend {
        Backend::Curl => curl::download(url, resume_from, callback),
        Backend::Reqwest => reqwest_be::download(url, resume_from, callback),
    }
}

pub fn download_to_path_with_backend(
    backend: Backend,
    url: &Url,
    path: &Path,
    resume_from_partial: bool,
    callback: Option<&dyn Fn(Event<'_>) -> Result<()>>,
) -> Result<()> {
    use std::cell::RefCell;
    use std::fs::OpenOptions;
    use std::io::{Read, Seek, SeekFrom, Write};

    || -> Result<()> {
        let (file, resume_from) = if resume_from_partial {
            let possible_partial = OpenOptions::new().read(true).open(&path);

            let downloaded_so_far = if let Ok(mut partial) = possible_partial {
                if let Some(cb) = callback {
                    cb(Event::ResumingPartialDownload)?;

                    let mut buf = vec![0; 32768];
                    let mut downloaded_so_far = 0;
                    loop {
                        let n = partial.read(&mut buf)?;
                        downloaded_so_far += n as u64;
                        if n == 0 {
                            break;
                        }
                        cb(Event::DownloadDataReceived(&buf[..n]))?;
                    }

                    downloaded_so_far
                } else {
                    let file_info = partial.metadata()?;
                    file_info.len()
                }
            } else {
                0
            };

            let mut possible_partial = OpenOptions::new()
                .write(true)
                .create(true)
                .open(&path)
                .chain_err(|| "error opening file for download")?;

            possible_partial.seek(SeekFrom::End(0))?;

            (possible_partial, downloaded_so_far)
        } else {
            (
                OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(&path)
                    .chain_err(|| "error creating file for download")?,
                0,
            )
        };

        let file = RefCell::new(file);

        download_with_backend(backend, url, resume_from, &|event| {
            if let Event::DownloadDataReceived(data) = event {
                file.borrow_mut()
                    .write_all(data)
                    .chain_err(|| "unable to write download to disk")?;
            }
            match callback {
                Some(cb) => cb(event),
                None => Ok(()),
            }
        })?;

        file.borrow_mut()
            .sync_data()
            .chain_err(|| "unable to sync download to disk")?;

        Ok(())
    }()
    .map_err(|e| {
        // TODO is there any point clearing up here? What kind of errors will leave us with an unusable partial?
        e
    })
}

/// Download via libcurl; encrypt with the native (or OpenSSl) TLS
/// stack via libcurl
#[cfg(feature = "curl-backend")]
pub mod curl {
    use super::Event;
    use crate::errors::*;
    use curl::easy::Easy;
    use std::cell::RefCell;
    use std::str;
    use std::time::Duration;
    use url::Url;

    pub fn download(
        url: &Url,
        resume_from: u64,
        callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<()> {
        // Fetch either a cached libcurl handle (which will preserve open
        // connections) or create a new one if it isn't listed.
        //
        // Once we've acquired it, reset the lifetime from 'static to our local
        // scope.
        thread_local!(static EASY: RefCell<Easy> = RefCell::new(Easy::new()));
        EASY.with(|handle| {
            let mut handle = handle.borrow_mut();

            handle
                .url(&url.to_string())
                .chain_err(|| "failed to set url")?;
            handle
                .follow_location(true)
                .chain_err(|| "failed to set follow redirects")?;

            if resume_from > 0 {
                handle
                    .resume_from(resume_from)
                    .chain_err(|| "setting the range header for download resumption")?;
            } else {
                // an error here indicates that the range header isn't supported by underlying curl,
                // so there's nothing to "clear" - safe to ignore this error.
                let _ = handle.resume_from(0);
            }

            // Take at most 30s to connect
            handle
                .connect_timeout(Duration::new(30, 0))
                .chain_err(|| "failed to set connect timeout")?;

            {
                let cberr = RefCell::new(None);
                let mut transfer = handle.transfer();

                // Data callback for libcurl which is called with data that's
                // downloaded. We just feed it into our hasher and also write it out
                // to disk.
                transfer
                    .write_function(|data| match callback(Event::DownloadDataReceived(data)) {
                        Ok(()) => Ok(data.len()),
                        Err(e) => {
                            *cberr.borrow_mut() = Some(e);
                            Ok(0)
                        }
                    })
                    .chain_err(|| "failed to set write")?;

                // Listen for headers and parse out a `Content-Length` (case-insensitive) if it
                // comes so we know how much we're downloading.
                transfer
                    .header_function(|header| {
                        if let Ok(data) = str::from_utf8(header) {
                            let prefix = "content-length: ";
                            if data.to_ascii_lowercase().starts_with(prefix) {
                                if let Ok(s) = data[prefix.len()..].trim().parse::<u64>() {
                                    let msg = Event::DownloadContentLengthReceived(s + resume_from);
                                    match callback(msg) {
                                        Ok(()) => (),
                                        Err(e) => {
                                            *cberr.borrow_mut() = Some(e);
                                            return false;
                                        }
                                    }
                                }
                            }
                        }
                        true
                    })
                    .chain_err(|| "failed to set header")?;

                // If an error happens check to see if we had a filesystem error up
                // in `cberr`, but we always want to punt it up.
                transfer.perform().or_else(|e| {
                    // If the original error was generated by one of our
                    // callbacks, return it.
                    match cberr.borrow_mut().take() {
                        Some(cberr) => Err(cberr),
                        None => {
                            // Otherwise, return the error from curl
                            if e.is_file_couldnt_read_file() {
                                Err(e).chain_err(|| ErrorKind::FileNotFound)
                            } else {
                                Err(e).chain_err(|| "error during download")
                            }
                        }
                    }
                })?;
            }

            // If we didn't get a 20x or 0 ("OK" for files) then return an error
            let code = handle
                .response_code()
                .chain_err(|| "failed to get response code")?;
            match code {
                0 | 200..=299 => {}
                _ => {
                    return Err(ErrorKind::HttpStatus(code).into());
                }
            };

            Ok(())
        })
    }
}

#[cfg(feature = "reqwest-backend")]
pub mod reqwest_be {
    use super::Event;
    use crate::errors::*;
    use lazy_static::lazy_static;
    use reqwest::{header, Client, Proxy, Response};
    use std::io;
    use std::time::Duration;
    use url::Url;

    pub fn download(
        url: &Url,
        resume_from: u64,
        callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<()> {
        // Short-circuit reqwest for the "file:" URL scheme
        if download_from_file_url(url, resume_from, callback)? {
            return Ok(());
        }

        let mut res = request(url, resume_from).chain_err(|| "failed to make network request")?;

        if !res.status().is_success() {
            let code: u16 = res.status().into();
            return Err(ErrorKind::HttpStatus(u32::from(code)).into());
        }

        let buffer_size = 0x10000;
        let mut buffer = vec![0u8; buffer_size];

        if let Some(len) = res.headers().get(header::CONTENT_LENGTH) {
            // TODO possible issues during unwrap?
            let len = len.to_str().unwrap().parse::<u64>().unwrap() + resume_from;
            callback(Event::DownloadContentLengthReceived(len))?;
        }

        loop {
            let bytes_read =
                io::Read::read(&mut res, &mut buffer).chain_err(|| "error reading from socket")?;

            if bytes_read != 0 {
                callback(Event::DownloadDataReceived(&buffer[0..bytes_read]))?;
            } else {
                return Ok(());
            }
        }
    }

    lazy_static! {
        static ref CLIENT: Client = {
            let catcher = || {
                Client::builder()
                    .gzip(false)
                    .proxy(Proxy::custom(env_proxy))
                    .timeout(Duration::from_secs(30))
                    .build()
            };

            // woah, an unwrap?!
            // It's OK. This is the same as what is happening in curl.
            //
            // The curl::Easy::new() internally assert!s that the initialized
            // Easy is not null. Inside reqwest, the errors here would be from
            // the TLS library returning a null pointer as well.
            catcher().unwrap()
        };
    }

    fn env_proxy(url: &Url) -> Option<Url> {
        env_proxy::for_url(url).to_url()
    }

    fn request(url: &Url, resume_from: u64) -> reqwest::Result<Response> {
        let mut req = CLIENT.get(url.as_str());

        if resume_from != 0 {
            req = req.header(header::RANGE, format!("bytes={}-", resume_from));
        }

        req.send()
    }

    fn download_from_file_url(
        url: &Url,
        resume_from: u64,
        callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<bool> {
        use std::fs;

        // The file scheme is mostly for use by tests to mock the dist server
        if url.scheme() == "file" {
            let src = url
                .to_file_path()
                .map_err(|_| Error::from(format!("bogus file url: '{}'", url)))?;
            if !src.is_file() {
                // Because some of rustup's logic depends on checking
                // the error when a downloaded file doesn't exist, make
                // the file case return the same error value as the
                // network case.
                return Err(ErrorKind::FileNotFound.into());
            }

            let mut f = fs::File::open(src).chain_err(|| "unable to open downloaded file")?;
            io::Seek::seek(&mut f, io::SeekFrom::Start(resume_from))?;

            let mut buffer = vec![0u8; 0x10000];
            loop {
                let bytes_read = io::Read::read(&mut f, &mut buffer)
                    .chain_err(|| "unable to read downloaded file")?;
                if bytes_read == 0 {
                    break;
                }
                callback(Event::DownloadDataReceived(&buffer[0..bytes_read]))?;
            }

            Ok(true)
        } else {
            Ok(false)
        }
    }
}

#[cfg(not(feature = "curl-backend"))]
pub mod curl {

    use super::Event;
    use crate::errors::*;
    use url::Url;

    pub fn download(
        _url: &Url,
        _resume_from: u64,
        _callback: &Fn(Event) -> Result<()>,
    ) -> Result<()> {
        Err(ErrorKind::BackendUnavailable("curl").into())
    }
}

#[cfg(not(feature = "reqwest-backend"))]
pub mod reqwest_be {

    use super::Event;
    use crate::errors::*;
    use url::Url;

    pub fn download(
        _url: &Url,
        _resume_from: u64,
        _callback: &Fn(Event) -> Result<()>,
    ) -> Result<()> {
        Err(ErrorKind::BackendUnavailable("reqwest").into())
    }
}
<commit_msg>download: Fix signatures on not-$backend<commit_after>//! Easy file downloading
#![deny(rust_2018_idioms)]

use std::path::Path;
use url::Url;

mod errors;
pub use crate::errors::*;

#[derive(Debug, Copy, Clone)]
pub enum Backend {
    Curl,
    Reqwest,
}

#[derive(Debug, Copy, Clone)]
pub enum Event<'a> {
    ResumingPartialDownload,
    /// Received the Content-Length of the to-be downloaded data.
    DownloadContentLengthReceived(u64),
    /// Received some data.
    DownloadDataReceived(&'a [u8]),
}

fn download_with_backend(
    backend: Backend,
    url: &Url,
    resume_from: u64,
    callback: &dyn Fn(Event<'_>) -> Result<()>,
) -> Result<()> {
    match backend {
        Backend::Curl => curl::download(url, resume_from, callback),
        Backend::Reqwest => reqwest_be::download(url, resume_from, callback),
    }
}

pub fn download_to_path_with_backend(
    backend: Backend,
    url: &Url,
    path: &Path,
    resume_from_partial: bool,
    callback: Option<&dyn Fn(Event<'_>) -> Result<()>>,
) -> Result<()> {
    use std::cell::RefCell;
    use std::fs::OpenOptions;
    use std::io::{Read, Seek, SeekFrom, Write};

    || -> Result<()> {
        let (file, resume_from) = if resume_from_partial {
            let possible_partial = OpenOptions::new().read(true).open(&path);

            let downloaded_so_far = if let Ok(mut partial) = possible_partial {
                if let Some(cb) = callback {
                    cb(Event::ResumingPartialDownload)?;

                    let mut buf = vec![0; 32768];
                    let mut downloaded_so_far = 0;
                    loop {
                        let n = partial.read(&mut buf)?;
                        downloaded_so_far += n as u64;
                        if n == 0 {
                            break;
                        }
                        cb(Event::DownloadDataReceived(&buf[..n]))?;
                    }

                    downloaded_so_far
                } else {
                    let file_info = partial.metadata()?;
                    file_info.len()
                }
            } else {
                0
            };

            let mut possible_partial = OpenOptions::new()
                .write(true)
                .create(true)
                .open(&path)
                .chain_err(|| "error opening file for download")?;

            possible_partial.seek(SeekFrom::End(0))?;

            (possible_partial, downloaded_so_far)
        } else {
            (
                OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(&path)
                    .chain_err(|| "error creating file for download")?,
                0,
            )
        };

        let file = RefCell::new(file);

        download_with_backend(backend, url, resume_from, &|event| {
            if let Event::DownloadDataReceived(data) = event {
                file.borrow_mut()
                    .write_all(data)
                    .chain_err(|| "unable to write download to disk")?;
            }
            match callback {
                Some(cb) => cb(event),
                None => Ok(()),
            }
        })?;

        file.borrow_mut()
            .sync_data()
            .chain_err(|| "unable to sync download to disk")?;

        Ok(())
    }()
    .map_err(|e| {
        // TODO is there any point clearing up here? What kind of errors will leave us with an unusable partial?
        e
    })
}

/// Download via libcurl; encrypt with the native (or OpenSSl) TLS
/// stack via libcurl
#[cfg(feature = "curl-backend")]
pub mod curl {
    use super::Event;
    use crate::errors::*;
    use curl::easy::Easy;
    use std::cell::RefCell;
    use std::str;
    use std::time::Duration;
    use url::Url;

    pub fn download(
        url: &Url,
        resume_from: u64,
        callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<()> {
        // Fetch either a cached libcurl handle (which will preserve open
        // connections) or create a new one if it isn't listed.
        //
        // Once we've acquired it, reset the lifetime from 'static to our local
        // scope.
        thread_local!(static EASY: RefCell<Easy> = RefCell::new(Easy::new()));
        EASY.with(|handle| {
            let mut handle = handle.borrow_mut();

            handle
                .url(&url.to_string())
                .chain_err(|| "failed to set url")?;
            handle
                .follow_location(true)
                .chain_err(|| "failed to set follow redirects")?;

            if resume_from > 0 {
                handle
                    .resume_from(resume_from)
                    .chain_err(|| "setting the range header for download resumption")?;
            } else {
                // an error here indicates that the range header isn't supported by underlying curl,
                // so there's nothing to "clear" - safe to ignore this error.
                let _ = handle.resume_from(0);
            }

            // Take at most 30s to connect
            handle
                .connect_timeout(Duration::new(30, 0))
                .chain_err(|| "failed to set connect timeout")?;

            {
                let cberr = RefCell::new(None);
                let mut transfer = handle.transfer();

                // Data callback for libcurl which is called with data that's
                // downloaded. We just feed it into our hasher and also write it out
                // to disk.
                transfer
                    .write_function(|data| match callback(Event::DownloadDataReceived(data)) {
                        Ok(()) => Ok(data.len()),
                        Err(e) => {
                            *cberr.borrow_mut() = Some(e);
                            Ok(0)
                        }
                    })
                    .chain_err(|| "failed to set write")?;

                // Listen for headers and parse out a `Content-Length` (case-insensitive) if it
                // comes so we know how much we're downloading.
                transfer
                    .header_function(|header| {
                        if let Ok(data) = str::from_utf8(header) {
                            let prefix = "content-length: ";
                            if data.to_ascii_lowercase().starts_with(prefix) {
                                if let Ok(s) = data[prefix.len()..].trim().parse::<u64>() {
                                    let msg = Event::DownloadContentLengthReceived(s + resume_from);
                                    match callback(msg) {
                                        Ok(()) => (),
                                        Err(e) => {
                                            *cberr.borrow_mut() = Some(e);
                                            return false;
                                        }
                                    }
                                }
                            }
                        }
                        true
                    })
                    .chain_err(|| "failed to set header")?;

                // If an error happens check to see if we had a filesystem error up
                // in `cberr`, but we always want to punt it up.
                transfer.perform().or_else(|e| {
                    // If the original error was generated by one of our
                    // callbacks, return it.
                    match cberr.borrow_mut().take() {
                        Some(cberr) => Err(cberr),
                        None => {
                            // Otherwise, return the error from curl
                            if e.is_file_couldnt_read_file() {
                                Err(e).chain_err(|| ErrorKind::FileNotFound)
                            } else {
                                Err(e).chain_err(|| "error during download")
                            }
                        }
                    }
                })?;
            }

            // If we didn't get a 20x or 0 ("OK" for files) then return an error
            let code = handle
                .response_code()
                .chain_err(|| "failed to get response code")?;
            match code {
                0 | 200..=299 => {}
                _ => {
                    return Err(ErrorKind::HttpStatus(code).into());
                }
            };

            Ok(())
        })
    }
}

#[cfg(feature = "reqwest-backend")]
pub mod reqwest_be {
    use super::Event;
    use crate::errors::*;
    use lazy_static::lazy_static;
    use reqwest::{header, Client, Proxy, Response};
    use std::io;
    use std::time::Duration;
    use url::Url;

    pub fn download(
        url: &Url,
        resume_from: u64,
        callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<()> {
        // Short-circuit reqwest for the "file:" URL scheme
        if download_from_file_url(url, resume_from, callback)? {
            return Ok(());
        }

        let mut res = request(url, resume_from).chain_err(|| "failed to make network request")?;

        if !res.status().is_success() {
            let code: u16 = res.status().into();
            return Err(ErrorKind::HttpStatus(u32::from(code)).into());
        }

        let buffer_size = 0x10000;
        let mut buffer = vec![0u8; buffer_size];

        if let Some(len) = res.headers().get(header::CONTENT_LENGTH) {
            // TODO possible issues during unwrap?
            let len = len.to_str().unwrap().parse::<u64>().unwrap() + resume_from;
            callback(Event::DownloadContentLengthReceived(len))?;
        }

        loop {
            let bytes_read =
                io::Read::read(&mut res, &mut buffer).chain_err(|| "error reading from socket")?;

            if bytes_read != 0 {
                callback(Event::DownloadDataReceived(&buffer[0..bytes_read]))?;
            } else {
                return Ok(());
            }
        }
    }

    lazy_static! {
        static ref CLIENT: Client = {
            let catcher = || {
                Client::builder()
                    .gzip(false)
                    .proxy(Proxy::custom(env_proxy))
                    .timeout(Duration::from_secs(30))
                    .build()
            };

            // woah, an unwrap?!
            // It's OK. This is the same as what is happening in curl.
            //
            // The curl::Easy::new() internally assert!s that the initialized
            // Easy is not null. Inside reqwest, the errors here would be from
            // the TLS library returning a null pointer as well.
            catcher().unwrap()
        };
    }

    fn env_proxy(url: &Url) -> Option<Url> {
        env_proxy::for_url(url).to_url()
    }

    fn request(url: &Url, resume_from: u64) -> reqwest::Result<Response> {
        let mut req = CLIENT.get(url.as_str());

        if resume_from != 0 {
            req = req.header(header::RANGE, format!("bytes={}-", resume_from));
        }

        req.send()
    }

    fn download_from_file_url(
        url: &Url,
        resume_from: u64,
        callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<bool> {
        use std::fs;

        // The file scheme is mostly for use by tests to mock the dist server
        if url.scheme() == "file" {
            let src = url
                .to_file_path()
                .map_err(|_| Error::from(format!("bogus file url: '{}'", url)))?;
            if !src.is_file() {
                // Because some of rustup's logic depends on checking
                // the error when a downloaded file doesn't exist, make
                // the file case return the same error value as the
                // network case.
                return Err(ErrorKind::FileNotFound.into());
            }

            let mut f = fs::File::open(src).chain_err(|| "unable to open downloaded file")?;
            io::Seek::seek(&mut f, io::SeekFrom::Start(resume_from))?;

            let mut buffer = vec![0u8; 0x10000];
            loop {
                let bytes_read = io::Read::read(&mut f, &mut buffer)
                    .chain_err(|| "unable to read downloaded file")?;
                if bytes_read == 0 {
                    break;
                }
                callback(Event::DownloadDataReceived(&buffer[0..bytes_read]))?;
            }

            Ok(true)
        } else {
            Ok(false)
        }
    }
}

#[cfg(not(feature = "curl-backend"))]
pub mod curl {

    use super::Event;
    use crate::errors::*;
    use url::Url;

    pub fn download(
        _url: &Url,
        _resume_from: u64,
        _callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<()> {
        Err(ErrorKind::BackendUnavailable("curl").into())
    }
}

#[cfg(not(feature = "reqwest-backend"))]
pub mod reqwest_be {

    use super::Event;
    use crate::errors::*;
    use url::Url;

    pub fn download(
        _url: &Url,
        _resume_from: u64,
        _callback: &dyn Fn(Event<'_>) -> Result<()>,
    ) -> Result<()> {
        Err(ErrorKind::BackendUnavailable("reqwest").into())
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::IntoIterator;

#[derive(Debug)]
pub struct OrderedHashMap<K, V> {
    base: HashMap<K, V>,
    order: Vec<K>,
}

pub struct Iter<'a, K, V> {
    base: &'a HashMap<K, V>,
    order_iterator: std::slice::Iter<'a, K>,
}

pub struct IterMut<'a, K, V> {
    base: &'a mut HashMap<K, V>,
    order_iterator: std::slice::Iter<'a, K>,
}

impl<'a, K, V> IntoIterator for &'a OrderedHashMap<K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    type IntoIter = Iter<'a, K, V>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            base: &self.base,
            order_iterator: self.order.iter(),
        }
    }
}

impl<'a, K, V> Iterator for Iter<'a, K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.order_iterator.next() {
            Some(k) => self.base.get_key_value(&k),
            None => None,
        }
    }
}

impl<'a, K, V> Iterator for IterMut<'a, K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.order_iterator.next() {
            Some(ref k) => Some((&k, self.base.get_mut(&k).unwrap())),
            None => None,
        }
    }
}

impl<K, V> OrderedHashMap<K, V>
where
    K: Eq + Hash + Clone,
{
    pub fn new() -> OrderedHashMap<K, V> {
        OrderedHashMap {
            base: HashMap::<K, V>::new(),
            order: Vec::<K>::new(),
        }
    }
    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    {
        self.base.get(k)
    }
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.order.push(k.clone());
        self.base.insert(k, v)
    }
    pub fn iter(&self) -> Iter<'_, K, V> {
        Iter {
            base: &self.base,
            order_iterator: self.order.iter(),
        }
    }
    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
        IterMut {
            base: &mut self.base,
            order_iterator: self.order.iter(),
        }
    }
    pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
        self.base.entry(key)
    }
}

<commit_msg>fix missing key in order<commit_after>use std::borrow::Borrow;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::IntoIterator;

#[derive(Debug)]
pub struct OrderedHashMap<K, V> {
    base: HashMap<K, V>,
    order: Vec<K>,
}

pub struct Iter<'a, K, V> {
    base: &'a HashMap<K, V>,
    order_iterator: std::slice::Iter<'a, K>,
}

pub struct IterMut<'a, K, V> {
    base: &'a mut HashMap<K, V>,
    order_iterator: std::slice::Iter<'a, K>,
}

impl<'a, K, V> IntoIterator for &'a OrderedHashMap<K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    type IntoIter = Iter<'a, K, V>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            base: &self.base,
            order_iterator: self.order.iter(),
        }
    }
}

impl<'a, K, V> Iterator for Iter<'a, K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.order_iterator.next() {
            Some(k) => self.base.get_key_value(&k),
            None => None,
        }
    }
}

impl<'a, K, V> Iterator for IterMut<'a, K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.order_iterator.next() {
            Some(ref k) => Some((&k, self.base.get_mut(&k).unwrap())),
            None => None,
        }
    }
}

impl<K, V> OrderedHashMap<K, V>
where
    K: Eq + Hash + Clone,
{
    pub fn new() -> OrderedHashMap<K, V> {
        OrderedHashMap {
            base: HashMap::<K, V>::new(),
            order: Vec::<K>::new(),
        }
    }
    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    {
        self.base.get(k)
    }
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.order.push(k.clone());
        self.base.insert(k, v)
    }
    pub fn iter(&self) -> Iter<'_, K, V> {
        Iter {
            base: &self.base,
            order_iterator: self.order.iter(),
        }
    }
    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
        IterMut {
            base: &mut self.base,
            order_iterator: self.order.iter(),
        }
    }
    pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
        self.order.push(key.clone());
        self.base.entry(key)
    }
}
<|endoftext|>


<commit_before>//ignore-windows: TODO env var emulation stubbed out on Windows

use std::env;

fn main() {
    assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent));
    env::set_var("MIRI_TEST", "the answer");
    assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned()));
}
<commit_msg>Test env isolation<commit_after>//ignore-windows: TODO env var emulation stubbed out on Windows

use std::env;

fn main() {
    assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent));
    env::set_var("MIRI_TEST", "the answer");
    assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned()));
    // Test that miri environment is isolated when communication is disabled.
    assert!(env::var("MIRI_ENV_VAR_TEST").is_err());
}
<|endoftext|>


<commit_before>//! Defines common interfaces for interacting with statistical distributions and provides
//! concrete implementations for a variety of distributions.

use rand::Rng;
use statistics::{Min, Max};

pub use self::bernoulli::Bernoulli;
pub use self::beta::Beta;
pub use self::binomial::Binomial;
pub use self::categorical::Categorical;
pub use self::cauchy::Cauchy;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::dirichlet::Dirichlet;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::fisher_snedecor::FisherSnedecor;
pub use self::gamma::Gamma;
pub use self::geometric::Geometric;
pub use self::hypergeometric::Hypergeometric;
pub use self::inverse_gamma::InverseGamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::students_t::StudentsT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod beta;
mod binomial;
mod categorical;
mod cauchy;
mod chi;
mod chi_squared;
mod dirichlet;
mod discrete_uniform;
mod exponential;
mod fisher_snedecor;
mod gamma;
mod geometric;
mod hypergeometric;
mod inverse_gamma;
mod log_normal;
mod normal;
mod poisson;
mod students_t;
mod triangular;
mod uniform;
mod weibull;
mod ziggurat;
mod ziggurat_tables;

/// The `Distribution` trait is used to specify an interface
/// for sampling statistical distributions
pub trait Distribution<T> {
    /// Draws a random sample using the supplied random number generator
    /// # Examples
    ///
    /// A trivial implementation that just samples from the supplied
    /// random number generator
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    ///
    /// use rand::Rng;
    /// use statrs::distribution::Distribution;
    ///
    /// struct Foo;
    ///
    /// impl Distribution<f64> for Foo {
    ///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
    ///         r.next_f64()
    ///     }
    /// }
    ///
    /// # fn main() { }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> T;
}

/// The `Univariate` trait is used to specify an interface for univariate
/// distributions e.g. distributions that have a closed form cumulative distribution
/// function
pub trait Univariate<T, K>: Distribution<K> + Min<T> + Max<T> {
    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Univariate, Uniform};
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self, x: K) -> K;
}

/// The `Continuous` trait extends the `Distribution`
/// trait and provides an interface for interacting with continuous
/// statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Continuous` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution.
pub trait Continuous<T, K> {
    /// Returns the probability density function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Continuous, Uniform};
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(1.0, n.pdf(0.5));
    /// ```
    fn pdf(&self, x: T) -> K;

    /// Returns the log of the probability density function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Continuous, Uniform};
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.ln_pdf(0.5));
    /// ```
    fn ln_pdf(&self, x: T) -> K;
}

/// The `Discrete` trait extends the `Distribution`
/// trait and provides an interface for interacting with discrete
/// statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Discrete` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution.
pub trait Discrete<T, K> {
    /// Returns the probability mass function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Discrete, Binomial};
    /// use statrs::prec;
    ///
    /// let n = Binomial::new(0.5, 10).unwrap();
    /// assert!(prec::almost_eq(n.pmf(5), 0.24609375, 1e-15));
    /// ```
    fn pmf(&self, x: T) -> K;

    /// Returns the log of the probability mass function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Discrete, Binomial};
    /// use statrs::prec;
    ///
    /// let n = Binomial::new(0.5, 10).unwrap();
    /// assert!(prec::almost_eq(n.ln_pmf(5), (0.24609375f64).ln(), 1e-15));
    /// ```
    fn ln_pmf(&self, x: T) -> K;
}
<commit_msg>wip: add InverseCDF trait<commit_after>//! Defines common interfaces for interacting with statistical distributions and provides
//! concrete implementations for a variety of distributions.

use rand::Rng;
use statistics::{Min, Max};

pub use self::bernoulli::Bernoulli;
pub use self::beta::Beta;
pub use self::binomial::Binomial;
pub use self::categorical::Categorical;
pub use self::cauchy::Cauchy;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::dirichlet::Dirichlet;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::fisher_snedecor::FisherSnedecor;
pub use self::gamma::Gamma;
pub use self::geometric::Geometric;
pub use self::hypergeometric::Hypergeometric;
pub use self::inverse_gamma::InverseGamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::students_t::StudentsT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod beta;
mod binomial;
mod categorical;
mod cauchy;
mod chi;
mod chi_squared;
mod dirichlet;
mod discrete_uniform;
mod exponential;
mod fisher_snedecor;
mod gamma;
mod geometric;
mod hypergeometric;
mod inverse_gamma;
mod log_normal;
mod normal;
mod poisson;
mod students_t;
mod triangular;
mod uniform;
mod weibull;
mod ziggurat;
mod ziggurat_tables;

/// The `Distribution` trait is used to specify an interface
/// for sampling statistical distributions
pub trait Distribution<T> {
    /// Draws a random sample using the supplied random number generator
    /// # Examples
    ///
    /// A trivial implementation that just samples from the supplied
    /// random number generator
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    ///
    /// use rand::Rng;
    /// use statrs::distribution::Distribution;
    ///
    /// struct Foo;
    ///
    /// impl Distribution<f64> for Foo {
    ///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
    ///         r.next_f64()
    ///     }
    /// }
    ///
    /// # fn main() { }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> T;
}

/// The `Univariate` trait is used to specify an interface for univariate
/// distributions e.g. distributions that have a closed form cumulative distribution
/// function
pub trait Univariate<T, K>: Distribution<K> + Min<T> + Max<T> {
    /// Returns the cumulative distribution function calculated
    /// at `x` for a given distribution. May panic depending
    /// on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Univariate, Uniform};
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.5, n.cdf(0.5));
    /// ```
    fn cdf(&self, x: K) -> K;
}

/// The `InverseCDF` trait used to specify an interface for distributions
/// with a closed form solution to the inverse cumulative distribution function.
/// This trait will probably be merged into `Univariate` in a future release
/// when already implemented distributions have `InverseCDF` back ported
pub trait InverseCDF<T> {
    /// Returns the inverse cumulative distribution function
    /// calculated at `x` for a given distribution. May panic
    /// depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// ```
    fn inverse_cdf(&self, x: T) -> T;
}

/// The `Continuous` trait extends the `Distribution`
/// trait and provides an interface for interacting with continuous
/// statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Continuous` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution.
pub trait Continuous<T, K> {
    /// Returns the probability density function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Continuous, Uniform};
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(1.0, n.pdf(0.5));
    /// ```
    fn pdf(&self, x: T) -> K;

    /// Returns the log of the probability density function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Continuous, Uniform};
    ///
    /// let n = Uniform::new(0.0, 1.0).unwrap();
    /// assert_eq!(0.0, n.ln_pdf(0.5));
    /// ```
    fn ln_pdf(&self, x: T) -> K;
}

/// The `Discrete` trait extends the `Distribution`
/// trait and provides an interface for interacting with discrete
/// statistical distributions
///
/// # Remarks
///
/// All methods provided by the `Discrete` trait are unchecked, meaning
/// they can panic if in an invalid state or encountering invalid input
/// depending on the implementing distribution.
pub trait Discrete<T, K> {
    /// Returns the probability mass function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Discrete, Binomial};
    /// use statrs::prec;
    ///
    /// let n = Binomial::new(0.5, 10).unwrap();
    /// assert!(prec::almost_eq(n.pmf(5), 0.24609375, 1e-15));
    /// ```
    fn pmf(&self, x: T) -> K;

    /// Returns the log of the probability mass function calculated at `x` for a given distribution.
    /// May panic depending on the implementor.
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::{Discrete, Binomial};
    /// use statrs::prec;
    ///
    /// let n = Binomial::new(0.5, 10).unwrap();
    /// assert!(prec::almost_eq(n.ln_pmf(5), (0.24609375f64).ln(), 1e-15));
    /// ```
    fn ln_pmf(&self, x: T) -> K;
}
<|endoftext|>


<commit_before>use regex::Regex;

lazy_static! {
    pub static ref BLOCK_QUOTATION_PATTERN: Regex = Regex::new("^bq(?P<attributes>.*?)(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref CODE_BLOCK_PATTERN: Regex = Regex::new("^bc(?P<attributes>.*?)(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref COMMENT_PATTERN: Regex = Regex::new("^#{3}(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref HEADING_PATTERN: Regex = Regex::new("^h(?P<level>[1-6])(?P<attributes>.*)\\. ").unwrap();
    pub static ref NO_TEXTILE_BLOCK_PATTERN: Regex = Regex::new("^notextile(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref PARAGRAPH_PATTERN: Regex = Regex::new("(?:^p(?P<attributes>.*)\\. )?").unwrap();
    pub static ref PRE_PATTERN: Regex = Regex::new("^pre(?P<attributes>.*)(?P<mode>\\.{1,2}) ").unwrap();

    pub static ref ABBREVIATION_PATTERN: Regex = Regex::new(r"^(?P<abbreviation>\p{Lu}{3,})(?:\((?P<transcript>.*?)\))?").unwrap();
    pub static ref BOLD_TEXT_PATTERN: Regex = Regex::new(r"^(?P<count1>\*+)(?P<string>.+?)(?P<count2>\*+)").unwrap();
    pub static ref CITATION_PATTERN: Regex = Regex::new(r"^\?\?(?P<string>.+?)\?\?").unwrap();
    pub static ref CODE_PATTERN: Regex = Regex::new("^@(?P<code>.*?)@").unwrap();
    pub static ref IMAGE_PATTERN: Regex = Regex::new("^!(?P<align>[<|>|=]?)(?P<string>.+?)!").unwrap();
    pub static ref IMAGE_URL_ALT_PATTERN: Regex = Regex::new("(?P<url>[^\\(\\) ]+)(?:\\((?P<alt>.+)\\))?").unwrap();
    pub static ref ITALIC_TEXT_PATTERN: Regex = Regex::new("^(?P<count1>_+)(?P<string>.+?)(?P<count2>_+)").unwrap();
    pub static ref LINK_PATTERN: Regex = Regex::new("^\"(?P<string>.+?)\":(?P<url>[^ \\(\\)]+)").unwrap();
    pub static ref NO_TEXTILE_INLINE_PATTERN: Regex = Regex::new("^={2}(?P<string>.*?)={2}").unwrap();
    pub static ref SPAN_PATTERN: Regex = Regex::new("^(?P<count1>%+)(?P<string>.+?)(?P<count2>%+)").unwrap();
    pub static ref STRIKETHROUGH_TEXT_PATTERN: Regex = Regex::new("^(?P<count1>-+)(?P<string>.+?)(?P<count2>-+)").unwrap();
    pub static ref SUBSCRIPT_TEXT_PATTERN: Regex = Regex::new("^(?P<count1>~+)(?P<string>.+?)(?P<count2>~+)").unwrap();
    pub static ref SUPERSCRIPT_TEXT_PATTERN: Regex = Regex::new(r"^(?P<count1>\^+)(?P<string>.+?)(?P<count2>\^+)").unwrap();
    pub static ref UNDERLINED_TEXT_PATTERN: Regex = Regex::new(r"^(?P<count1>\++)(?P<string>.+?)(?P<count2>\++)").unwrap();

    pub static ref ATTRS_STR_PATTERN: Regex = Regex::new("(?:^([\\[\\{\\(].+?[\\]\\}\\)])*)").unwrap();
    pub static ref PADDING_PATTERN: Regex = Regex::new("\\(+|\\)+").unwrap();
    pub static ref ALIGN_PATTERN: Regex = Regex::new("[<|>|=]{1,2}").unwrap();
    pub static ref LANG_PATTERN: Regex = Regex::new("\\[([A-Za-z]{2}(?:-[A-Za-z]{2})?)\\]").unwrap();
    pub static ref CLASS_ID_PATTERN: Regex = Regex::new("\\((?P<class>[\\w-_\\. ]+)?(?:#(?P<id>[\\w-_]+))?\\)").unwrap();
    pub static ref CLASS_STR_SPLIT_PATTERN: Regex = Regex::new(" +").unwrap();
    pub static ref CSS_PROPS_PATTERN: Regex = Regex::new("\\{([^\\{\\}]+)\\}").unwrap();
    pub static ref CSS_PROPS_SPLIT_PATTERN: Regex = Regex::new("; *").unwrap();
    pub static ref CSS_PROP_STR_PATTERN: Regex = Regex::new("(?P<key>[a-z-_]+): *(?P<value>.+)").unwrap();
}
<commit_msg>Fix 'pre' block element pattern<commit_after>use regex::Regex;

lazy_static! {
    pub static ref BLOCK_QUOTATION_PATTERN: Regex = Regex::new("^bq(?P<attributes>.*?)(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref CODE_BLOCK_PATTERN: Regex = Regex::new("^bc(?P<attributes>.*?)(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref COMMENT_PATTERN: Regex = Regex::new("^#{3}(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref HEADING_PATTERN: Regex = Regex::new("^h(?P<level>[1-6])(?P<attributes>.*)\\. ").unwrap();
    pub static ref NO_TEXTILE_BLOCK_PATTERN: Regex = Regex::new("^notextile(?P<mode>\\.{1,2}) ").unwrap();
    pub static ref PARAGRAPH_PATTERN: Regex = Regex::new("(?:^p(?P<attributes>.*)\\. )?").unwrap();
    pub static ref PRE_PATTERN: Regex = Regex::new("^pre(?P<attributes>.*?)(?P<mode>\\.{1,2}) ").unwrap();

    pub static ref ABBREVIATION_PATTERN: Regex = Regex::new(r"^(?P<abbreviation>\p{Lu}{3,})(?:\((?P<transcript>.*?)\))?").unwrap();
    pub static ref BOLD_TEXT_PATTERN: Regex = Regex::new(r"^(?P<count1>\*+)(?P<string>.+?)(?P<count2>\*+)").unwrap();
    pub static ref CITATION_PATTERN: Regex = Regex::new(r"^\?\?(?P<string>.+?)\?\?").unwrap();
    pub static ref CODE_PATTERN: Regex = Regex::new("^@(?P<code>.*?)@").unwrap();
    pub static ref IMAGE_PATTERN: Regex = Regex::new("^!(?P<align>[<|>|=]?)(?P<string>.+?)!").unwrap();
    pub static ref IMAGE_URL_ALT_PATTERN: Regex = Regex::new("(?P<url>[^\\(\\) ]+)(?:\\((?P<alt>.+)\\))?").unwrap();
    pub static ref ITALIC_TEXT_PATTERN: Regex = Regex::new("^(?P<count1>_+)(?P<string>.+?)(?P<count2>_+)").unwrap();
    pub static ref LINK_PATTERN: Regex = Regex::new("^\"(?P<string>.+?)\":(?P<url>[^ \\(\\)]+)").unwrap();
    pub static ref NO_TEXTILE_INLINE_PATTERN: Regex = Regex::new("^={2}(?P<string>.*?)={2}").unwrap();
    pub static ref SPAN_PATTERN: Regex = Regex::new("^(?P<count1>%+)(?P<string>.+?)(?P<count2>%+)").unwrap();
    pub static ref STRIKETHROUGH_TEXT_PATTERN: Regex = Regex::new("^(?P<count1>-+)(?P<string>.+?)(?P<count2>-+)").unwrap();
    pub static ref SUBSCRIPT_TEXT_PATTERN: Regex = Regex::new("^(?P<count1>~+)(?P<string>.+?)(?P<count2>~+)").unwrap();
    pub static ref SUPERSCRIPT_TEXT_PATTERN: Regex = Regex::new(r"^(?P<count1>\^+)(?P<string>.+?)(?P<count2>\^+)").unwrap();
    pub static ref UNDERLINED_TEXT_PATTERN: Regex = Regex::new(r"^(?P<count1>\++)(?P<string>.+?)(?P<count2>\++)").unwrap();

    pub static ref ATTRS_STR_PATTERN: Regex = Regex::new("(?:^([\\[\\{\\(].+?[\\]\\}\\)])*)").unwrap();
    pub static ref PADDING_PATTERN: Regex = Regex::new("\\(+|\\)+").unwrap();
    pub static ref ALIGN_PATTERN: Regex = Regex::new("[<|>|=]{1,2}").unwrap();
    pub static ref LANG_PATTERN: Regex = Regex::new("\\[([A-Za-z]{2}(?:-[A-Za-z]{2})?)\\]").unwrap();
    pub static ref CLASS_ID_PATTERN: Regex = Regex::new("\\((?P<class>[\\w-_\\. ]+)?(?:#(?P<id>[\\w-_]+))?\\)").unwrap();
    pub static ref CLASS_STR_SPLIT_PATTERN: Regex = Regex::new(" +").unwrap();
    pub static ref CSS_PROPS_PATTERN: Regex = Regex::new("\\{([^\\{\\}]+)\\}").unwrap();
    pub static ref CSS_PROPS_SPLIT_PATTERN: Regex = Regex::new("; *").unwrap();
    pub static ref CSS_PROP_STR_PATTERN: Regex = Regex::new("(?P<key>[a-z-_]+): *(?P<value>.+)").unwrap();
}
<|endoftext|>


<commit_before>//! waypoint handles parsing of GPX-spec waypoints.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use geo::Point;
use parser::extensions;
use parser::fix;
use parser::link;
use parser::string;
use parser::time;
use parser::verify_starting_tag;
use parser::Context;

use Waypoint;

use GpxVersion;

/// consume consumes a GPX waypoint from the `reader` until it ends.
pub fn consume<R: Read>(context: &mut Context<R>, tagname: &'static str) -> Result<Waypoint> {
    let attributes = verify_starting_tag(context, tagname)?;

    // get required latitude and longitude
    let latitude = attributes
        .iter()
        .filter(|attr| attr.name.local_name == "lat")
        .nth(0)
        .ok_or(ErrorKind::InvalidElementLacksAttribute(
            "latitude", "waypoint",
        ))?;

    let latitude: f64 = latitude
        .clone()
        .value
        .parse()
        .chain_err(|| "error while casting latitude to f64")?;

    let longitude = attributes
        .iter()
        .filter(|attr| attr.name.local_name == "lon")
        .nth(0)
        .ok_or(ErrorKind::InvalidElementLacksAttribute(
            "longitude",
            "waypoint",
        ))?;

    let longitude: f64 = longitude
        .clone()
        .value
        .parse()
        .chain_err(|| "error while casting longitude to f64")?;

    let mut waypoint: Waypoint = Waypoint::new(Point::new(longitude, latitude));

    loop {
        let next_event = {
            if let Some(next) = context.reader.peek() {
                next.clone()
            } else {
                break;
            }
        };

        match next_event.chain_err(|| Error::from("error while parsing waypoint event"))? {
            XmlEvent::StartElement { ref name, .. } => match name.local_name.as_ref() {
                "ele" => {
                    // Cast the elevation to an f64, from a string.
                    waypoint.elevation = Some(string::consume(context, "ele")?
                        .parse()
                        .chain_err(|| "error while casting elevation to f64")?)
                }
                "speed" if context.version == GpxVersion::Gpx10 => {
                    // Speed is from GPX 1.0
                    waypoint.speed = Some(string::consume(context, "speed")?
                        .parse()
                        .chain_err(|| "error while casting speed to f64")?);
                }
                "time" => waypoint.time = Some(time::consume(context)?),
                "name" => waypoint.name = Some(string::consume(context, "name")?),
                "cmt" => waypoint.comment = Some(string::consume(context, "cmt")?),
                "desc" => waypoint.description = Some(string::consume(context, "desc")?),
                "src" => waypoint.source = Some(string::consume(context, "src")?),
                "link" => waypoint.links.push(link::consume(context)?),
                "sym" => waypoint.symbol = Some(string::consume(context, "sym")?),
                "type" => waypoint._type = Some(string::consume(context, "type")?),

                // Optional accuracy information
                "fix" => waypoint.fix = Some(fix::consume(context)?),
                "geoidheight" => {
                    waypoint.geoidheight = Some(string::consume(context, "geoidheight")?
                        .parse()
                        .chain_err(|| "error while casting geoid (geoidheight) to f64")?)
                }
                "sat" => {
                    waypoint.sat = Some(string::consume(context, "sat")?
                        .parse()
                        .chain_err(|| "error while casting number of satellites (sat) to u64")?)
                }
                "hdop" => {
                    waypoint.hdop = Some(string::consume(context, "hdop")?.parse().chain_err(
                        || "error while casting horizontal dilution of precision (hdop) to f64",
                    )?)
                }
                "vdop" => {
                    waypoint.vdop = Some(string::consume(context, "vdop")?.parse().chain_err(
                        || "error while casting vertical dilution of precision (vdop) to f64",
                    )?)
                }
                "pdop" => {
                    waypoint.pdop = Some(string::consume(context, "pdop")?.parse().chain_err(
                        || "error while casting position dilution of precision (pdop) to f64",
                    )?)
                }
                "ageofgpsdata" => {
                    waypoint.age = Some(string::consume(context, "ageofgpsdata")?
                        .parse()
                        .chain_err(|| "error while casting age of GPS data to f64")?)
                }
                "dgpsid" => {
                    waypoint.dgpsid = Some(string::consume(context, "dgpsid")?
                        .parse()
                        .chain_err(|| "error while casting DGPS station ID to u16")?)
                }

                // Finally the GPX 1.1 extensions
                "extensions" => extensions::consume(context)?,
                child => {
                    bail!(ErrorKind::InvalidChildElement(
                        String::from(child),
                        "waypoint"
                    ));
                }
            },
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == tagname,
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), "waypoint")
                );
                context.reader.next(); //consume the end tag
                return Ok(waypoint);
            }
            _ => {
                context.reader.next(); //consume and ignore this event
            }
        }
    }

    bail!(ErrorKind::MissingClosingTag("waypoint"));
}

#[cfg(test)]
mod tests {
    use geo::Point;
    use std::io::BufReader;

    use super::consume;
    use Fix;
    use GpxVersion;

    #[test]
    fn consume_waypoint() {
        let waypoint = consume!(
            "
            <wpt lon=\"-77.0365\" lat=\"38.8977\">
                <name>The White House</name>
                <cmt>This is a comment about the white house.</cmt>
                <desc>The white house is very nice!</desc>
                <src>Garmin eTrex</src>
                <type>waypoint classification</type>
                <ele>4608.12</ele>
                <fix>dgps</fix>
                <sat>4</sat>
                <hdop>6.058</hdop>
                <speed>0.0000</speed>
            </wpt>
            ",
            GpxVersion::Gpx10,
            "wpt"
        );

        assert!(waypoint.is_ok());

        let waypoint = waypoint.unwrap();

        assert_eq!(waypoint.point(), Point::new(-77.0365, 38.8977));
        assert_eq!(waypoint.name.unwrap(), "The White House");
        assert_eq!(
            waypoint.comment.unwrap(),
            "This is a comment about the white house."
        );
        assert_eq!(
            waypoint.description.unwrap(),
            "The white house is very nice!"
        );
        assert_eq!(waypoint.source.unwrap(), "Garmin eTrex");
        assert_eq!(waypoint._type.unwrap(), "waypoint classification");
        assert_eq!(waypoint.elevation.unwrap(), 4608.12);
        assert_eq!(waypoint.fix.unwrap(), Fix::DGPS);
        assert_eq!(waypoint.sat.unwrap(), 4);
        assert_eq!(waypoint.hdop.unwrap(), 6.058);
    }

    #[test]
    fn consume_empty() {
        let waypoint = consume!(
            "<trkpt lat=\"2.345\" lon=\"1.234\"></trkpt>",
            GpxVersion::Gpx11,
            "trkpt"
        );

        assert!(waypoint.is_ok());
        let waypoint = waypoint.unwrap();

        assert_eq!(waypoint.point(), Point::new(1.234, 2.345));
        assert_eq!(waypoint.point().lng(), 1.234);
        assert_eq!(waypoint.point().lat(), 2.345);
    }

    #[test]
    fn consume_bad_waypoint() {
        let waypoint = consume!(
            "<wpt lat=\"32.4\" lon=\"notanumber\"></wpt>",
            GpxVersion::Gpx11,
            "wpt"
        );

        assert!(waypoint.is_err());
    }
}
<commit_msg>fmt src/parser/waypoint.rs file<commit_after>//! waypoint handles parsing of GPX-spec waypoints.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use geo::Point;
use parser::extensions;
use parser::fix;
use parser::link;
use parser::string;
use parser::time;
use parser::verify_starting_tag;
use parser::Context;

use Waypoint;

use GpxVersion;

/// consume consumes a GPX waypoint from the `reader` until it ends.
pub fn consume<R: Read>(context: &mut Context<R>, tagname: &'static str) -> Result<Waypoint> {
    let attributes = verify_starting_tag(context, tagname)?;

    // get required latitude and longitude
    let latitude = attributes
        .iter()
        .filter(|attr| attr.name.local_name == "lat")
        .nth(0)
        .ok_or(ErrorKind::InvalidElementLacksAttribute(
            "latitude", "waypoint",
        ))?;

    let latitude: f64 = latitude
        .clone()
        .value
        .parse()
        .chain_err(|| "error while casting latitude to f64")?;

    let longitude = attributes
        .iter()
        .filter(|attr| attr.name.local_name == "lon")
        .nth(0)
        .ok_or(ErrorKind::InvalidElementLacksAttribute(
            "longitude",
            "waypoint",
        ))?;

    let longitude: f64 = longitude
        .clone()
        .value
        .parse()
        .chain_err(|| "error while casting longitude to f64")?;

    let mut waypoint: Waypoint = Waypoint::new(Point::new(longitude, latitude));

    loop {
        let next_event = {
            if let Some(next) = context.reader.peek() {
                next.clone()
            } else {
                break;
            }
        };

        match next_event.chain_err(|| Error::from("error while parsing waypoint event"))? {
            XmlEvent::StartElement { ref name, .. } => match name.local_name.as_ref() {
                "ele" => {
                    // Cast the elevation to an f64, from a string.
                    waypoint.elevation = Some(
                        string::consume(context, "ele")?
                            .parse()
                            .chain_err(|| "error while casting elevation to f64")?,
                    )
                }
                "speed" if context.version == GpxVersion::Gpx10 => {
                    // Speed is from GPX 1.0
                    waypoint.speed = Some(
                        string::consume(context, "speed")?
                            .parse()
                            .chain_err(|| "error while casting speed to f64")?,
                    );
                }
                "time" => waypoint.time = Some(time::consume(context)?),
                "name" => waypoint.name = Some(string::consume(context, "name")?),
                "cmt" => waypoint.comment = Some(string::consume(context, "cmt")?),
                "desc" => waypoint.description = Some(string::consume(context, "desc")?),
                "src" => waypoint.source = Some(string::consume(context, "src")?),
                "link" => waypoint.links.push(link::consume(context)?),
                "sym" => waypoint.symbol = Some(string::consume(context, "sym")?),
                "type" => waypoint._type = Some(string::consume(context, "type")?),

                // Optional accuracy information
                "fix" => waypoint.fix = Some(fix::consume(context)?),
                "geoidheight" => {
                    waypoint.geoidheight = Some(
                        string::consume(context, "geoidheight")?
                            .parse()
                            .chain_err(|| "error while casting geoid (geoidheight) to f64")?,
                    )
                }
                "sat" => {
                    waypoint.sat = Some(
                        string::consume(context, "sat")?
                            .parse()
                            .chain_err(|| "error while casting number of satellites (sat) to u64")?,
                    )
                }
                "hdop" => {
                    waypoint.hdop = Some(string::consume(context, "hdop")?.parse().chain_err(
                        || "error while casting horizontal dilution of precision (hdop) to f64",
                    )?)
                }
                "vdop" => {
                    waypoint.vdop = Some(string::consume(context, "vdop")?.parse().chain_err(
                        || "error while casting vertical dilution of precision (vdop) to f64",
                    )?)
                }
                "pdop" => {
                    waypoint.pdop = Some(string::consume(context, "pdop")?.parse().chain_err(
                        || "error while casting position dilution of precision (pdop) to f64",
                    )?)
                }
                "ageofgpsdata" => {
                    waypoint.age = Some(
                        string::consume(context, "ageofgpsdata")?
                            .parse()
                            .chain_err(|| "error while casting age of GPS data to f64")?,
                    )
                }
                "dgpsid" => {
                    waypoint.dgpsid = Some(
                        string::consume(context, "dgpsid")?
                            .parse()
                            .chain_err(|| "error while casting DGPS station ID to u16")?,
                    )
                }

                // Finally the GPX 1.1 extensions
                "extensions" => extensions::consume(context)?,
                child => {
                    bail!(ErrorKind::InvalidChildElement(
                        String::from(child),
                        "waypoint"
                    ));
                }
            },
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == tagname,
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), "waypoint")
                );
                context.reader.next(); //consume the end tag
                return Ok(waypoint);
            }
            _ => {
                context.reader.next(); //consume and ignore this event
            }
        }
    }

    bail!(ErrorKind::MissingClosingTag("waypoint"));
}

#[cfg(test)]
mod tests {
    use geo::Point;
    use std::io::BufReader;

    use super::consume;
    use Fix;
    use GpxVersion;

    #[test]
    fn consume_waypoint() {
        let waypoint = consume!(
            "
            <wpt lon=\"-77.0365\" lat=\"38.8977\">
                <name>The White House</name>
                <cmt>This is a comment about the white house.</cmt>
                <desc>The white house is very nice!</desc>
                <src>Garmin eTrex</src>
                <type>waypoint classification</type>
                <ele>4608.12</ele>
                <fix>dgps</fix>
                <sat>4</sat>
                <hdop>6.058</hdop>
                <speed>0.0000</speed>
            </wpt>
            ",
            GpxVersion::Gpx10,
            "wpt"
        );

        assert!(waypoint.is_ok());

        let waypoint = waypoint.unwrap();

        assert_eq!(waypoint.point(), Point::new(-77.0365, 38.8977));
        assert_eq!(waypoint.name.unwrap(), "The White House");
        assert_eq!(
            waypoint.comment.unwrap(),
            "This is a comment about the white house."
        );
        assert_eq!(
            waypoint.description.unwrap(),
            "The white house is very nice!"
        );
        assert_eq!(waypoint.source.unwrap(), "Garmin eTrex");
        assert_eq!(waypoint._type.unwrap(), "waypoint classification");
        assert_eq!(waypoint.elevation.unwrap(), 4608.12);
        assert_eq!(waypoint.fix.unwrap(), Fix::DGPS);
        assert_eq!(waypoint.sat.unwrap(), 4);
        assert_eq!(waypoint.hdop.unwrap(), 6.058);
    }

    #[test]
    fn consume_empty() {
        let waypoint = consume!(
            "<trkpt lat=\"2.345\" lon=\"1.234\"></trkpt>",
            GpxVersion::Gpx11,
            "trkpt"
        );

        assert!(waypoint.is_ok());
        let waypoint = waypoint.unwrap();

        assert_eq!(waypoint.point(), Point::new(1.234, 2.345));
        assert_eq!(waypoint.point().lng(), 1.234);
        assert_eq!(waypoint.point().lat(), 2.345);
    }

    #[test]
    fn consume_bad_waypoint() {
        let waypoint = consume!(
            "<wpt lat=\"32.4\" lon=\"notanumber\"></wpt>",
            GpxVersion::Gpx11,
            "wpt"
        );

        assert!(waypoint.is_err());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0
use crate::{
    data::{LibraAccountResource, LibraEventHandle, LibraStatus},
    error::*,
};
use libra_types::{
    account_config::AccountResource, account_state_blob::AccountStateBlob, event::EVENT_KEY_LENGTH,
};
use std::{convert::TryFrom, slice};

pub fn libra_LibraAccountResource_from_safe(
    blob: AccountStateBlob,
) -> Result<LibraAccountResource, LibraStatus> {
    clear_error();
    match AccountResource::try_from(&blob) {
        Ok(account_resource) => {
            let mut authentication_key = [0u8; 32];
            authentication_key.copy_from_slice(account_resource.authentication_key().as_bytes());

            let mut sent_key_copy = [0u8; EVENT_KEY_LENGTH];
            sent_key_copy.copy_from_slice(account_resource.sent_events().key().as_bytes());

            let sent_events = LibraEventHandle {
                count: account_resource.sent_events().count(),
                key: sent_key_copy,
            };

            let mut received_key_copy = [0u8; EVENT_KEY_LENGTH];
            received_key_copy.copy_from_slice(account_resource.received_events().key().as_bytes());

            let received_events = LibraEventHandle {
                count: account_resource.received_events().count(),
                key: received_key_copy,
            };

            Ok(LibraAccountResource {
                balance: account_resource.balance(),
                sequence: account_resource.sequence_number(),
                delegated_key_rotation_capability: account_resource
                    .delegated_key_rotation_capability(),
                delegated_withdrawal_capability: account_resource.delegated_withdrawal_capability(),
                sent_events,
                received_events,
                authentication_key,
            })
        }
        Err(e) => {
            update_last_error(format!(
                "Error deserializing account state blob: {}",
                e.to_string()
            ));
            Err(LibraStatus::InvalidArgument)
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn libra_LibraAccountResource_from(
    buf: *const u8,
    len: usize,
    out: *mut LibraAccountResource,
) -> LibraStatus {
    clear_error();
    if buf.is_null() {
        update_last_error("buf parameter must not be null.".to_string());
        return LibraStatus::InvalidArgument;
    }
    let buf: &[u8] = slice::from_raw_parts(buf, len);
    let account_state_blob = AccountStateBlob::from(buf.to_vec());

    match libra_LibraAccountResource_from_safe(account_state_blob) {
        Ok(res) => *out = res,
        Err(err) => return err,
    }
    LibraStatus::Ok
}

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

    /// Generate an AccountBlob and verify we can parse it
    #[test]
    fn test_get_accountresource() {
        use libra_crypto::ed25519::compat;
        use libra_types::{
            account_address::AccountAddress,
            account_config::{AccountResource, ACCOUNT_RESOURCE_PATH},
            byte_array::ByteArray,
            event::{EventHandle, EventKey},
        };
        use std::collections::BTreeMap;

        let keypair = compat::generate_keypair(None);

        // Figure out how to use Libra code to generate AccountStateBlob directly, not involving btreemap directly
        let mut map: BTreeMap<Vec<u8>, Vec<u8>> = BTreeMap::new();
        let addr = AccountAddress::from_public_key(&keypair.1);
        let ar = AccountResource::new(
            987_654_321,
            123_456_789,
            ByteArray::new(addr.to_vec()),
            true,
            false,
            EventHandle::new(EventKey::new_from_address(&addr, 0), 777),
            EventHandle::new(EventKey::new_from_address(&addr, 0), 888),
            0,
        );

        // Fill in data
        map.insert(
            ACCOUNT_RESOURCE_PATH.to_vec(),
            lcs::to_bytes(&ar).expect("Account resource lcs serialization was not successful"),
        );

        let account_state_blob = lcs::to_bytes(&map).expect("LCS serialization failed");

        let mut result = LibraAccountResource::default();
        assert_eq!(LibraStatus::Ok, unsafe {
            libra_LibraAccountResource_from(
                account_state_blob.as_ptr(),
                account_state_blob.len(),
                &mut result,
            )
        });

        assert_eq!(result.balance, ar.balance());
        assert_eq!(result.sequence, ar.sequence_number());
        assert_eq!(
            result.authentication_key,
            ar.authentication_key().as_bytes()
        );
        assert_eq!(
            result.delegated_key_rotation_capability,
            ar.delegated_key_rotation_capability()
        );
        assert_eq!(
            result.delegated_withdrawal_capability,
            ar.delegated_withdrawal_capability()
        );
        assert_eq!(result.sent_events.count, ar.sent_events().count());
        // Array comparision only work to 32
        assert_eq!(
            result.sent_events.key[..32],
            ar.sent_events().key().as_bytes()[..32]
        );
        assert_eq!(
            result.sent_events.key[32..],
            ar.sent_events().key().as_bytes()[32..]
        );
        assert_eq!(result.received_events.count, ar.received_events().count());
        // Array comparision only work to 32
        assert_eq!(
            result.received_events.key[..32],
            ar.received_events().key().as_bytes()[..32]
        );
        assert_eq!(
            result.received_events.key[32..],
            ar.received_events().key().as_bytes()[32..]
        );
    }
}
<commit_msg>fix libra-dev test in new address length<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0
use crate::{
    data::{LibraAccountResource, LibraEventHandle, LibraStatus},
    error::*,
};
use libra_crypto::ed25519::ED25519_PUBLIC_KEY_LENGTH;
use libra_types::{
    account_config::AccountResource, account_state_blob::AccountStateBlob, event::EVENT_KEY_LENGTH,
};
use std::{convert::TryFrom, slice};

pub fn libra_LibraAccountResource_from_safe(
    blob: AccountStateBlob,
) -> Result<LibraAccountResource, LibraStatus> {
    clear_error();
    match AccountResource::try_from(&blob) {
        Ok(account_resource) => {
            let mut authentication_key = [0u8; ED25519_PUBLIC_KEY_LENGTH];
            authentication_key.copy_from_slice(account_resource.authentication_key().as_bytes());

            let mut sent_key_copy = [0u8; EVENT_KEY_LENGTH];
            sent_key_copy.copy_from_slice(account_resource.sent_events().key().as_bytes());

            let sent_events = LibraEventHandle {
                count: account_resource.sent_events().count(),
                key: sent_key_copy,
            };

            let mut received_key_copy = [0u8; EVENT_KEY_LENGTH];
            received_key_copy.copy_from_slice(account_resource.received_events().key().as_bytes());

            let received_events = LibraEventHandle {
                count: account_resource.received_events().count(),
                key: received_key_copy,
            };

            Ok(LibraAccountResource {
                balance: account_resource.balance(),
                sequence: account_resource.sequence_number(),
                delegated_key_rotation_capability: account_resource
                    .delegated_key_rotation_capability(),
                delegated_withdrawal_capability: account_resource.delegated_withdrawal_capability(),
                sent_events,
                received_events,
                authentication_key,
            })
        }
        Err(e) => {
            update_last_error(format!(
                "Error deserializing account state blob: {}",
                e.to_string()
            ));
            Err(LibraStatus::InvalidArgument)
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn libra_LibraAccountResource_from(
    buf: *const u8,
    len: usize,
    out: *mut LibraAccountResource,
) -> LibraStatus {
    clear_error();
    if buf.is_null() {
        update_last_error("buf parameter must not be null.".to_string());
        return LibraStatus::InvalidArgument;
    }
    let buf: &[u8] = slice::from_raw_parts(buf, len);
    let account_state_blob = AccountStateBlob::from(buf.to_vec());

    match libra_LibraAccountResource_from_safe(account_state_blob) {
        Ok(res) => *out = res,
        Err(err) => return err,
    }
    LibraStatus::Ok
}

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

    /// Generate an AccountBlob and verify we can parse it
    #[test]
    fn test_get_accountresource() {
        use libra_crypto::ed25519::compat;
        use libra_types::{
            account_address::AccountAddress,
            account_config::{AccountResource, ACCOUNT_RESOURCE_PATH},
            byte_array::ByteArray,
            event::{EventHandle, EventKey},
        };
        use std::collections::BTreeMap;

        let keypair = compat::generate_keypair(None);

        // Figure out how to use Libra code to generate AccountStateBlob directly, not involving btreemap directly
        let mut map: BTreeMap<Vec<u8>, Vec<u8>> = BTreeMap::new();
        let addr = AccountAddress::from_public_key(&keypair.1);
        let ar = AccountResource::new(
            987_654_321,
            123_456_789,
            ByteArray::new(addr.to_vec()),
            true,
            false,
            EventHandle::new(EventKey::new_from_address(&addr, 0), 777),
            EventHandle::new(EventKey::new_from_address(&addr, 0), 888),
            0,
        );

        // Fill in data
        map.insert(
            ACCOUNT_RESOURCE_PATH.to_vec(),
            lcs::to_bytes(&ar).expect("Account resource lcs serialization was not successful"),
        );

        let account_state_blob = lcs::to_bytes(&map).expect("LCS serialization failed");

        let mut result = LibraAccountResource::default();
        assert_eq!(LibraStatus::Ok, unsafe {
            libra_LibraAccountResource_from(
                account_state_blob.as_ptr(),
                account_state_blob.len(),
                &mut result,
            )
        });

        assert_eq!(result.balance, ar.balance());
        assert_eq!(result.sequence, ar.sequence_number());
        assert_eq!(
            result.authentication_key,
            ar.authentication_key().as_bytes()
        );
        assert_eq!(
            result.delegated_key_rotation_capability,
            ar.delegated_key_rotation_capability()
        );
        assert_eq!(
            result.delegated_withdrawal_capability,
            ar.delegated_withdrawal_capability()
        );
        assert_eq!(result.sent_events.count, ar.sent_events().count());
        assert_eq!(
            EventKey::new(result.sent_events.key),
            *ar.sent_events().key()
        );

        assert_eq!(result.received_events.count, ar.received_events().count());
        assert_eq!(
            EventKey::new(result.received_events.key),
            *ar.received_events().key()
        );
    }
}
<|endoftext|>