<commit_before>//! A simple timer, used to enqueue operations meant to be executed at
//! a given time or after a given delay.

extern crate chrono;

use std::cmp::Ordering;
use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender};
use std::collections::BinaryHeap;

use chrono::{Duration, DateTime, UTC};

/// An item scheduled for delayed execution.
struct Schedule {
    /// The instant at which to execute.
    date: DateTime<UTC>,

    /// The callback to execute.
    cb: Box<Fn() + Send>
}
impl Ord for Schedule {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date).reverse()
    }
}
impl PartialOrd for Schedule {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date).map(|ord| ord.reverse())
    }
}
impl Eq for Schedule {
}
impl PartialEq for Schedule {
    fn eq(&self, other: &Self) -> bool {
        self.date.eq(&other.date)
    }
}

/// An operation to be sent across threads.
enum Op {
    /// Schedule a new item for execution.
    Schedule(Schedule),

    /// Stop the thread.
    Stop
}

/// A mutex-based kind-of-channel used to communicate between the
/// Communication thread and the Scheuler thread.
struct WaiterChannel {
    /// Pending messages.
    messages: Mutex<Vec<Op>>,
    /// A condition variable used for waiting.
    condvar: Condvar,
}
impl WaiterChannel {
    fn with_capacity(cap: usize) -> Self {
        WaiterChannel {
            messages: Mutex::new(Vec::with_capacity(cap)),
            condvar: Condvar::new(),
        }
    }
}

struct Scheduler {
    waiter: Arc<WaiterChannel>,
    heap: BinaryHeap<Schedule>,
}

impl Scheduler {
    fn with_capacity(waiter: Arc<WaiterChannel>, capacity: usize) -> Self {
        Scheduler {
            waiter: waiter,
            heap: BinaryHeap::with_capacity(capacity),
        }
    }
    fn run(&mut self) {
        let ref waiter = *self.waiter;
        loop {
            let mut lock = waiter.messages.lock().unwrap();

            // Pop all messages.
            for msg in lock.drain(..) {
                match msg {
                    Op::Stop => {
                        return;
                    }
                    Op::Schedule(sched) => self.heap.push(sched),
                }
            }

            // Pop all the callbacks that are ready.
            let mut delay = None;
            loop {
                let now = UTC::now();
                if let Some(sched) = self.heap.peek() {
                    if sched.date > now {
                        // First item is not ready yet, so nothing is ready.
                        // We assume that `sched.date > now` is still true.
                        delay = Some(sched.date - now);
                        break;
                    }
                } else {
                    // No item at all.
                    break;
                }
                let sched = self.heap.pop().unwrap(); // We just checked that the heap is not empty.
                (sched.cb)();
            }

            match delay {
                None => {
                    let _ = waiter.condvar.wait(lock);
                },
                Some(delay) => {
                    let sec = delay.num_seconds();
                    let ns = (delay - Duration::seconds(sec)).num_nanoseconds().unwrap(); // This `unwrap()` asserts that the number of ns is not > 1_000_000_000. Since we just substracted the number of seconds, the assertion should always pass.
                    let duration = std::time::Duration::new(sec as u64, ns as u32);
                    let _ = waiter.condvar.wait_timeout(lock, duration);
                }
            }
        }
    }
}

/// A timer, used to schedule execution of callbacks at a later date.
///
/// In the current implementation, each timer is executed as two
/// threads. The _Scheduler_ thread is in charge of maintaining the
/// queue of callbacks to execute and of actually executing them. The
/// _Communication_ thread is in charge of communicating with the
/// _Scheduler_ thread (which requires acquiring a possibly-long-held
/// Mutex) without blocking the caller thread.
pub struct Timer {
    /// Sender used to communicate with the _Communication_ thread. In
    /// turn, this thread will send
    tx: Sender<Op>
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.tx.send(Op::Stop).unwrap();
    }
}

impl Timer {
    /// Create a timer.
    ///
    /// This immediatey launches two threads, which will remain
    /// launched until the timer is dropped. As expected, the threads
    /// spend most of their life waiting for instructions.
    pub fn new() -> Self {
        Self::with_capacity(32)
    }

    /// As `new()`, but with a manually specified initial capaicty.
    pub fn with_capacity(capacity: usize) -> Self {
        let waiter_send = Arc::new(WaiterChannel::with_capacity(capacity));
        let waiter_recv = waiter_send.clone();

        // Spawn a first thread, whose sole role is to dispatch
        // messages to the second thread without having to wait too
        // long for the mutex.
        let (tx, rx) = channel();
        thread::spawn(move || {
            use Op::*;
            let ref waiter = *waiter_send;
            for msg in rx.iter() {
                let mut vec = waiter.messages.lock().unwrap();
                match msg {
                    Schedule(sched) => {
                        vec.push(Schedule(sched));
                        waiter.condvar.notify_one();
                    }
                    Stop => {
                        vec.clear();
                        vec.push(Op::Stop);
                        waiter.condvar.notify_one();
                        return;
                    }
                }
            }
        });

        // Spawn a second thread, in charge of scheduling.
        thread::Builder::new().name("Timer thread".to_owned()).spawn(move || {
            let mut scheduler = Scheduler::with_capacity(waiter_recv, capacity);
            scheduler.run()
        }).unwrap();
        Timer {
            tx: tx
        }
    }

    /// Schedule a callback for execution after a delay.
    ///
    /// Callbacks are guaranteed to never be called before the
    /// delay. However, it is possible that they will be called a
    /// little after the delay.
    ///
    /// If the delay is negative, the callback is executed as soon as
    /// possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate timer;
    /// extern crate chrono;
    /// use std::sync::mpsc::channel;
    ///
    /// let timer = timer::Timer::new();
    /// let (tx, rx) = channel();
    ///
    /// timer.schedule_with_delay(chrono::Duration::seconds(3), move || {
    ///   // This closure is executed on the scheduler thread,
    ///   // so we want to move it away asap.
    ///
    ///   let _ignored = tx.send(()); // Avoid unwrapping here.
    /// });
    ///
    /// rx.recv().unwrap();
    /// println!("This code has been executed after 3 seconds");
    /// ```
    pub fn schedule_with_delay<F>(&self, delay: Duration, cb: F)
        where F: 'static + Fn() + Send {
        self.schedule_with_date(UTC::now() + delay, cb)
    }

    /// Schedule a callback for execution at a given date.
    ///
    /// Callbacks are guaranteed to never be called before their
    /// date. However, it is possible that they will be called a
    /// little after it.
    ///
    /// If the date is in the past, the callback is executed as soon
    /// as possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    pub fn schedule_with_date<F>(&self, date: DateTime<UTC>, cb: F)
        where F: 'static + Fn() + Send {
        self.tx.send(Op::Schedule(Schedule {
            date: date,
            cb: Box::new(cb)
        })).unwrap();
    }
}

#[test]
fn test_schedule_with_delay() {
    let timer = Timer::new();
    let (tx, rx) = channel();

    // Schedule a number of callbacks in an arbitrary order, make sure
    // that they are executed in the right order.
    let mut delays = vec![1, 5, 3, -1];
    let start = UTC::now();
    for i in delays.clone() {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    delays.sort();
    for (i, msg) in (0..delays.len()).zip(rx.iter()) {
        let elapsed = (UTC::now() - start).num_seconds();
        println!("Received message {} after {} seconds", msg, elapsed);
        assert_eq!(msg, delays[i]);
        assert!(delays[i] <= elapsed && elapsed <= delays[i] + 3, "We have waited {} seconds, expecting [{}, {}]", elapsed, delays[i], delays[i] + 3);
    }

    // Now make sure that callbacks that are designed to be executed
    // immediately are executed quickly.
    let start = UTC::now();
    for i in vec![10, 0] {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    assert_eq!(rx.recv().unwrap(), 0);
    assert!(UTC::now() - start <= Duration::seconds(1));
}

#[test]
fn test_schedule_and_panic() {
    let timer = Timer::new();
    for i in 0..1000 {
        let (tx, rx) = channel();
        timer.schedule_with_delay(Duration::milliseconds(i), move || {
            println!("Received callback {}, preparing to panic", i);
            if true {
                panic!("Testing the behavior in presence of a panic");
            } else {
                tx.send(()).unwrap();
            }
        });
        assert!(rx.try_recv().is_err());
    }

    let (tx, rx) = channel();
    timer.schedule_with_delay(Duration::seconds(1), move || {
        println!("Received final callback, don't panic");
        tx.send(()).unwrap();
    });
    rx.try_recv().unwrap();
}
<commit_msg>Removed bogus test<commit_after>//! A simple timer, used to enqueue operations meant to be executed at
//! a given time or after a given delay.

extern crate chrono;

use std::cmp::Ordering;
use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender};
use std::collections::BinaryHeap;

use chrono::{Duration, DateTime, UTC};

/// An item scheduled for delayed execution.
struct Schedule {
    /// The instant at which to execute.
    date: DateTime<UTC>,

    /// The callback to execute.
    cb: Box<Fn() + Send>
}
impl Ord for Schedule {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date).reverse()
    }
}
impl PartialOrd for Schedule {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date).map(|ord| ord.reverse())
    }
}
impl Eq for Schedule {
}
impl PartialEq for Schedule {
    fn eq(&self, other: &Self) -> bool {
        self.date.eq(&other.date)
    }
}

/// An operation to be sent across threads.
enum Op {
    /// Schedule a new item for execution.
    Schedule(Schedule),

    /// Stop the thread.
    Stop
}

/// A mutex-based kind-of-channel used to communicate between the
/// Communication thread and the Scheuler thread.
struct WaiterChannel {
    /// Pending messages.
    messages: Mutex<Vec<Op>>,
    /// A condition variable used for waiting.
    condvar: Condvar,
}
impl WaiterChannel {
    fn with_capacity(cap: usize) -> Self {
        WaiterChannel {
            messages: Mutex::new(Vec::with_capacity(cap)),
            condvar: Condvar::new(),
        }
    }
}

struct Scheduler {
    waiter: Arc<WaiterChannel>,
    heap: BinaryHeap<Schedule>,
}

impl Scheduler {
    fn with_capacity(waiter: Arc<WaiterChannel>, capacity: usize) -> Self {
        Scheduler {
            waiter: waiter,
            heap: BinaryHeap::with_capacity(capacity),
        }
    }
    fn run(&mut self) {
        let ref waiter = *self.waiter;
        loop {
            let mut lock = waiter.messages.lock().unwrap();

            // Pop all messages.
            for msg in lock.drain(..) {
                match msg {
                    Op::Stop => {
                        return;
                    }
                    Op::Schedule(sched) => self.heap.push(sched),
                }
            }

            // Pop all the callbacks that are ready.
            let mut delay = None;
            loop {
                let now = UTC::now();
                if let Some(sched) = self.heap.peek() {
                    if sched.date > now {
                        // First item is not ready yet, so nothing is ready.
                        // We assume that `sched.date > now` is still true.
                        delay = Some(sched.date - now);
                        break;
                    }
                } else {
                    // No item at all.
                    break;
                }
                let sched = self.heap.pop().unwrap(); // We just checked that the heap is not empty.
                (sched.cb)();
            }

            match delay {
                None => {
                    let _ = waiter.condvar.wait(lock);
                },
                Some(delay) => {
                    let sec = delay.num_seconds();
                    let ns = (delay - Duration::seconds(sec)).num_nanoseconds().unwrap(); // This `unwrap()` asserts that the number of ns is not > 1_000_000_000. Since we just substracted the number of seconds, the assertion should always pass.
                    let duration = std::time::Duration::new(sec as u64, ns as u32);
                    let _ = waiter.condvar.wait_timeout(lock, duration);
                }
            }
        }
    }
}

/// A timer, used to schedule execution of callbacks at a later date.
///
/// In the current implementation, each timer is executed as two
/// threads. The _Scheduler_ thread is in charge of maintaining the
/// queue of callbacks to execute and of actually executing them. The
/// _Communication_ thread is in charge of communicating with the
/// _Scheduler_ thread (which requires acquiring a possibly-long-held
/// Mutex) without blocking the caller thread.
pub struct Timer {
    /// Sender used to communicate with the _Communication_ thread. In
    /// turn, this thread will send
    tx: Sender<Op>
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.tx.send(Op::Stop).unwrap();
    }
}

impl Timer {
    /// Create a timer.
    ///
    /// This immediatey launches two threads, which will remain
    /// launched until the timer is dropped. As expected, the threads
    /// spend most of their life waiting for instructions.
    pub fn new() -> Self {
        Self::with_capacity(32)
    }

    /// As `new()`, but with a manually specified initial capaicty.
    pub fn with_capacity(capacity: usize) -> Self {
        let waiter_send = Arc::new(WaiterChannel::with_capacity(capacity));
        let waiter_recv = waiter_send.clone();

        // Spawn a first thread, whose sole role is to dispatch
        // messages to the second thread without having to wait too
        // long for the mutex.
        let (tx, rx) = channel();
        thread::spawn(move || {
            use Op::*;
            let ref waiter = *waiter_send;
            for msg in rx.iter() {
                let mut vec = waiter.messages.lock().unwrap();
                match msg {
                    Schedule(sched) => {
                        vec.push(Schedule(sched));
                        waiter.condvar.notify_one();
                    }
                    Stop => {
                        vec.clear();
                        vec.push(Op::Stop);
                        waiter.condvar.notify_one();
                        return;
                    }
                }
            }
        });

        // Spawn a second thread, in charge of scheduling.
        thread::Builder::new().name("Timer thread".to_owned()).spawn(move || {
            let mut scheduler = Scheduler::with_capacity(waiter_recv, capacity);
            scheduler.run()
        }).unwrap();
        Timer {
            tx: tx
        }
    }

    /// Schedule a callback for execution after a delay.
    ///
    /// Callbacks are guaranteed to never be called before the
    /// delay. However, it is possible that they will be called a
    /// little after the delay.
    ///
    /// If the delay is negative, the callback is executed as soon as
    /// possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate timer;
    /// extern crate chrono;
    /// use std::sync::mpsc::channel;
    ///
    /// let timer = timer::Timer::new();
    /// let (tx, rx) = channel();
    ///
    /// timer.schedule_with_delay(chrono::Duration::seconds(3), move || {
    ///   // This closure is executed on the scheduler thread,
    ///   // so we want to move it away asap.
    ///
    ///   let _ignored = tx.send(()); // Avoid unwrapping here.
    /// });
    ///
    /// rx.recv().unwrap();
    /// println!("This code has been executed after 3 seconds");
    /// ```
    pub fn schedule_with_delay<F>(&self, delay: Duration, cb: F)
        where F: 'static + Fn() + Send {
        self.schedule_with_date(UTC::now() + delay, cb)
    }

    /// Schedule a callback for execution at a given date.
    ///
    /// Callbacks are guaranteed to never be called before their
    /// date. However, it is possible that they will be called a
    /// little after it.
    ///
    /// If the date is in the past, the callback is executed as soon
    /// as possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    pub fn schedule_with_date<F>(&self, date: DateTime<UTC>, cb: F)
        where F: 'static + Fn() + Send {
        self.tx.send(Op::Schedule(Schedule {
            date: date,
            cb: Box::new(cb)
        })).unwrap();
    }
}

#[test]
fn test_schedule_with_delay() {
    let timer = Timer::new();
    let (tx, rx) = channel();

    // Schedule a number of callbacks in an arbitrary order, make sure
    // that they are executed in the right order.
    let mut delays = vec![1, 5, 3, -1];
    let start = UTC::now();
    for i in delays.clone() {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    delays.sort();
    for (i, msg) in (0..delays.len()).zip(rx.iter()) {
        let elapsed = (UTC::now() - start).num_seconds();
        println!("Received message {} after {} seconds", msg, elapsed);
        assert_eq!(msg, delays[i]);
        assert!(delays[i] <= elapsed && elapsed <= delays[i] + 3, "We have waited {} seconds, expecting [{}, {}]", elapsed, delays[i], delays[i] + 3);
    }

    // Now make sure that callbacks that are designed to be executed
    // immediately are executed quickly.
    let start = UTC::now();
    for i in vec![10, 0] {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    assert_eq!(rx.recv().unwrap(), 0);
    assert!(UTC::now() - start <= Duration::seconds(1));
}
<|endoftext|>


<commit_before>//! Stochastic processes.

#[cfg(test)]
extern crate assert;

extern crate complex;
extern crate czt;
extern crate probability;

pub mod gaussian;

/// A stochastic process.
pub trait Process {
    /// The index set.
    type Index;

    /// The state space.
    type State;

    /// Sample paths.
    type Path: Path<Self::State>;

    /// Compute the covariance function.
    fn cov(&self, Self::Index, Self::Index) -> f64;
}

/// A sample path of a stochastic process.
pub trait Path<T>: Iterator<Item=T> {
}

/// A stationary process.
pub trait Stationary {
    /// The index set.
    type Index;

    /// Compute the covariance functino.
    fn cov(&self, Self::Index) -> f64;
}
<commit_msg>Fix a typo<commit_after>//! Stochastic processes.

#[cfg(test)]
extern crate assert;

extern crate complex;
extern crate czt;
extern crate probability;

pub mod gaussian;

/// A stochastic process.
pub trait Process {
    /// The index set.
    type Index;

    /// The state space.
    type State;

    /// Sample paths.
    type Path: Path<Self::State>;

    /// Compute the covariance function.
    fn cov(&self, Self::Index, Self::Index) -> f64;
}

/// A sample path of a stochastic process.
pub trait Path<T>: Iterator<Item=T> {
}

/// A stationary process.
pub trait Stationary {
    /// The index set.
    type Index;

    /// Compute the covariance function.
    fn cov(&self, Self::Index) -> f64;
}
<|endoftext|>


<commit_before>//! This crate contains utilities to work with Fractal Global Credits. It contains the wallet
//! address representation and the currency amount type. Each of them is explained in its own
//! documentation and can be easily used by third parties.
//!
//! Using it is as simple as including this in the crate:
//!
//! ```
//! extern crate fractal_utils;
//! ```
#![forbid(missing_docs, warnings)]
#![deny(deprecated, improper_ctypes, non_shorthand_field_patterns, overflowing_literals,
    plugin_as_library, private_no_mangle_fns, private_no_mangle_statics, stable_features,
    unconditional_recursion, unknown_lints, unused, unused_allocation, unused_attributes,
    unused_comparisons, unused_features, unused_parens, while_true)]
#![warn(trivial_casts, trivial_numeric_casts, unused, unused_extern_crates, unused_import_braces,
    unused_qualifications, unused_results, variant_size_differences)]

extern crate rustc_serialize;
extern crate rust_base58;

pub mod amount;
pub mod wallet_address;
pub mod location;
pub mod relations;

pub use amount::Amount;
pub use wallet_address::{WALLET_ADDRESS_LEN, WalletAddress};
pub use location::Address;
pub use relations::{Relationship, get_relationship_id, get_relationship};
/// The symbol of Fractal Global Credits
///
/// This symbol, `Ͼ` should be used whenever an amount of currency has to be represented. It is an
/// upside-down amperstand symbol, the Unicode *U+03FE* character. It can easily be used when
/// formatting currencies:
///
/// ```
/// use fractal_utils::{CURRENCY_SYMBOL, Amount};
/// # assert_eq!(CURRENCY_SYMBOL, 'Ͼ');
/// # assert_eq!(CURRENCY_SYMBOL, '\u{03FE}');
/// let amount = Amount::from_repr(30_000); // 30.000
/// assert_eq!(format!("{} {}", CURRENCY_SYMBOL, amount), "Ͼ 30");
/// ```
pub const CURRENCY_SYMBOL: char = 'Ͼ';
<commit_msg>Fixed description<commit_after>//! This crate contains utilities to work with Fractal Global Credits. It contains the wallet
//! address representation and the currency amount type. Each of them is explained in its own
//! documentation and can be easily used by third parties.
//!
//! Using it is as simple as including this in the crate:
//!
//! ```
//! extern crate fractal_utils;
//! ```
#![forbid(missing_docs, warnings)]
#![deny(deprecated, improper_ctypes, non_shorthand_field_patterns, overflowing_literals,
    plugin_as_library, private_no_mangle_fns, private_no_mangle_statics, stable_features,
    unconditional_recursion, unknown_lints, unused, unused_allocation, unused_attributes,
    unused_comparisons, unused_features, unused_parens, while_true)]
#![warn(trivial_casts, trivial_numeric_casts, unused, unused_extern_crates, unused_import_braces,
    unused_qualifications, unused_results, variant_size_differences)]

extern crate rustc_serialize;
extern crate rust_base58;

pub mod amount;
pub mod wallet_address;
pub mod location;
pub mod relations;

pub use amount::Amount;
pub use wallet_address::{WALLET_ADDRESS_LEN, WalletAddress};
pub use location::Address;
pub use relations::{Relationship, get_relationship_id, get_relationship};
/// The symbol of Fractal Global Credits
///
/// This symbol, `Ͼ` should be used whenever an amount of currency has to be represented. It is a
/// dotted lumate sigma symbol, the Unicode *U+03FE* character. It can easily be used when
/// formatting currencies:
///
/// ```
/// use fractal_utils::{CURRENCY_SYMBOL, Amount};
/// # assert_eq!(CURRENCY_SYMBOL, 'Ͼ');
/// # assert_eq!(CURRENCY_SYMBOL, '\u{03FE}');
/// let amount = Amount::from_repr(30_000); // 30.000
/// assert_eq!(format!("{} {}", CURRENCY_SYMBOL, amount), "Ͼ 30");
/// ```
pub const CURRENCY_SYMBOL: char = 'Ͼ';
<|endoftext|>


<commit_before>#![crate_name = "rusoto"]
#![crate_type = "lib"]
#![allow(dead_code)]

//! # Rusoto
//!
//! Rusoto is an SDK for [Amazon Web Services](http://aws.amazon.com/).  It follows best practices
//! for [AWS Credentials](https://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs).
//!
//! The library is designed with use on AWS EC2 instances in mind but can be used as an
//! [AWS CLI](https://aws.amazon.com/cli/) replacement.
//!
//! ## Credentials
//!
//! Credentials are sourced from environment variables, AWS credentials file and IAM instance profiles,
//! in that order.  IAM instance profile credentials are refreshed automatically as needed.
//!
//! ## Supported services
//!
//! * SQS
//! * S3 (partial implementation)
//!
//! ## Requests and request signing
//!
//! Rusoto uses [AWS Signature 4](http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)
//! to sign requests.

extern crate time;
extern crate xml;
extern crate hyper;
extern crate openssl;
extern crate url;
extern crate rustc_serialize as serialize;
extern crate regex;
extern crate crypto;

#[macro_use] pub mod params;
#[macro_use] pub mod signature;
pub mod credentials;
pub mod error;
pub mod sqs;
pub mod s3;
pub mod xmlutil;
pub mod regions;
pub mod request;
<commit_msg>Rewords rustdoc for top level page.<commit_after>#![crate_name = "rusoto"]
#![crate_type = "lib"]
#![allow(dead_code)]

//! # Rusoto
//!
//! Rusoto is a Rust SDK for [Amazon Web Services](http://aws.amazon.com/).  It follows best practices
//! for [AWS Credentials](https://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs).
//!
//! The library interacts with AWS in the same fashion as Python's [boto3](https://github.com/boto/boto3) SDK.
//!
//! ## Credentials
//!
//! Credentials are sourced from environment variables, AWS credentials file and IAM instance profiles,
//! in that order.  IAM instance profile credentials are refreshed automatically as needed.
//!
//! ## Supported services
//!
//! * SQS
//! * S3 (partial implementation)
//!
//! ## Requests and request signing
//!
//! Rusoto uses [AWS Signature 4](http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)
//! to sign requests.

extern crate time;
extern crate xml;
extern crate hyper;
extern crate openssl;
extern crate url;
extern crate rustc_serialize as serialize;
extern crate regex;
extern crate crypto;

#[macro_use] pub mod params;
#[macro_use] pub mod signature;
pub mod credentials;
pub mod error;
pub mod sqs;
pub mod s3;
pub mod xmlutil;
pub mod regions;
pub mod request;
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;

use std::io;
use std::io::{Write, Read, Error, ErrorKind};
use nix::errno::Errno;
use nix::Error::Sys;
use nix::sys::termios;
use nix::sys::termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, ECHO, ICANON, IEXTEN, ISIG, VMIN, VTIME};

static MAX_LINE: i32 = 4096;
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb","cons25","emacs"];

const    NULL     : u8   = 0;     // NULL
const    CTRLA    : u8   = 1;     // C-a
const    CTRLB    : u8   = 2;     // C-b
const    CTRLC    : u8   = 3;     // C-c
const    CTRLD    : u8   = 4;     // C-d
const    CTRLE    : u8   = 5;     // C-e
const    CTRLF    : u8   = 6;     // C-f
const    CTRLH    : u8   = 8;     // C-h
const    TAB      : u8   = 9;     // Tab
const    CTRLK    : u8   = 11;    // C-k
const    CTRLL    : u8   = 12;    // C-l
const    ENTER    : u8   = 13;    // Enter
const    CTRLN    : u8   = 14;    // C-n
const    CTRLP    : u8   = 16;    // C-p
const    CTRLT    : u8   = 20;    // C-t
const    CTRLU    : u8   = 21;    // C-u
const    CTRLW    : u8   = 23;    // C-w
const    ESC      : u8   = 27;    // Esc
const    BACKSPACE: u8   = 127;   // Backspace

fn is_a_tty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

fn is_unsupported_term() -> bool {
    let term = std::env::var("TERM").ok().unwrap();
    let mut unsupported = false;
    for iter in &UNSUPPORTED_TERM {
        unsupported = term == *iter
    }
    unsupported
}

fn enable_raw_mode() -> Result<termios::Termios, nix::Error> {
    if !is_a_tty() {
        Err(Sys(Errno::ENOTTY))
    } else {
        let original_term = try!(termios::tcgetattr(libc::STDIN_FILENO));
        let mut raw = original_term;
        raw.c_iflag = raw.c_iflag   & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        raw.c_oflag = raw.c_oflag   & !(OPOST);
        raw.c_cflag = raw.c_cflag   | (CS8);
        raw.c_lflag = raw.c_lflag   & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1;
        raw.c_cc[VTIME] = 0;
        try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &raw));
        Ok(original_term)
    }
}

fn disable_raw_mode(original_termios: termios::Termios) -> Result<(), nix::Error> {
    try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &original_termios));
    Ok(())
}

fn readline_edit() -> Result<String, io::Error> {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];
    loop {
        let numread = io::stdin().read(&mut input).unwrap();
        match input[0] {
            ENTER  => break,
            _      => { print!("{}", input[0]); io::stdout().flush(); }
        }
        buffer.push(input[0]);
    }
    Ok(String::from_utf8(buffer).unwrap())
}

fn readline_raw() -> Result<String, io::Error> {
    if is_a_tty() {
        let original_termios = match enable_raw_mode() {
            Err(Sys(Errno::ENOTTY)) => return Err(Error::new(ErrorKind::Other, "Not a TTY")),
            Err(Sys(Errno::EBADF))  => return Err(Error::new(ErrorKind::Other, "Not a file descriptor")),
            Err(..)                 => return Err(Error::new(ErrorKind::Other, "Unknown Error")),
            Ok(term)                => term
        };

        let user_input = readline_edit();

        match disable_raw_mode(original_termios) {
            Err(..) => return Err(Error::new(ErrorKind::Other, "Failed to revert to original termios")),
            Ok(..)  => ()
        }

        user_input
    } else {

        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    }
}

pub fn readline(prompt: &'static str) -> Result<String, io::Error> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    try!(stdout.write(prompt.as_bytes()));
    try!(stdout.flush());

    if is_unsupported_term() {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    } else {
        readline_raw()
    }
}
<commit_msg>Added CONST values for Keypress<commit_after>extern crate libc;
extern crate nix;

use std::io;
use std::io::{Write, Read, Error, ErrorKind};
use nix::errno::Errno;
use nix::Error::Sys;
use nix::sys::termios;
use nix::sys::termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, ECHO, ICANON, IEXTEN, ISIG, VMIN, VTIME};

static MAX_LINE: u32 = 4096;
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb","cons25","emacs"];

const    NULL     : u8   = 0;     // NULL
const    CTRL_A    : u8   = 1;     // C-a
const    CTRL_B    : u8   = 2;     // C-b
const    CTRL_C    : u8   = 3;     // C-c
const    CTRL_D    : u8   = 4;     // C-d
const    CTRL_E    : u8   = 5;     // C-e
const    CTRL_F    : u8   = 6;     // C-f
const    CTRL_H    : u8   = 8;     // C-h
const    TAB      : u8   = 9;     // Tab
const    CTRL_K    : u8   = 11;    // C-k
const    CTRL_L    : u8   = 12;    // C-l
const    ENTER    : u8   = 13;    // Enter
const    CTRL_N    : u8   = 14;    // C-n
const    CTRL_P    : u8   = 16;    // C-p
const    CTRL_T    : u8   = 20;    // C-t
const    CTRL_U    : u8   = 21;    // C-u
const    CTRL_W    : u8   = 23;    // C-w
const    ESC      : u8   = 27;    // Esc
const    BACKSPACE: u8   = 127;   // Backspace

fn is_a_tty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

fn is_unsupported_term() -> bool {
    let term = std::env::var("TERM").ok().unwrap();
    let mut unsupported = false;
    for iter in &UNSUPPORTED_TERM {
        unsupported = term == *iter
    }
    unsupported
}

fn enable_raw_mode() -> Result<termios::Termios, nix::Error> {
    if !is_a_tty() {
        Err(Sys(Errno::ENOTTY))
    } else {
        let original_term = try!(termios::tcgetattr(libc::STDIN_FILENO));
        let mut raw = original_term;
        raw.c_iflag = raw.c_iflag   & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        raw.c_oflag = raw.c_oflag   & !(OPOST);
        raw.c_cflag = raw.c_cflag   | (CS8);
        raw.c_lflag = raw.c_lflag   & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1;
        raw.c_cc[VTIME] = 0;
        try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &raw));
        Ok(original_term)
    }
}

fn disable_raw_mode(original_termios: termios::Termios) -> Result<(), nix::Error> {
    try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &original_termios));
    Ok(())
}

fn readline_edit() -> Result<String, io::Error> {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];
    loop {
        let numread = io::stdin().read(&mut input).unwrap();
        match input[0] {
            CTRL_A => print!("Pressed C-a"),
            CTRL_B => print!("Pressed C-b"),
            CTRL_C => print!("Pressed C-c"),
            CTRL_D => print!("Pressed C-d"),
            CTRL_E => print!("Pressed C-e"),
            CTRL_F => print!("Pressed C-f"),
            CTRL_H => print!("Pressed C-h"),
            CTRL_K => print!("Pressed C-k"),
            CTRL_L => print!("Pressed C-l"),
            CTRL_N => print!("Pressed C-n"),
            CTRL_P => print!("Pressed C-p"),
            CTRL_T => print!("Pressed C-t"),
            CTRL_U => print!("Pressed C-u"),
            CTRL_W => print!("Pressed C-w"),
            ESC    => print!("Pressed esc") ,
            ENTER  => break,
            _      => { print!("{}", input[0]); io::stdout().flush(); }
        }
        buffer.push(input[0]);
    }
    Ok(String::from_utf8(buffer).unwrap())
}

fn readline_raw() -> Result<String, io::Error> {
    if is_a_tty() {
        let original_termios = match enable_raw_mode() {
            Err(Sys(Errno::ENOTTY)) => return Err(Error::new(ErrorKind::Other, "Not a TTY")),
            Err(Sys(Errno::EBADF))  => return Err(Error::new(ErrorKind::Other, "Not a file descriptor")),
            Err(..)                 => return Err(Error::new(ErrorKind::Other, "Unknown Error")),
            Ok(term)                => term
        };

        let user_input = readline_edit();

        match disable_raw_mode(original_termios) {
            Err(..) => return Err(Error::new(ErrorKind::Other, "Failed to revert to original termios")),
            Ok(..)  => ()
        }

        user_input
    } else {

        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    }
}

pub fn readline(prompt: &'static str) -> Result<String, io::Error> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    try!(stdout.write(prompt.as_bytes()));
    try!(stdout.flush());

    if is_unsupported_term() {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    } else {
        readline_raw()
    }
}
<|endoftext|>


<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! Default options:
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("disk.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```
//!
//! Custom options:
//!
//! ```rust
//! # use loopdev::LoopControl;
//! # let lc = LoopControl::open().unwrap();
//! # let ld = lc.next_free().unwrap();
//! #
//! ld.with()
//!     .part_scan(true)
//!     .offset(512 * 1024 * 1024) // 512 MiB
//!     .size_limit(1024 * 1024 * 1024) // 1GiB
//!     .attach("disk.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use bindings::{
    loop_info64, LOOP_CLR_FD, LOOP_CTL_GET_FREE, LOOP_SET_CAPACITY, LOOP_SET_DIRECT_IO,
    LOOP_SET_FD, LOOP_SET_STATUS64, LO_FLAGS_AUTOCLEAR, LO_FLAGS_READ_ONLY,
};
use libc::{c_int, ioctl};
use std::{
    default::Default,
    fs::{File, OpenOptions},
    io,
    os::unix::prelude::*,
    path::{Path, PathBuf},
};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(non_snake_case)]
mod bindings {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(not(target_os = "android"))]
type IoctlRequest = libc::c_ulong;
#[cfg(target_os = "android")]
type IoctlRequest = libc::c_int;

const LOOP_CONTROL: &str = "/dev/loop-control";
#[cfg(not(target_os = "android"))]
const LOOP_PREFIX: &str = "/dev/loop";
#[cfg(target_os = "android")]
const LOOP_PREFIX: &str = "/dev/block/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(
                self.dev_file.as_raw_fd() as c_int,
                LOOP_CTL_GET_FREE as IoctlRequest,
            )
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

impl AsRawFd for LoopControl {
    fn as_raw_fd(&self) -> RawFd {
        self.dev_file.as_raw_fd()
    }
}

impl IntoRawFd for LoopControl {
    fn into_raw_fd(self) -> RawFd {
        self.dev_file.into_raw_fd()
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl IntoRawFd for LoopDevice {
    fn into_raw_fd(self) -> RawFd {
        self.device.into_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file with given options.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let mut ld = LoopDevice::open("/dev/loop3").unwrap();
    /// ld.with().part_scan(true).attach("disk.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn with(&mut self) -> AttachOptions<'_> {
        AttachOptions {
            device: self,
            info: Default::default(),
            direct_io: false,
        }
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("disk.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        let info = loop_info64 {
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.2",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    #[deprecated(
        since = "0.2.2",
        note = "use `with().size_limit(size).attach(file)` instead"
    )]
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        size_limit: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            lo_sizelimit: size_limit,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file with loop_info64.
    fn attach_with_loop_info(
        &self, // TODO should be mut? - but changing it is a breaking change
        backing_file: impl AsRef<Path>,
        info: loop_info64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;
        self.attach_fd_with_loop_info(bf, info)
    }

    /// Attach the loop device to a fd with loop_info.
    fn attach_fd_with_loop_info(&self, bf: impl AsRawFd, info: loop_info64) -> io::Result<()> {
        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD as IoctlRequest,
                bf.as_raw_fd() as c_int,
            )
        })?;

        let result = unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64 as IoctlRequest,
                &info,
            )
        };
        match ioctl_to_error(result) {
            Err(err) => {
                // Ignore the error to preserve the original error
                let _ = self.detach();
                Err(err)
            }
            Ok(_) => Ok(()),
        }
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Get the device major number
    pub fn major(&self) -> io::Result<u32> {
        self.device
            .metadata()
            .map(|m| unsafe { libc::major(m.rdev()) as u32 })
    }

    /// Get the device major number
    pub fn minor(&self) -> io::Result<u32> {
        self.device
            .metadata()
            .map(|m| unsafe { libc::minor(m.rdev()) as u32 })
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// # ld.attach_file("disk.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_CLR_FD as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }

    // Enable or disable direct I/O for the backing file.
    pub fn set_direct_io(&self, direct_io: bool) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_DIRECT_IO as IoctlRequest,
                if direct_io { 1 } else { 0 },
            )
        })?;
        Ok(())
    }
}

/// Used to set options when attaching a device. Created with [LoopDevice::with()].
///
/// # Examples
///
/// Enable partition scanning on attach:
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop6").unwrap();
/// ld.with()
///     .part_scan(true)
///     .attach("disk.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
///
/// A 1MiB slice of the file located at 1KiB into the file.
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop7").unwrap();
/// ld.with()
///     .offset(1024*1024)
///     .size_limit(1024*1024*1024)
///     .attach("test.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
pub struct AttachOptions<'d> {
    device: &'d mut LoopDevice,
    info: loop_info64,
    direct_io: bool,
}

impl AttachOptions<'_> {
    /// Offset in bytes from the start of the backing file the data will start at.
    pub fn offset(mut self, offset: u64) -> Self {
        self.info.lo_offset = offset;
        self
    }

    /// Maximum size of the data in bytes.
    pub fn size_limit(mut self, size_limit: u64) -> Self {
        self.info.lo_sizelimit = size_limit;
        self
    }

    /// Set read only flag
    pub fn read_only(mut self, read_only: bool) -> Self {
        if read_only {
            self.info.lo_flags |= LO_FLAGS_READ_ONLY;
        } else {
            self.info.lo_flags &= !LO_FLAGS_READ_ONLY;
        }
        self
    }

    /// Set autoclear flag
    pub fn autoclear(mut self, read_only: bool) -> Self {
        if read_only {
            self.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
        } else {
            self.info.lo_flags &= !LO_FLAGS_AUTOCLEAR;
        }
        self
    }

    // Enable or disable direct I/O for the backing file.
    pub fn set_direct_io(mut self, direct_io: bool) -> Self {
        self.direct_io = direct_io;
        self
    }

    /// Force the kernel to scan the partition table on a newly created loop device. Note that the
    /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
    pub fn part_scan(mut self, enable: bool) -> Self {
        if enable {
            self.info.lo_flags |= 1 << 4;
        } else {
            self.info.lo_flags &= u32::max_value() - (1 << 4);
        }
        self
    }

    /// Attach the loop device to a file with the set options.
    pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
        self.device.attach_with_loop_info(backing_file, self.info)?;
        if self.direct_io {
            self.device.set_direct_io(self.direct_io)?;
        }
        Ok(())
    }

    /// Attach the loop device to an fd
    pub fn attach_fd(self, backing_file_fd: impl AsRawFd) -> io::Result<()> {
        self.device
            .attach_fd_with_loop_info(backing_file_fd, self.info)?;
        if self.direct_io {
            self.device.set_direct_io(self.direct_io)?;
        }
        Ok(())
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<commit_msg>Remove mut from with and AttachOptions to make it consistant with the other methods<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! Default options:
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("disk.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```
//!
//! Custom options:
//!
//! ```rust
//! # use loopdev::LoopControl;
//! # let lc = LoopControl::open().unwrap();
//! # let ld = lc.next_free().unwrap();
//! #
//! ld.with()
//!     .part_scan(true)
//!     .offset(512 * 1024 * 1024) // 512 MiB
//!     .size_limit(1024 * 1024 * 1024) // 1GiB
//!     .attach("disk.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use bindings::{
    loop_info64, LOOP_CLR_FD, LOOP_CTL_GET_FREE, LOOP_SET_CAPACITY, LOOP_SET_DIRECT_IO,
    LOOP_SET_FD, LOOP_SET_STATUS64, LO_FLAGS_AUTOCLEAR, LO_FLAGS_READ_ONLY,
};
use libc::{c_int, ioctl};
use std::{
    default::Default,
    fs::{File, OpenOptions},
    io,
    os::unix::prelude::*,
    path::{Path, PathBuf},
};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(non_snake_case)]
mod bindings {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(not(target_os = "android"))]
type IoctlRequest = libc::c_ulong;
#[cfg(target_os = "android")]
type IoctlRequest = libc::c_int;

const LOOP_CONTROL: &str = "/dev/loop-control";
#[cfg(not(target_os = "android"))]
const LOOP_PREFIX: &str = "/dev/loop";
#[cfg(target_os = "android")]
const LOOP_PREFIX: &str = "/dev/block/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(
                self.dev_file.as_raw_fd() as c_int,
                LOOP_CTL_GET_FREE as IoctlRequest,
            )
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

impl AsRawFd for LoopControl {
    fn as_raw_fd(&self) -> RawFd {
        self.dev_file.as_raw_fd()
    }
}

impl IntoRawFd for LoopControl {
    fn into_raw_fd(self) -> RawFd {
        self.dev_file.into_raw_fd()
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl IntoRawFd for LoopDevice {
    fn into_raw_fd(self) -> RawFd {
        self.device.into_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file with given options.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let mut ld = LoopDevice::open("/dev/loop3").unwrap();
    /// ld.with().part_scan(true).attach("disk.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn with(&self) -> AttachOptions<'_> {
        AttachOptions {
            device: self,
            info: Default::default(),
            direct_io: false,
        }
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("disk.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        let info = loop_info64 {
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.2",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    #[deprecated(
        since = "0.2.2",
        note = "use `with().size_limit(size).attach(file)` instead"
    )]
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        size_limit: u64,
    ) -> io::Result<()> {
        let info = loop_info64 {
            lo_offset: offset,
            lo_sizelimit: size_limit,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file with loop_info64.
    fn attach_with_loop_info(
        &self, // TODO should be mut? - but changing it is a breaking change
        backing_file: impl AsRef<Path>,
        info: loop_info64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;
        self.attach_fd_with_loop_info(bf, info)
    }

    /// Attach the loop device to a fd with loop_info.
    fn attach_fd_with_loop_info(&self, bf: impl AsRawFd, info: loop_info64) -> io::Result<()> {
        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD as IoctlRequest,
                bf.as_raw_fd() as c_int,
            )
        })?;

        let result = unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64 as IoctlRequest,
                &info,
            )
        };
        match ioctl_to_error(result) {
            Err(err) => {
                // Ignore the error to preserve the original error
                let _ = self.detach();
                Err(err)
            }
            Ok(_) => Ok(()),
        }
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Get the device major number
    pub fn major(&self) -> io::Result<u32> {
        self.device
            .metadata()
            .map(|m| unsafe { libc::major(m.rdev()) as u32 })
    }

    /// Get the device major number
    pub fn minor(&self) -> io::Result<u32> {
        self.device
            .metadata()
            .map(|m| unsafe { libc::minor(m.rdev()) as u32 })
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// # ld.attach_file("disk.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_CLR_FD as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY as IoctlRequest,
                0,
            )
        })?;
        Ok(())
    }

    // Enable or disable direct I/O for the backing file.
    pub fn set_direct_io(&self, direct_io: bool) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_DIRECT_IO as IoctlRequest,
                if direct_io { 1 } else { 0 },
            )
        })?;
        Ok(())
    }
}

/// Used to set options when attaching a device. Created with [LoopDevice::with()].
///
/// # Examples
///
/// Enable partition scanning on attach:
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop6").unwrap();
/// ld.with()
///     .part_scan(true)
///     .attach("disk.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
///
/// A 1MiB slice of the file located at 1KiB into the file.
///
/// ```rust
/// use loopdev::LoopDevice;
/// let mut ld = LoopDevice::open("/dev/loop7").unwrap();
/// ld.with()
///     .offset(1024*1024)
///     .size_limit(1024*1024*1024)
///     .attach("disk.img")
///     .unwrap();
/// # ld.detach().unwrap();
/// ```
pub struct AttachOptions<'d> {
    device: &'d LoopDevice,
    info: loop_info64,
    direct_io: bool,
}

impl AttachOptions<'_> {
    /// Offset in bytes from the start of the backing file the data will start at.
    pub fn offset(mut self, offset: u64) -> Self {
        self.info.lo_offset = offset;
        self
    }

    /// Maximum size of the data in bytes.
    pub fn size_limit(mut self, size_limit: u64) -> Self {
        self.info.lo_sizelimit = size_limit;
        self
    }

    /// Set read only flag
    pub fn read_only(mut self, read_only: bool) -> Self {
        if read_only {
            self.info.lo_flags |= LO_FLAGS_READ_ONLY;
        } else {
            self.info.lo_flags &= !LO_FLAGS_READ_ONLY;
        }
        self
    }

    /// Set autoclear flag
    pub fn autoclear(mut self, read_only: bool) -> Self {
        if read_only {
            self.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
        } else {
            self.info.lo_flags &= !LO_FLAGS_AUTOCLEAR;
        }
        self
    }

    // Enable or disable direct I/O for the backing file.
    pub fn set_direct_io(mut self, direct_io: bool) -> Self {
        self.direct_io = direct_io;
        self
    }

    /// Force the kernel to scan the partition table on a newly created loop device. Note that the
    /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
    pub fn part_scan(mut self, enable: bool) -> Self {
        if enable {
            self.info.lo_flags |= 1 << 4;
        } else {
            self.info.lo_flags &= u32::max_value() - (1 << 4);
        }
        self
    }

    /// Attach the loop device to a file with the set options.
    pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
        self.device.attach_with_loop_info(backing_file, self.info)?;
        if self.direct_io {
            self.device.set_direct_io(self.direct_io)?;
        }
        Ok(())
    }

    /// Attach the loop device to an fd
    pub fn attach_fd(self, backing_file_fd: impl AsRawFd) -> io::Result<()> {
        self.device
            .attach_fd_with_loop_info(backing_file_fd, self.info)?;
        if self.direct_io {
            self.device.set_direct_io(self.direct_io)?;
        }
        Ok(())
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Luis Casillas. 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.

extern crate rand;

pub mod splittable {
    //! A trait for splittable pseudo random number generators, that
    //! support a "split" operation that produces two generators whose
    //! initial state depends on the PRNG's state, but produce
    //! statistically independent results thereafter.
    //!
    //! References:
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  "Splittable
    //!   Pseudorandom Number Generators using Cryptographic Hashing."
    //!   *Haskell '13 Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //! * Schaathun, Hans Georg.  2015.  "Evaluation of Splittable
    //!   Pseudo-Random Generators."  *Journal of Functional
    //!   Programming*, Vol. 25.
    //! * The Haskell [`tf-random` library](https://hackage.haskell.org/package/tf-random)

    use rand::Rng;

    pub trait SplittableRng : Rng {

        /// Split this random number generator into two "branches"
        /// that produce statistically independent results.  Note that
        /// the original generator is moved into this function, and
        /// can then no longer be reused.
        fn split(self) -> (Self, Self);

    }

}

pub mod siprng {
    //! A splittable pseudo-random number generator based on the
    //! SipHash-1-3 function.  **This is not intended to be a
    //! cryptographically secure PRNG.**
    //!
    //! This generator is broadly modeled after the one described in
    //! this reference, and implemented in the Haskell [`tf-random`
    //! library](https://hackage.haskell.org/package/tf-random):
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  "Splittable
    //!   Pseudorandom Number Generators using Cryptographic Hashing."
    //!   *Haskell '13 Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //!
    //! Instead of using the Skein hash function, however, we use
    //! SipHash.

    use rand::{Rand, Rng, SeedableRng};
    use splittable::SplittableRng;
    use std::mem;

    #[derive(Clone)]
    pub struct SipRng {
        v0:  u64,
        v1:  u64,
        v2:  u64,
        v3:  u64,
        ctr: u64,
        len: usize
    }

    macro_rules! sipround {
        ($v0: expr, $v1: expr, $v2: expr, $v3: expr) => {
            $v0 = $v0.wrapping_add($v1); $v2 = $v2.wrapping_add($v3);
            $v1 = $v1.rotate_left(13);   $v3 = $v3.rotate_left(16);
            $v1 ^= $v0;                  $v3 ^= $v2;
            $v0 = $v0.rotate_left(32);

            $v2 = $v2.wrapping_add($v1); $v0 = $v0.wrapping_add($v3);
            $v1 = $v1.rotate_left(17);   $v3 = $v3.rotate_left(21);
            $v1 ^= $v2;                  $v3 ^= $v0;
            $v2 = $v0.rotate_left(32);
        }
    }

    const C0: u64 = 0x736f6d6570736575;
    const C1: u64 = 0x646f72616e646f6d;
    const C2: u64 = 0x6c7967656e657261;
    const C3: u64 = 0x7465646279746573;

    impl SipRng {
        pub fn new(k0: u64, k1: u64) -> SipRng {
            SipRng {
                v0:  k0 ^ C0,
                v1:  k1 ^ C1,
                v2:  k0 ^ C2,
                v3:  k1 ^ C3,
                ctr: 0,
                len: 1
            }
        }

        #[inline]
        fn advance(&mut self) {
            self.v3 ^= self.ctr;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= self.ctr;
            self.ctr.wrapping_add(1);
        }

        #[inline]
        fn descend(&mut self, branch: u64) {
            self.v3 ^= branch;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= branch;
            self.len.wrapping_add(1);
        }

    }

    impl SplittableRng for SipRng {

        fn split(self) -> (Self, Self) {
            let (mut r0, mut r1) = (self.clone(), self.clone());
            r0.descend(0); r1.descend(1);
            (r0, r1)
        }

    }

    impl Rng for SipRng {
        #[inline]
        fn next_u64(&mut self) -> u64 {
            self.advance();
            let (mut v0, mut v1, mut v2, mut v3) =
                (self.v0, self.v1, self.v2, self.v3);

            let len = (self.len as u64).wrapping_shl(56);
            v3 ^= len;
            sipround!(v0, v1, v2, v3);
            v0 ^= len;

            v2 ^= 0xff;
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            v0 ^ v1 ^ v2 ^ v3
        }

        #[inline]
        fn next_u32(&mut self) -> u32 {
            self.next_u64() as u32
        }

        #[inline]
        fn fill_bytes(&mut self, dest: &mut [u8]) {
            for chunk in dest.chunks_mut(8) {
                let block = unsafe {
                    mem::transmute::<u64, [u8; 8]>(self.next_u64())
                };
                for i in 0..chunk.len() {
                    chunk[i] = block[i];
                }
            }
        }
    }

    impl SeedableRng<(u64, u64)> for SipRng {

        fn reseed(&mut self, seed: (u64, u64)) {
            self.v0 = seed.0 ^ C0;
            self.v1 = seed.1 ^ C1;
            self.v2 = seed.0 ^ C2;
            self.v3 = seed.1 ^ C3;
            self.len = 1;
            self.ctr = 0;
        }

        fn from_seed(seed: (u64, u64)) -> SipRng {
            let (k0, k1) = seed;
            SipRng::new(k0, k1)
        }
    }

    impl Rand for SipRng {
        fn rand<R: Rng>(other: &mut R) -> SipRng {
            let (k0, k1) = other.gen::<(u64, u64)>();
            SipRng::new(k0, k1)
        }
    }

}

#[cfg(test)]
mod tests {
    /*
     * I have shamelessly lifted a lot of these tests from the `rand`
     * crate.
     */

    use rand::{Rng, SeedableRng};
    use rand::os::OsRng;
    use siprng::SipRng;
    use splittable::SplittableRng;

    #[test]
    fn test_rng_rand_split() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));

        let (mut ra0, mut ra1) = ra.split();
        let (mut rb0, mut rb1) = rb.split();

        assert!(iter_eq(ra0.gen_ascii_chars().take(100),
                        rb0.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra1.gen_ascii_chars().take(100),
                        rb1.gen_ascii_chars().take(100)));

        let (mut ra00, mut ra01) = ra0.split();
        let (mut ra10, mut ra11) = ra1.split();
        let (mut rb00, mut rb01) = rb0.split();
        let (mut rb10, mut rb11) = rb1.split();

        assert!(iter_eq(ra00.gen_ascii_chars().take(100),
                        rb00.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra01.gen_ascii_chars().take(100),
                        rb01.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra10.gen_ascii_chars().take(100),
                        rb10.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra11.gen_ascii_chars().take(100),
                        rb11.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_rand_seeded() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_seeded() {
        let seed : (u64, u64) = gen_seed();
        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);
        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let seed : (u64, u64) = (1234567890, 987654321);
        let mut r: SipRng = SeedableRng::from_seed(seed);
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed(seed);

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    #[test]
    fn test_rng_clone() {
        let seed : (u64, u64) = (0, 0);
        let mut rng: SipRng = SeedableRng::from_seed(seed);
        let mut clone = rng.clone();
        for _ in 0..16 {
            assert_eq!(rng.next_u64(), clone.next_u64());
        }
    }

    /*
     * Utility functions
     */

    fn gen_seed() -> (u64, u64) {
        let mut osrng = OsRng::new().ok().expect("Could not create OsRng");
        osrng.gen()
    }

    fn iter_eq<I, J>(i: I, j: J) -> bool
        where I: IntoIterator,
              J: IntoIterator<Item=I::Item>,
              I::Item: Eq
    {
        // make sure the iterators have equal length
        let mut i = i.into_iter();
        let mut j = j.into_iter();
        loop {
            match (i.next(), j.next()) {
                (Some(ref ei), Some(ref ej)) if ei == ej => { }
                (None, None) => return true,
                _ => return false,
            }
        }
    }
}
<commit_msg>Refactor the traits so as to implement the `splitn` operation.<commit_after>// Copyright 2016 Luis Casillas. 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.

extern crate rand;

pub mod splittable {
    //! Traits to support splittable random number generators.
    //! References:
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  "Splittable
    //!   Pseudorandom Number Generators using Cryptographic Hashing."
    //!   *Haskell '13 Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //! * Schaathun, Hans Georg.  2015.  "Evaluation of Splittable
    //!   Pseudo-Random Generators."  *Journal of Functional
    //!   Programming*, Vol. 25.
    //! * The Haskell [`tf-random` library](https://hackage.haskell.org/package/tf-random)

    use rand::Rng;

    /// A trait for **splittable** pseudo random number generators,
    /// that support a "split" operations that produce two generators
    /// whose initial state depends on the source RNG's state, but
    /// produce statistically independent results.
    pub trait SplittableRng : Rng + Sized {

        /// The type of "splits" produced off a `SplittableRng`
        /// instance.
        type Split : SplitRng<Self>;

        /// Split this random number generator into "branches" that
        /// produce statistically independent results.
        ///
        /// The original generator is moved into this function, and
        /// can then no longer be reused.  This is deliberate; the
        /// Claessen & Pałka construction requires this.
        ///
        /// But the `Split` object returned from here supports
        /// instantiating the same branch multiple times.  This is
        /// also deliberate.
        fn splitn(self) -> Self::Split;

        /// Split this random number generator into two branches.
        /// This has a default implementation in terms of `splitn`.
        fn split(self) -> (Self, Self) {
            let splits: Self::Split = self.splitn();
            (splits.branch(0), splits.branch(1))
        }

    }

    /// The trait implemented by the "splits" of a `SplittableRng`.
    /// This should be seen as a factory for `usize`-indexed
    /// `SplittableRng` instances.
    pub trait SplitRng<R> {
        /// Instantiate the `i`th branch of the captured
        /// `SplittableRng`.
        ///
        /// Note that instantiating the same `i` multiple times is
        /// allowed; they all start from the same state.  This is
        /// useful in some cases; for example, random generation of
        /// deterministic functions (like Haskell's QuickCheck library
        /// does).
        fn branch(&self, i: usize) -> R;
    }

}

pub mod siprng {
    //! A splittable pseudo-random number generator based on the
    //! SipHash-1-3 function.  **This is not intended to be a
    //! cryptographically secure PRNG.**
    //!
    //! This generator is broadly modeled after the one described in
    //! this reference, and implemented in the Haskell [`tf-random`
    //! library](https://hackage.haskell.org/package/tf-random):
    //!
    //! * Claessen, Koen and Michał H. Pałka.  2013.  "Splittable
    //!   Pseudorandom Number Generators using Cryptographic Hashing."
    //!   *Haskell '13 Proceedings of the 2013 ACM SIGPLAN symposium
    //!   on Haskell*, pp. 47-58.
    //!
    //! Instead of the Skein hash function, however, we use
    //! SipHash-1-3 in counter mode.

    use rand::{Rand, Rng, SeedableRng};
    use splittable::{SplittableRng, SplitRng};
    use std::mem;

    #[derive(Clone)]
    pub struct SipRng {
        v0:  u64,
        v1:  u64,
        v2:  u64,
        v3:  u64,
        ctr: u64,
        len: usize
    }

    /// A "split" of a `SipRng`.
    pub struct SipRngSplit(SipRng);

    macro_rules! sipround {
        ($v0: expr, $v1: expr, $v2: expr, $v3: expr) => {
            $v0 = $v0.wrapping_add($v1); $v2 = $v2.wrapping_add($v3);
            $v1 = $v1.rotate_left(13);   $v3 = $v3.rotate_left(16);
            $v1 ^= $v0;                  $v3 ^= $v2;
            $v0 = $v0.rotate_left(32);

            $v2 = $v2.wrapping_add($v1); $v0 = $v0.wrapping_add($v3);
            $v1 = $v1.rotate_left(17);   $v3 = $v3.rotate_left(21);
            $v1 ^= $v2;                  $v3 ^= $v0;
            $v2 = $v0.rotate_left(32);
        }
    }

    const C0: u64 = 0x736f6d6570736575;
    const C1: u64 = 0x646f72616e646f6d;
    const C2: u64 = 0x6c7967656e657261;
    const C3: u64 = 0x7465646279746573;

    impl SipRng {
        pub fn new(k0: u64, k1: u64) -> SipRng {
            SipRng {
                v0:  k0 ^ C0,
                v1:  k1 ^ C1,
                v2:  k0 ^ C2,
                v3:  k1 ^ C3,
                ctr: 0,
                len: 1
            }
        }

        #[inline]
        fn advance(&mut self) {
            self.v3 ^= self.ctr;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= self.ctr;
            self.ctr.wrapping_add(1);
            // TODO: should we do something here if we hit zero again?
        }

        #[inline]
        fn descend(&mut self, branch: u64) {
            self.v3 ^= branch;
            sipround!(self.v0, self.v1, self.v2, self.v3);
            self.v0 ^= branch;
            self.len.wrapping_add(1);
        }

    }

    impl SplitRng<SipRng> for SipRngSplit {
        fn branch(&self, i: usize) -> SipRng {
            let mut r = self.0.clone();
            r.descend(i as u64);
            r
        }
    }

    impl SplittableRng for SipRng {
        type Split = SipRngSplit;

        fn splitn(self) -> SipRngSplit {
            SipRngSplit(self)
        }

    }

    impl Rng for SipRng {
        #[inline]
        fn next_u64(&mut self) -> u64 {
            self.advance();
            let (mut v0, mut v1, mut v2, mut v3) =
                (self.v0, self.v1, self.v2, self.v3);

            let len = (self.len as u64).wrapping_shl(56);
            v3 ^= len;
            sipround!(v0, v1, v2, v3);
            v0 ^= len;

            v2 ^= 0xff;
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            sipround!(v0, v1, v2, v3);
            v0 ^ v1 ^ v2 ^ v3
        }

        #[inline]
        fn next_u32(&mut self) -> u32 {
            self.next_u64() as u32
        }

        #[inline]
        fn fill_bytes(&mut self, dest: &mut [u8]) {
            for chunk in dest.chunks_mut(8) {
                let block = unsafe {
                    mem::transmute::<u64, [u8; 8]>(self.next_u64())
                };
                for i in 0..chunk.len() {
                    chunk[i] = block[i];
                }
            }
        }
    }

    impl SeedableRng<(u64, u64)> for SipRng {

        fn reseed(&mut self, seed: (u64, u64)) {
            self.v0 = seed.0 ^ C0;
            self.v1 = seed.1 ^ C1;
            self.v2 = seed.0 ^ C2;
            self.v3 = seed.1 ^ C3;
            self.len = 1;
            self.ctr = 0;
        }

        fn from_seed(seed: (u64, u64)) -> SipRng {
            let (k0, k1) = seed;
            SipRng::new(k0, k1)
        }
    }

    impl Rand for SipRng {
        fn rand<R: Rng>(other: &mut R) -> SipRng {
            let (k0, k1) = other.gen::<(u64, u64)>();
            SipRng::new(k0, k1)
        }
    }

}

#[cfg(test)]
mod tests {
    /*
     * I have shamelessly lifted a lot of these tests from the `rand`
     * crate.
     */

    use rand::{Rng, SeedableRng};
    use rand::os::OsRng;
    use siprng::SipRng;
    use splittable::SplittableRng;

    #[test]
    fn test_rng_rand_split() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));

        let (mut ra0, mut ra1) = ra.split();
        let (mut rb0, mut rb1) = rb.split();

        assert!(iter_eq(ra0.gen_ascii_chars().take(100),
                        rb0.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra1.gen_ascii_chars().take(100),
                        rb1.gen_ascii_chars().take(100)));

        let (mut ra00, mut ra01) = ra0.split();
        let (mut ra10, mut ra11) = ra1.split();
        let (mut rb00, mut rb01) = rb0.split();
        let (mut rb10, mut rb11) = rb1.split();

        assert!(iter_eq(ra00.gen_ascii_chars().take(100),
                        rb00.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra01.gen_ascii_chars().take(100),
                        rb01.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra10.gen_ascii_chars().take(100),
                        rb10.gen_ascii_chars().take(100)));
        assert!(iter_eq(ra11.gen_ascii_chars().take(100),
                        rb11.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_rand_seeded() {
        let seed : (u64, u64) = gen_seed();

        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);

        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_seeded() {
        let seed : (u64, u64) = gen_seed();
        let mut ra: SipRng = SeedableRng::from_seed(seed);
        let mut rb: SipRng = SeedableRng::from_seed(seed);
        assert!(iter_eq(ra.gen_ascii_chars().take(100),
                        rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let seed : (u64, u64) = (1234567890, 987654321);
        let mut r: SipRng = SeedableRng::from_seed(seed);
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed(seed);

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    #[test]
    fn test_rng_clone() {
        let seed : (u64, u64) = (0, 0);
        let mut rng: SipRng = SeedableRng::from_seed(seed);
        let mut clone = rng.clone();
        for _ in 0..16 {
            assert_eq!(rng.next_u64(), clone.next_u64());
        }
    }

    /*
     * Utility functions
     */

    fn gen_seed() -> (u64, u64) {
        let mut osrng = OsRng::new().ok().expect("Could not create OsRng");
        osrng.gen()
    }

    fn iter_eq<I, J>(i: I, j: J) -> bool
        where I: IntoIterator,
              J: IntoIterator<Item=I::Item>,
              I::Item: Eq
    {
        // make sure the iterators have equal length
        let mut i = i.into_iter();
        let mut j = j.into_iter();
        loop {
            match (i.next(), j.next()) {
                (Some(ref ei), Some(ref ej)) if ei == ej => { }
                (None, None) => return true,
                _ => return false,
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! # Edit distance
//!
//! The Levenshtein edit distance between two strings is the number of
//! individual single-character changes (insert, delete, substitute)
//! necessary for string `a` to change it into `b`.

/// This can be a helpful way to order search results or fuzzy
/// auto-completion.
///
/// The runtime complexity is O(m*n), where m and n are the strings'
/// length.
///
/// # Examples
///
/// ```
/// use edit_distance::edit_distance;
///
/// edit_distance("kitten", "sitting"); // => 3
/// ```
pub fn edit_distance(a: &str, b: &str) -> i32 {

    let row: Vec<i32> = vec![0; b.len() + 1];
    let mut matrix: Vec<Vec<i32>> = vec![row; a.len() + 1];

    // initialize string a
    for i in (0..a.len()) {
        matrix[i+1][0] = matrix[i][0] + 1;
    }

    // initialize string b
    for i in (0..b.len()) {
        matrix[0][i+1] = matrix[0][i] + 1;
    }

    // calculate matrix
    for (i, ca) in a.char_indices() {
        for (j, cb) in b.char_indices() {

            let mut alternatives = [
                // deletion
                matrix[i][j+1] + 1,
                // insertion
                matrix[i+1][j] + 1,
                // match or substitution
                matrix[i][j] + if ca == cb { 0 } else { 1 }];
            alternatives.sort();
            matrix[i+1][j+1] = *alternatives.first().unwrap();
        }
    }

    matrix[a.len()][b.len()]
}

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

    #[test]
    fn simple() {
        assert_eq!(edit_distance("kitten", "sitting"), 3);
        assert_eq!(edit_distance("Tier", "Tor"), 2);
    }
}
<commit_msg>Use Iterator#min instead of sorting on mut array<commit_after>#![deny(missing_docs)]

//! # Edit distance
//!
//! The Levenshtein edit distance between two strings is the number of
//! individual single-character changes (insert, delete, substitute)
//! necessary for string `a` to change it into `b`.

/// This can be a helpful way to order search results or fuzzy
/// auto-completion.
///
/// The runtime complexity is O(m*n), where m and n are the strings'
/// length.
///
/// # Examples
///
/// ```
/// use edit_distance::edit_distance;
///
/// edit_distance("kitten", "sitting"); // => 3
/// ```
pub fn edit_distance(a: &str, b: &str) -> i32 {

    let row: Vec<i32> = vec![0; b.len() + 1];
    let mut matrix: Vec<Vec<i32>> = vec![row; a.len() + 1];

    // initialize string a
    for i in (0..a.len()) {
        matrix[i+1][0] = matrix[i][0] + 1;
    }

    // initialize string b
    for i in (0..b.len()) {
        matrix[0][i+1] = matrix[0][i] + 1;
    }

    // calculate matrix
    for (i, ca) in a.char_indices() {
        for (j, cb) in b.char_indices() {

            let alternatives = [
                // deletion
                matrix[i][j+1] + 1,
                // insertion
                matrix[i+1][j] + 1,
                // match or substitution
                matrix[i][j] + if ca == cb { 0 } else { 1 }];
            matrix[i+1][j+1] = *alternatives.iter().min().unwrap();
        }
    }

    matrix[a.len()][b.len()]
}

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

    #[test]
    fn simple() {
        assert_eq!(edit_distance("kitten", "sitting"), 3);
        assert_eq!(edit_distance("Tier", "Tor"), 2);
    }
}
<|endoftext|>


<commit_before>extern crate xml;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use std::num;

use xml::reader::{EventReader, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;

pub type Coordinate = f64;

#[derive(Debug, PartialEq)]
pub struct Tag {
    pub key: String,
    pub val: String
}

#[derive(Debug, PartialEq)]
pub struct Bounds {
    pub minlat: Coordinate,
    pub minlon: Coordinate,
    pub maxlat: Coordinate,
    pub maxlon: Coordinate,
}

#[derive(Debug, PartialEq)]
pub struct Node {
    pub id: i64,
    pub lat: Coordinate,
    pub lon: Coordinate,
    pub tags: Vec<Tag>
}

#[derive(Debug)]
pub struct OSM {
    pub bounds: Option<Bounds>,
    pub nodes: Vec<Node>
}

impl OSM {
    fn empty() -> OSM {
        OSM {
            bounds: None,
            nodes: Vec::new(),
        }
    }

    pub fn parse(file: File) -> Option<OSM> {
        let mut osm = OSM::empty();

        let reader = BufReader::new(file);
        let parser = EventReader::new(reader);

        for element in parser {
            match element {
                Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                    handle_element(&mut osm, name, attributes);
                },
                _ => { }
            }
        }

        Some(osm)
    }
}

#[derive(Debug)]
enum ErrorKind {
    BoundsMissing(AttributeError),
    IdMissing(AttributeError),
    CoordinateMissing(AttributeError),
    UnknownElement
}

#[derive(Debug)]
enum AttributeError {
    ParseFloat(num::ParseFloatError),
    ParseInt(num::ParseIntError),
    Missing
}

impl From<num::ParseFloatError> for AttributeError {
    fn from(err: num::ParseFloatError) -> AttributeError {
        AttributeError::ParseFloat(err)
    }
}

impl From<num::ParseIntError> for AttributeError {
    fn from(err: num::ParseIntError) -> AttributeError {
        AttributeError::ParseInt(err)
    }
}

#[allow(dead_code)]
enum ElementType {
    Bounds,
    Node,
    Way,
    Relation
}

impl FromStr for ElementType {
    type Err = ErrorKind;

    fn from_str(s: &str) -> Result<ElementType, ErrorKind> {
        let downcased = s.to_lowercase();

        if downcased == "bounds" {
            return Ok(ElementType::Bounds);
        }

        if downcased == "node" {
            return Ok(ElementType::Node);
        }

        if downcased == "way" {
            return Ok(ElementType::Way);
        }

        if downcased == "relation" {
            return Ok(ElementType::Relation);
        }

        Err(ErrorKind::UnknownElement)
    }
}

fn handle_element(osm: &mut OSM, name: OwnedName, attrs: Vec<OwnedAttribute>) {
    match ElementType::from_str(&name.local_name) {
        Ok(element) => {
            match element {
                ElementType::Bounds => set_bounds(osm, &attrs),
                ElementType::Node => insert_node(osm, &attrs),
                _ => ()
            }
        },
        Err(_) => ()
    }
}

fn set_bounds(osm: &mut OSM, attrs: &Vec<OwnedAttribute>) {
    match parse_bounds(&attrs) {
        Ok(bounds) => osm.bounds = Some(bounds),
        Err(_) => osm.bounds = None
    }
}

fn insert_node(osm: &mut OSM, attrs: &Vec<OwnedAttribute>) {
    match parse_node(&attrs) {
        Ok(node) => osm.nodes.push(node),
        Err(_) => ()
    }
}

fn parse_bounds(attrs: &Vec<OwnedAttribute>) -> Result<Bounds, ErrorKind> {
    let minlat = try!(find_attribute("minlat", attrs).map_err(ErrorKind::BoundsMissing));
    let minlon = try!(find_attribute("minlon", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlat = try!(find_attribute("maxlat", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlon = try!(find_attribute("maxlon", attrs).map_err(ErrorKind::BoundsMissing));

    Ok(Bounds {
        minlat: minlat,
        minlon: minlon,
        maxlat: maxlat,
        maxlon: maxlon,
    })
}

fn parse_node(attrs: &Vec<OwnedAttribute>) -> Result<Node, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::IdMissing));
    let lon = try!(find_attribute("lon", attrs).map_err(ErrorKind::CoordinateMissing));
    let lat = try!(find_attribute("lat", attrs).map_err(ErrorKind::CoordinateMissing));

    Ok(Node {
        id: id,
        lon: lon,
        lat: lat,
        tags: Vec::new()
    })
}

fn find_attribute<T>( name: &str, attrs: &Vec<OwnedAttribute>) -> Result<T, AttributeError>
    where AttributeError: std::convert::From<<T as std::str::FromStr>::Err>,
          T: FromStr
{
    let attr = attrs.iter().find(|attr| attr.name.local_name == name);
    match attr {
        Some(a) => {
            let val = try!(a.value.parse::<T>());
            Ok(val)
        },
        None => Err(AttributeError::Missing)
    }
}
<commit_msg>Inline handle_element functionality<commit_after>extern crate xml;

use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use std::num;

use xml::reader::{EventReader, XmlEvent};
use xml::attribute::OwnedAttribute;

pub type Coordinate = f64;

#[derive(Debug, PartialEq)]
pub struct Tag {
    pub key: String,
    pub val: String
}

#[derive(Debug, PartialEq)]
pub struct Bounds {
    pub minlat: Coordinate,
    pub minlon: Coordinate,
    pub maxlat: Coordinate,
    pub maxlon: Coordinate,
}

#[derive(Debug, PartialEq)]
pub struct Node {
    pub id: i64,
    pub lat: Coordinate,
    pub lon: Coordinate,
    pub tags: Vec<Tag>
}

#[derive(Debug)]
pub struct OSM {
    pub bounds: Option<Bounds>,
    pub nodes: Vec<Node>
}

impl OSM {
    fn empty() -> OSM {
        OSM {
            bounds: None,
            nodes: Vec::new(),
        }
    }

    pub fn parse(file: File) -> Option<OSM> {
        let mut osm = OSM::empty();

        let reader = BufReader::new(file);
        let parser = EventReader::new(reader);

        for element in parser {
            match element {
                Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                    match ElementType::from_str(&name.local_name) {
                        Ok(element) => {
                            match element {
                                ElementType::Bounds => set_bounds(&mut osm, &attributes),
                                ElementType::Node => insert_node(&mut osm, &attributes),
                                _ => ()
                            }
                        },
                        Err(_) => ()
                    }
                },
                _ => { }
            }
        }

        Some(osm)
    }
}

#[derive(Debug)]
enum ErrorKind {
    BoundsMissing(AttributeError),
    IdMissing(AttributeError),
    CoordinateMissing(AttributeError),
    UnknownElement
}

#[derive(Debug)]
enum AttributeError {
    ParseFloat(num::ParseFloatError),
    ParseInt(num::ParseIntError),
    Missing
}

impl From<num::ParseFloatError> for AttributeError {
    fn from(err: num::ParseFloatError) -> AttributeError {
        AttributeError::ParseFloat(err)
    }
}

impl From<num::ParseIntError> for AttributeError {
    fn from(err: num::ParseIntError) -> AttributeError {
        AttributeError::ParseInt(err)
    }
}

#[allow(dead_code)]
enum ElementType {
    Bounds,
    Node,
    Way,
    Relation
}

impl FromStr for ElementType {
    type Err = ErrorKind;

    fn from_str(s: &str) -> Result<ElementType, ErrorKind> {
        let downcased = s.to_lowercase();

        if downcased == "bounds" {
            return Ok(ElementType::Bounds);
        }

        if downcased == "node" {
            return Ok(ElementType::Node);
        }

        if downcased == "way" {
            return Ok(ElementType::Way);
        }

        if downcased == "relation" {
            return Ok(ElementType::Relation);
        }

        Err(ErrorKind::UnknownElement)
    }
}

fn set_bounds(osm: &mut OSM, attrs: &Vec<OwnedAttribute>) {
    match parse_bounds(&attrs) {
        Ok(bounds) => osm.bounds = Some(bounds),
        Err(_) => osm.bounds = None
    }
}

fn insert_node(osm: &mut OSM, attrs: &Vec<OwnedAttribute>) {
    match parse_node(&attrs) {
        Ok(node) => osm.nodes.push(node),
        Err(_) => ()
    }
}

fn parse_bounds(attrs: &Vec<OwnedAttribute>) -> Result<Bounds, ErrorKind> {
    let minlat = try!(find_attribute("minlat", attrs).map_err(ErrorKind::BoundsMissing));
    let minlon = try!(find_attribute("minlon", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlat = try!(find_attribute("maxlat", attrs).map_err(ErrorKind::BoundsMissing));
    let maxlon = try!(find_attribute("maxlon", attrs).map_err(ErrorKind::BoundsMissing));

    Ok(Bounds {
        minlat: minlat,
        minlon: minlon,
        maxlat: maxlat,
        maxlon: maxlon,
    })
}

fn parse_node(attrs: &Vec<OwnedAttribute>) -> Result<Node, ErrorKind> {
    let id = try!(find_attribute("id", attrs).map_err(ErrorKind::IdMissing));
    let lon = try!(find_attribute("lon", attrs).map_err(ErrorKind::CoordinateMissing));
    let lat = try!(find_attribute("lat", attrs).map_err(ErrorKind::CoordinateMissing));

    Ok(Node {
        id: id,
        lon: lon,
        lat: lat,
        tags: Vec::new()
    })
}

fn find_attribute<T>( name: &str, attrs: &Vec<OwnedAttribute>) -> Result<T, AttributeError>
    where AttributeError: std::convert::From<<T as std::str::FromStr>::Err>,
          T: FromStr
{
    let attr = attrs.iter().find(|attr| attr.name.local_name == name);
    match attr {
        Some(a) => {
            let val = try!(a.value.parse::<T>());
            Ok(val)
        },
        None => Err(AttributeError::Missing)
    }
}
<|endoftext|>