<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

//! `sysinfo` is a crate used to get a system's information.
//!
//! Before any attempt to read the different structs' information, you need to update them to
//! get up-to-date information.
//!
//! # Examples
//!
//! ```
//! use sysinfo::{ProcessExt, SystemExt};
//!
//! let mut system = sysinfo::System::new_all();
//!
//! // First we update all information of our system struct.
//! system.refresh_all();
//!
//! // Now let's print every process' id and name:
//! for (pid, proc_) in system.get_processes() {
//!     println!("{}:{} => status: {:?}", pid, proc_.name(), proc_.status());
//! }
//!
//! // Then let's print the temperature of the different components:
//! for component in system.get_components() {
//!     println!("{:?}", component);
//! }
//!
//! // And then all disks' information:
//! for disk in system.get_disks() {
//!     println!("{:?}", disk);
//! }
//!
//! // And finally the RAM and SWAP information:
//! println!("total memory: {} KiB", system.get_total_memory());
//! println!("used memory : {} KiB", system.get_used_memory());
//! println!("total swap  : {} KiB", system.get_total_swap());
//! println!("used swap   : {} KiB", system.get_used_swap());
//! ```

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![deny(missing_docs)]
#![deny(intra_doc_link_resolution_failure)]
//#![deny(warnings)]
#![allow(unknown_lints)]

#[macro_use]
extern crate cfg_if;
#[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))]
extern crate libc;
extern crate rayon;

#[macro_use]
extern crate doc_comment;

extern crate once_cell;

#[cfg(doctest)]
doctest!("../README.md");

#[cfg(feature = "debug")]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if! {
    if #[cfg(target_os = "macos")] {
        mod mac;
        use mac as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(unix)] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 0;
    }
}

pub use common::{
    AsU32, DiskType, DiskUsage, LoadAvg, NetworksIter, Pid, RefreshKind, Signal, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;
pub use utils::get_current_pid;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    #[cfg(all(not(target_os = "macos"), unix))]
    {
        if _new_limit < 0 {
            _new_limit = 0;
        }
        let max = sys::system::get_max_nb_fds();
        if _new_limit > max {
            _new_limit = max;
        }
        if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
            // If files are already open, to be sure that the number won't be bigger when those
            // files are closed, we subtract the current number of opened files to the new limit.
            let diff = max - **x;
            **x = _new_limit - diff;
            true
        } else {
            false
        }
    }
    #[cfg(any(not(unix), target_os = "macos"))]
    {
        false
    }
}

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

    #[test]
    fn check_memory_usage() {
        let mut s = ::System::new();

        s.refresh_all();
        assert_eq!(
            s.get_processes()
                .iter()
                .all(|(_, proc_)| proc_.memory() == 0),
            false
        );
    }

    #[test]
    fn check_users() {
        let mut s = ::System::new();
        assert!(s.get_users().is_empty());
        s.refresh_users_list();
        assert!(s.get_users().len() >= MIN_USERS);

        let mut s = ::System::new();
        assert!(s.get_users().is_empty());
        s.refresh_all();
        assert!(s.get_users().is_empty());

        let s = ::System::new_all();
        assert!(s.get_users().len() >= MIN_USERS);
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
doc_comment!(
    "
```
fn is_send<T: Send>() {}
is_send::<sysinfo::System>();
```

```
fn is_sync<T: Sync>() {}
is_sync::<sysinfo::System>();
```"
);
<commit_msg>Strenghten cfg check: use linux and android instead of unix<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

//! `sysinfo` is a crate used to get a system's information.
//!
//! Before any attempt to read the different structs' information, you need to update them to
//! get up-to-date information.
//!
//! # Examples
//!
//! ```
//! use sysinfo::{ProcessExt, SystemExt};
//!
//! let mut system = sysinfo::System::new_all();
//!
//! // First we update all information of our system struct.
//! system.refresh_all();
//!
//! // Now let's print every process' id and name:
//! for (pid, proc_) in system.get_processes() {
//!     println!("{}:{} => status: {:?}", pid, proc_.name(), proc_.status());
//! }
//!
//! // Then let's print the temperature of the different components:
//! for component in system.get_components() {
//!     println!("{:?}", component);
//! }
//!
//! // And then all disks' information:
//! for disk in system.get_disks() {
//!     println!("{:?}", disk);
//! }
//!
//! // And finally the RAM and SWAP information:
//! println!("total memory: {} KiB", system.get_total_memory());
//! println!("used memory : {} KiB", system.get_used_memory());
//! println!("total swap  : {} KiB", system.get_total_swap());
//! println!("used swap   : {} KiB", system.get_used_swap());
//! ```

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![deny(missing_docs)]
#![deny(intra_doc_link_resolution_failure)]
//#![deny(warnings)]
#![allow(unknown_lints)]

#[macro_use]
extern crate cfg_if;
#[cfg(not(any(target_os = "unknown", target_arch = "wasm32")))]
extern crate libc;
extern crate rayon;

#[macro_use]
extern crate doc_comment;

extern crate once_cell;

#[cfg(doctest)]
doctest!("../README.md");

#[cfg(feature = "debug")]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if! {
    if #[cfg(target_os = "macos")] {
        mod mac;
        use mac as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 0;
    }
}

pub use common::{
    AsU32, DiskType, DiskUsage, LoadAvg, NetworksIter, Pid, RefreshKind, Signal, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;
pub use utils::get_current_pid;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    {
        if _new_limit < 0 {
            _new_limit = 0;
        }
        let max = sys::system::get_max_nb_fds();
        if _new_limit > max {
            _new_limit = max;
        }
        if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
            // If files are already open, to be sure that the number won't be bigger when those
            // files are closed, we subtract the current number of opened files to the new limit.
            let diff = max - **x;
            **x = _new_limit - diff;
            true
        } else {
            false
        }
    }
    #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
    {
        false
    }
}

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

    #[test]
    fn check_memory_usage() {
        let mut s = ::System::new();

        s.refresh_all();
        assert_eq!(
            s.get_processes()
                .iter()
                .all(|(_, proc_)| proc_.memory() == 0),
            false
        );
    }

    #[test]
    fn check_users() {
        let mut s = ::System::new();
        assert!(s.get_users().is_empty());
        s.refresh_users_list();
        assert!(s.get_users().len() >= MIN_USERS);

        let mut s = ::System::new();
        assert!(s.get_users().is_empty());
        s.refresh_all();
        assert!(s.get_users().is_empty());

        let s = ::System::new_all();
        assert!(s.get_users().len() >= MIN_USERS);
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
doc_comment!(
    "
```
fn is_send<T: Send>() {}
is_send::<sysinfo::System>();
```

```
fn is_sync<T: Sync>() {}
is_sync::<sysinfo::System>();
```"
);
<|endoftext|>


<commit_before>use std::ptr;
use std::sync::{Mutex};
use std::iter::FromIterator;

struct Node<T> {
    value: Option<T>,
    next: *mut Node<T>
}

pub struct Queue<T> {
    head: Mutex<*mut Node<T>>,
    tail: Mutex<*mut Node<T>>
}

impl<T> Node<T> {
    /// Create a new Node<T> struct.
    /// This is only used internally by the Queue functions.
    fn new(v: Option<T>) -> *mut Node<T> {
        Box::into_raw(Box::new(Node {
            next: ptr::null_mut(),
            value: v
        }))
    }
}

unsafe impl<T> Sync for Queue<T> {}
unsafe impl<T> Send for Queue<T> {}

impl<T> Queue<T> {
    /// Create a new scottqueue::tlqueue::Queue<T> struct
    /// Starts out empty, with a single Node containing `None`
    ///
    /// # Examples
    ///
    /// ```
    /// use scottqueue::tlqueue::Queue;
    /// let q: Queue<i64> = Queue::new();
    /// ```
    pub fn new() -> Queue<T> {
        let null_node : *mut Node<T> = Node::new(None);
        Queue {
            head: Mutex::new(null_node),
            tail: Mutex::new(null_node),
        }
    }

    /// Push a value into the Queue.
    /// Internally this creates a new Node<T> and sets its value
    /// to the given value.
    ///
    /// # Examples
    ///
    /// ```
    /// use scottqueue::tlqueue::Queue;
    /// let q: Queue<i64> = Queue::new();
    /// q.push(12);
    /// ```
    pub fn push(&self, value : T) {
        let new_node : *mut Node<T> = Node::new(Some(value));
        let mut tail = self.tail.lock().unwrap();
        unsafe {
            (**tail).next = new_node;
            *tail = new_node;
        }
    }

    /// pop a value from the Queue.
    /// Internally this grabs the head of the queue, and returns the value.
    /// It then removes that node and sets the head to the next node.
    ///
    ///  Examples
    ///
    /// ```
    /// use scottqueue::tlqueue::Queue;
    /// let q: Queue<i64> = Queue::new();
    /// q.push(12);
    /// println!("Result!: {}", q.pop().unwrap());
    /// ```
    pub fn pop(&self) -> Option<T> {
        let mut head = self.head.lock().unwrap();
        unsafe {
            if (**head).next.is_null() { // is queue empty?
                return None;
            }
            let value = (*(**head).next).value.take().unwrap();
            let _: Box<Node<T>> = Box::from_raw(*head); // ? make sure that shit is deleted?
            *head = (**head).next;
            return Some(value);
        }
    }
}

impl<T> Iterator for Queue<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.pop()
    }
}

impl<A> FromIterator<A> for Queue<A> {
    fn from_iter<T>(iterator: T) -> Self where T: IntoIterator<Item=A> {
        let q = Queue::new();
        for item in iterator {
            q.push(item);
        }
        q
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use std::sync::mpsc::channel;
    use std::sync::Arc;
    use std::collections::HashSet;
    use std::thread;
    use self::test::Bencher;

    #[test]
    fn test_single_item() {
        let q: super::Queue<i64> = super::Queue::new();
        q.push(1);
        assert_eq!(q.pop().unwrap(), 1);
    }

    #[test]
    fn test_queue() {
        let values = &vec![1, 2, 3, 4, 5];
        let q: super::Queue<i64> = super::Queue::new();
        for value in values {
            q.push(*value);
        }
        let mut results: Vec<i64> = vec![];
        for _ in 0..5 {
            results.push(q.pop().unwrap());
        }
        assert_eq!(&results, values);
    }

    #[test]
    fn test_iterator() {
        let values = &vec![1, 2, 3, 4, 5];
        let q: super::Queue<i64> = super::Queue::new();
        for value in values {
            q.push(*value);
        }
        let results : Vec<i64> = q.collect();
        assert_eq!(&results, values);
    }

    #[test]
    fn test_from_iterator() {
        let values = &vec![1, 2, 3, 4, 5];
        let q: super::Queue<i64> = values.clone().into_iter().collect();
        let results : Vec<i64> = q.collect();
        assert_eq!(&results, values);
    }

    #[test]
    fn test_threads() {
        for _ in 0..100 {
            _test_threads();
        }
    }

    fn _test_threads() {
        let (tx, rx) = channel();
        let nthreads = 20;
        let nmsgs = 10000;

        let q = Arc::new(super::Queue::new());
        let mut start_set = HashSet::new();
        let mut end_set = HashSet::new();
        for i in 0..nmsgs {
            q.push(i);
            start_set.insert(i);
        }
        for _ in 0..nthreads {
            let tx = tx.clone();
            let q = q.clone();
            thread::spawn(move|| {
                for _ in 0..(nmsgs/nthreads) {
                    tx.send(q.pop().unwrap()).unwrap();
                }
                drop(tx);
            });
        }
        for i in 0..nmsgs {
            let msg = rx.recv().unwrap();
            assert!(!end_set.contains(&msg));
            end_set.insert(msg);

        }
        assert_eq!(end_set, start_set);
    }

    #[bench]
    fn push_bench(b: &mut Bencher) {
        let q = super::Queue::new();
        b.iter(|| q.push(0));
    }

    #[bench]
    fn pop_bench(b: &mut Bencher) {
        let q = super::Queue::new();
        for i in 0..10000 {
            q.push(i);
        }
        b.iter(|| q.pop());
    }
}
<commit_msg>Fixed a couple compiler warnings, tweaked benchmark parameters, and added channel benchmarks for comparision<commit_after>use std::ptr;
use std::sync::{Mutex};
use std::iter::FromIterator;

struct Node<T> {
    value: Option<T>,
    next: *mut Node<T>
}

pub struct Queue<T> {
    head: Mutex<*mut Node<T>>,
    tail: Mutex<*mut Node<T>>
}

impl<T> Node<T> {
    /// Create a new Node<T> struct.
    /// This is only used internally by the Queue functions.
    fn new(v: Option<T>) -> *mut Node<T> {
        Box::into_raw(Box::new(Node {
            next: ptr::null_mut(),
            value: v
        }))
    }
}

unsafe impl<T> Sync for Queue<T> {}
unsafe impl<T> Send for Queue<T> {}

impl<T> Queue<T> {
    /// Create a new scottqueue::tlqueue::Queue<T> struct
    /// Starts out empty, with a single Node containing `None`
    ///
    /// # Examples
    ///
    /// ```
    /// use scottqueue::tlqueue::Queue;
    /// let q: Queue<i64> = Queue::new();
    /// ```
    pub fn new() -> Queue<T> {
        let null_node : *mut Node<T> = Node::new(None);
        Queue {
            head: Mutex::new(null_node),
            tail: Mutex::new(null_node),
        }
    }

    /// Push a value into the Queue.
    /// Internally this creates a new Node<T> and sets its value
    /// to the given value.
    ///
    /// # Examples
    ///
    /// ```
    /// use scottqueue::tlqueue::Queue;
    /// let q: Queue<i64> = Queue::new();
    /// q.push(12);
    /// ```
    pub fn push(&self, value : T) {
        let new_node : *mut Node<T> = Node::new(Some(value));
        let mut tail = self.tail.lock().unwrap();
        unsafe {
            (**tail).next = new_node;
            *tail = new_node;
        }
    }

    /// pop a value from the Queue.
    /// Internally this grabs the head of the queue, and returns the value.
    /// It then removes that node and sets the head to the next node.
    ///
    ///  Examples
    ///
    /// ```
    /// use scottqueue::tlqueue::Queue;
    /// let q: Queue<i64> = Queue::new();
    /// q.push(12);
    /// println!("Result!: {}", q.pop().unwrap());
    /// ```
    pub fn pop(&self) -> Option<T> {
        let mut head = self.head.lock().unwrap();
        unsafe {
            if (**head).next.is_null() { // is queue empty?
                return None;
            }
            let value = (*(**head).next).value.take().unwrap();
            let _: Box<Node<T>> = Box::from_raw(*head); // ? make sure that shit is deleted?
            *head = (**head).next;
            return Some(value);
        }
    }
}

impl<T> Iterator for Queue<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.pop()
    }
}

impl<A> FromIterator<A> for Queue<A> {
    fn from_iter<T>(iterator: T) -> Self where T: IntoIterator<Item=A> {
        let q = Queue::new();
        for item in iterator {
            q.push(item);
        }
        q
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use std::sync::mpsc::channel;
    use std::sync::Arc;
    use std::collections::HashSet;
    use std::thread;
    use self::test::Bencher;

    #[test]
    fn test_single_item() {
        let q: super::Queue<i64> = super::Queue::new();
        q.push(1);
        assert_eq!(q.pop().unwrap(), 1);
    }

    #[test]
    fn test_queue() {
        let values = &vec![1, 2, 3, 4, 5];
        let q: super::Queue<i64> = super::Queue::new();
        for value in values {
            q.push(*value);
        }
        let mut results: Vec<i64> = vec![];
        for _ in 0..5 {
            results.push(q.pop().unwrap());
        }
        assert_eq!(&results, values);
    }

    #[test]
    fn test_iterator() {
        let values = &vec![1, 2, 3, 4, 5];
        let q: super::Queue<i64> = super::Queue::new();
        for value in values {
            q.push(*value);
        }
        let results : Vec<i64> = q.collect();
        assert_eq!(&results, values);
    }

    #[test]
    fn test_from_iterator() {
        let values = &vec![1, 2, 3, 4, 5];
        let q: super::Queue<i64> = values.clone().into_iter().collect();
        let results : Vec<i64> = q.collect();
        assert_eq!(&results, values);
    }

    #[test]
    fn test_threads() {
        for _ in 0..100 {
            _test_threads();
        }
    }

    fn _test_threads() {
        let (tx, rx) = channel();
        let nthreads = 20;
        let nmsgs = 10000;

        let q = Arc::new(super::Queue::new());
        let mut start_set = HashSet::new();
        let mut end_set = HashSet::new();
        for i in 0..nmsgs {
            q.push(i);
            start_set.insert(i);
        }
        for _ in 0..nthreads {
            let tx = tx.clone();
            let q = q.clone();
            thread::spawn(move|| {
                for _ in 0..(nmsgs/nthreads) {
                    tx.send(q.pop().unwrap()).unwrap();
                }
                drop(tx);
            });
        }
        for _ in 0..nmsgs {
            let msg = rx.recv().unwrap();
            assert!(!end_set.contains(&msg));
            end_set.insert(msg);

        }
        assert_eq!(end_set, start_set);
    }

    #[bench]
    fn push_bench(b: &mut Bencher) {
        let q = super::Queue::new();
        b.iter(|| q.push(0));
    }

    #[bench]
    fn pop_bench(b: &mut Bencher) {
        let q = super::Queue::new();
        for i in 0..100000 {
            q.push(i);
        }
        b.iter(|| q.pop());
    }

    #[bench]
    fn channel_send_bench(b: &mut Bencher) {
        let (tx, rx) = channel();
        b.iter(|| tx.send(0).unwrap());
        drop(tx);
        drop(rx);
    }

    #[bench]
    fn channel_recv_bench(b: &mut Bencher) {
        let (tx, rx) = channel();
        for i in 0..100000 {
            tx.send(i).unwrap();
        }
        b.iter(|| rx.recv().unwrap());
        drop(tx);
        drop(rx);
    }

}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// 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.

use std;
use v2::*;

/// Helper trait for retrieving top-level objects by a universal identifier
pub trait Get<T> {
    /// Retrieves a single value at the given index
    fn get(&self, id: &Index<T>) -> &T;
}

/// Helper trait for attempting to retrieve top-level objects by a universal
/// identifier
pub trait TryGet<T> {
    /// Attempts to retrieve a single value at the given index
    fn try_get(&self, id: &Index<T>) -> Result<&T, ()>;
}

/// Represents an offset into an array of type `T` owned by the root glTF object
#[derive(Clone, Copy, Debug)]
pub struct Index<T>(u32, std::marker::PhantomData<T>);

/// The root object of a glTF 2.0 asset
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Root<E: Extras> {
    #[serde(default)]
    accessors: Vec<accessor::Accessor<E>>,

    #[serde(default)]
    animations: Vec<animation::Animation<E>>,

    /// Metadata about the glTF asset
    asset: asset::Asset<E>,

    #[serde(default)]
    buffers: Vec<buffer::Buffer<E>>,

    #[serde(default, rename = "bufferViews")]
    buffer_views: Vec<buffer::BufferView<E>>,

    /// Extension specific data
    #[serde(default)]
    extensions: RootExtensions,

    /// Optional application specific data
    #[serde(default)]
    pub extras: <E as Extras>::Root,

    /// Names of glTF extensions used somewhere in this asset
    #[serde(default, rename = "extensionsUsed")]
    extensions_used: Vec<String>,

    /// Names of glTF extensions required to properly load this asset
    #[serde(default, rename = "extensionsRequired")]
    extensions_required: Vec<String>,

    #[serde(default)]
    cameras: Vec<camera::Camera<E>>,

    #[serde(default)]
    images: Vec<image::Image<E>>,

    #[serde(default)]
    materials: Vec<material::Material<E>>,

    #[serde(default)]
    meshes: Vec<mesh::Mesh<E>>,

    #[serde(default)]
    nodes: Vec<scene::Node<E>>,

    #[serde(default)]
    samplers: Vec<texture::Sampler<E>>,

    /// The default scene
    #[serde(default = "root_scene_default")]
    scene: Index<scene::Scene<E>>,

    #[serde(default)]
    scenes: Vec<scene::Scene<E>>,

    #[serde(default)]
    skins: Vec<skin::Skin<E>>,

    #[serde(default)]
    textures: Vec<texture::Texture<E>>,
}

fn root_scene_default<E: Extras>() -> Index<scene::Scene<E>> {
    Index(0, std::marker::PhantomData)
}

/// Extension specific data for `Root`
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RootExtensions {
    _allow_extra_fields: (),
}

impl<E: Extras> Root<E> {
    /// Returns the accessor at the given index
    pub fn accessor(&self, index: Index<accessor::Accessor<E>>) -> &accessor::Accessor<E> {
        &self.accessors[index.0 as usize]
    }

    /// Returns all accessors as a slice
    pub fn accessors(&self) -> &[accessor::Accessor<E>] {
        &self.accessors
    }

    /// Returns the animation at the given index
    pub fn animation(&self, index: Index<animation::Animation<E>>) -> &animation::Animation<E> {
        &self.animations[index.0 as usize]
    }

    /// Returns all animations as a slice
    pub fn animations(&self) -> &[animation::Animation<E>] {
        &self.animations
    }

    /// Returns the metadata included with this asset
    pub fn asset(&self) -> &asset::Asset<E> {
        &self.asset
    }

    /// Returns the buffer at the given index
    pub fn buffer(&self, index: Index<buffer::Buffer<E>>) -> &buffer::Buffer<E> {
        &self.buffers[index.0 as usize]
    }

    /// Returns all buffers as a slice
    pub fn buffers(&self) -> &[buffer::Buffer<E>] {
        &self.buffers
    }

    /// Returns the buffer view at the given index
    pub fn buffer_view(&self, index: Index<buffer::BufferView<E>>) -> &buffer::BufferView<E> {
        &self.buffer_views[index.0 as usize]
    }

    /// Returns all buffer views as a slice
    pub fn buffer_views(&self) -> &[buffer::BufferView<E>] {
        &self.buffer_views
    }

    /// Returns the camera at the given index
    pub fn camera(&self, index: Index<camera::Camera<E>>) -> &camera::Camera<E> {
        &self.cameras[index.0 as usize]
    }

    /// Returns all cameras as a slice
    pub fn cameras(&self) -> &[camera::Camera<E>] {
        &self.cameras
    }

    /// Returns the extensions referenced in this .gltf file
    pub fn extensions_used(&self) -> &[String] {
        &self.extensions_used
    }

    /// Returns the extensions required to load and render this asset
    pub fn extensions_required(&self) -> &[String] {
        &self.extensions_required
    }

    /// Returns a single item from the root object
    pub fn get<T>(&self, index: &Index<T>) -> &T
        where Self: Get<T>
    {
        (self as &Get<T>).get(index)
    }

    /// Returns a single item from the root object if the index is in range
    // N.B. this is hidden from the docs because it's only necessary for
    // validation during `import()`
    #[doc(hidden)]
    pub fn try_get<T>(&self, index: &Index<T>) -> Result<&T, ()>
        where Self: TryGet<T>
    {
        (self as &TryGet<T>).try_get(index)
    }

    /// Returns the image at the given index
    pub fn image(&self, index: Index<image::Image<E>>) -> &image::Image<E> {
        &self.images[index.0 as usize]
    }

    /// Returns all images as a slice
    pub fn images(&self) -> &[image::Image<E>] {
        &self.images
    }

    /// Returns the material at the given index
    pub fn material(&self, index: Index<material::Material<E>>) -> &material::Material<E> {
        &self.materials[index.0 as usize]
    }

    /// Returns all materials as a slice
    pub fn materials(&self) -> &[material::Material<E>] {
        &self.materials
    }

    /// Returns the mesh at the given index
    pub fn mesh(&self, index: Index<mesh::Mesh<E>>) -> &mesh::Mesh<E> {
        &self.meshes[index.0 as usize]
    }

    /// Returns all meshes as a slice
    pub fn meshes(&self) -> &[mesh::Mesh<E>] {
        &self.meshes
    }

    /// Returns the node at the given index
    pub fn node(&self, index: Index<scene::Node<E>>) -> &scene::Node<E> {
        &self.nodes[index.0 as usize]
    }

    /// Returns all nodes as a slice
    pub fn nodes(&self) -> &[scene::Node<E>] {
        &self.nodes
    }

    /// Returns the sampler at the given index
    pub fn sampler(&self, index: Index<texture::Sampler<E>>) -> &texture::Sampler<E> {
        &self.samplers[index.0 as usize]
    }

    /// Returns all samplers as a slice
    pub fn samplers(&self) -> &[texture::Sampler<E>] {
        &self.samplers
    }

    /// Returns the scene at the given index
    pub fn scene(&self, index: Index<scene::Scene<E>>) -> &scene::Scene<E> {
        &self.scenes[index.0 as usize]
    }

    /// Returns all scenes as a slice
    pub fn scenes(&self) -> &[scene::Scene<E>] {
        &self.scenes
    }

    /// Returns the skin at the given index
    pub fn skin(&self, index: Index<skin::Skin<E>>) -> &skin::Skin<E> {
        &self.skins[index.0 as usize]
    }

    /// Returns all skins as a slice
    pub fn skins(&self) -> &[skin::Skin<E>] {
        &self.skins
    }

    /// Returns the texture at the given index
    pub fn texture(&self, index: Index<texture::Texture<E>>) -> &texture::Texture<E> {
        &self.textures[index.0 as usize]
    }

    /// Returns all textures as a slice
    pub fn textures(&self) -> &[texture::Texture<E>] {
        &self.textures
    }

    /// Performs a search for any indices that are out of range of the array
    /// they reference. Returns true if all indices are within range.
    #[doc(hidden)]
    pub fn range_check(&self) -> Result<(), ()> {
        macro_rules! range_check {
            ($field:ident) => {
                for item in self.$field.iter() {
                    let _ = item.range_check(self)?;
                }
            }
        }
        range_check!(accessors);
        range_check!(animations);
        range_check!(buffers);
        range_check!(buffer_views);
        range_check!(cameras);
        range_check!(images);
        range_check!(materials);
        range_check!(meshes);
        range_check!(nodes);
        range_check!(samplers);
        range_check!(scenes);
        range_check!(skins);
        range_check!(textures);
        let _ = self.try_get(&self.scene)?;
        Ok(())
    }
}

impl<T> Index<T> {
    /// Creates a new `Index` representing an offset into an array containing `T`
    fn new(value: u32) -> Self {
        Index(value, std::marker::PhantomData)
    }

    /// Returns the internal offset value
    pub fn value(&self) -> u32 {
        self.0
    }
}

impl<T> serde::Serialize for Index<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ::serde::Serializer
    {
        serializer.serialize_u64(self.value() as u64)
    }
}

impl<T> serde::Deserialize for Index<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: serde::Deserializer
    {
        struct Visitor<T>(std::marker::PhantomData<T>);
        impl<T> serde::de::Visitor for Visitor<T> {
            type Value = Index<T>;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("GLenum")
            }

            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
                where E: serde::de::Error
            {
                Ok(Index::new(value as u32))
            }
        }
        deserializer.deserialize_u64(Visitor::<T>(std::marker::PhantomData))
    }
}

macro_rules! impl_get {
    ($ty:ty, $field:ident) => {
        impl<'a, E: Extras> Get<$ty> for Root<E> {
            fn get(&self, index: &Index<$ty>) -> &$ty {
                &self.$field[index.value() as usize]
            }
        }
    }
}

macro_rules! impl_try_get {
    ($ty:ty, $field:ident) => {
        #[doc(hidden)]
        impl<'a, E: Extras> TryGet<$ty> for Root<E> {
            fn try_get(&self, index: &Index<$ty>) -> Result<&$ty, ()> {
                self.$field.get(index.value() as usize).ok_or(())
            }
        }
    }
}

impl_get!(accessor::Accessor<E>, accessors);
impl_get!(animation::Animation<E>, animations);
impl_get!(buffer::Buffer<E>, buffers);
impl_get!(buffer::BufferView<E>, buffer_views);
impl_get!(camera::Camera<E>, cameras);
impl_get!(image::Image<E>, images);
impl_get!(material::Material<E>, materials);
impl_get!(mesh::Mesh<E>, meshes);
impl_get!(scene::Node<E>, nodes);
impl_get!(texture::Sampler<E>, samplers);
impl_get!(scene::Scene<E>, scenes);
impl_get!(skin::Skin<E>, skins);
impl_get!(texture::Texture<E>, textures);

impl_try_get!(accessor::Accessor<E>, accessors);
impl_try_get!(animation::Animation<E>, animations);
impl_try_get!(buffer::Buffer<E>, buffers);
impl_try_get!(buffer::BufferView<E>, buffer_views);
impl_try_get!(camera::Camera<E>, cameras);
impl_try_get!(image::Image<E>, images);
impl_try_get!(material::Material<E>, materials);
impl_try_get!(mesh::Mesh<E>, meshes);
impl_try_get!(scene::Node<E>, nodes);
impl_try_get!(texture::Sampler<E>, samplers);
impl_try_get!(scene::Scene<E>, scenes);
impl_try_get!(skin::Skin<E>, skins);
impl_try_get!(texture::Texture<E>, textures);
<commit_msg>Added v2::Root::default_scene()<commit_after>
// Copyright 2017 The gltf Library Developers
//
// 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.

use std;
use v2::*;

/// Helper trait for retrieving top-level objects by a universal identifier
pub trait Get<T> {
    /// Retrieves a single value at the given index
    fn get(&self, id: &Index<T>) -> &T;
}

/// Helper trait for attempting to retrieve top-level objects by a universal
/// identifier
pub trait TryGet<T> {
    /// Attempts to retrieve a single value at the given index
    fn try_get(&self, id: &Index<T>) -> Result<&T, ()>;
}

/// Represents an offset into an array of type `T` owned by the root glTF object
#[derive(Clone, Copy, Debug)]
pub struct Index<T>(u32, std::marker::PhantomData<T>);

/// The root object of a glTF 2.0 asset
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Root<E: Extras> {
    #[serde(default)]
    accessors: Vec<accessor::Accessor<E>>,

    #[serde(default)]
    animations: Vec<animation::Animation<E>>,

    /// Metadata about the glTF asset
    asset: asset::Asset<E>,

    #[serde(default)]
    buffers: Vec<buffer::Buffer<E>>,

    #[serde(default, rename = "bufferViews")]
    buffer_views: Vec<buffer::BufferView<E>>,

    /// The default scene
    #[serde(default = "root_scene_default", rename = "scene")]
    default_scene: Index<scene::Scene<E>>,

    /// Extension specific data
    #[serde(default)]
    extensions: RootExtensions,

    /// Optional application specific data
    #[serde(default)]
    pub extras: <E as Extras>::Root,

    /// Names of glTF extensions used somewhere in this asset
    #[serde(default, rename = "extensionsUsed")]
    extensions_used: Vec<String>,

    /// Names of glTF extensions required to properly load this asset
    #[serde(default, rename = "extensionsRequired")]
    extensions_required: Vec<String>,

    #[serde(default)]
    cameras: Vec<camera::Camera<E>>,

    #[serde(default)]
    images: Vec<image::Image<E>>,

    #[serde(default)]
    materials: Vec<material::Material<E>>,

    #[serde(default)]
    meshes: Vec<mesh::Mesh<E>>,

    #[serde(default)]
    nodes: Vec<scene::Node<E>>,

    #[serde(default)]
    samplers: Vec<texture::Sampler<E>>,

    #[serde(default)]
    scenes: Vec<scene::Scene<E>>,

    #[serde(default)]
    skins: Vec<skin::Skin<E>>,

    #[serde(default)]
    textures: Vec<texture::Texture<E>>,
}

fn root_scene_default<E: Extras>() -> Index<scene::Scene<E>> {
    Index(0, std::marker::PhantomData)
}

/// Extension specific data for `Root`
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RootExtensions {
    _allow_extra_fields: (),
}

impl<E: Extras> Root<E> {
    /// Returns the accessor at the given index
    pub fn accessor(&self, index: Index<accessor::Accessor<E>>) -> &accessor::Accessor<E> {
        &self.accessors[index.0 as usize]
    }

    /// Returns all accessors as a slice
    pub fn accessors(&self) -> &[accessor::Accessor<E>] {
        &self.accessors
    }

    /// Returns the animation at the given index
    pub fn animation(&self, index: Index<animation::Animation<E>>) -> &animation::Animation<E> {
        &self.animations[index.0 as usize]
    }

    /// Returns all animations as a slice
    pub fn animations(&self) -> &[animation::Animation<E>] {
        &self.animations
    }

    /// Returns the metadata included with this asset
    pub fn asset(&self) -> &asset::Asset<E> {
        &self.asset
    }

    /// Returns the buffer at the given index
    pub fn buffer(&self, index: Index<buffer::Buffer<E>>) -> &buffer::Buffer<E> {
        &self.buffers[index.0 as usize]
    }

    /// Returns all buffers as a slice
    pub fn buffers(&self) -> &[buffer::Buffer<E>] {
        &self.buffers
    }

    /// Returns the buffer view at the given index
    pub fn buffer_view(&self, index: Index<buffer::BufferView<E>>) -> &buffer::BufferView<E> {
        &self.buffer_views[index.0 as usize]
    }

    /// Returns all buffer views as a slice
    pub fn buffer_views(&self) -> &[buffer::BufferView<E>] {
        &self.buffer_views
    }

    /// Returns the camera at the given index
    pub fn camera(&self, index: Index<camera::Camera<E>>) -> &camera::Camera<E> {
        &self.cameras[index.0 as usize]
    }

    /// Returns all cameras as a slice
    pub fn cameras(&self) -> &[camera::Camera<E>] {
        &self.cameras
    }

    /// Returns the default scene
    pub fn default_scene(&self) -> &scene::Scene<E> {
        self.get(&self.default_scene)
    }

    /// Returns the extensions referenced in this .gltf file
    pub fn extensions_used(&self) -> &[String] {
        &self.extensions_used
    }

    /// Returns the extensions required to load and render this asset
    pub fn extensions_required(&self) -> &[String] {
        &self.extensions_required
    }

    /// Returns a single item from the root object
    pub fn get<T>(&self, index: &Index<T>) -> &T
        where Self: Get<T>
    {
        (self as &Get<T>).get(index)
    }

    /// Returns a single item from the root object if the index is in range
    // N.B. this is hidden from the docs because it's only necessary for
    // validation during `import()`
    #[doc(hidden)]
    pub fn try_get<T>(&self, index: &Index<T>) -> Result<&T, ()>
        where Self: TryGet<T>
    {
        (self as &TryGet<T>).try_get(index)
    }

    /// Returns the image at the given index
    pub fn image(&self, index: Index<image::Image<E>>) -> &image::Image<E> {
        &self.images[index.0 as usize]
    }

    /// Returns all images as a slice
    pub fn images(&self) -> &[image::Image<E>] {
        &self.images
    }

    /// Returns the material at the given index
    pub fn material(&self, index: Index<material::Material<E>>) -> &material::Material<E> {
        &self.materials[index.0 as usize]
    }

    /// Returns all materials as a slice
    pub fn materials(&self) -> &[material::Material<E>] {
        &self.materials
    }

    /// Returns the mesh at the given index
    pub fn mesh(&self, index: Index<mesh::Mesh<E>>) -> &mesh::Mesh<E> {
        &self.meshes[index.0 as usize]
    }

    /// Returns all meshes as a slice
    pub fn meshes(&self) -> &[mesh::Mesh<E>] {
        &self.meshes
    }

    /// Returns the node at the given index
    pub fn node(&self, index: Index<scene::Node<E>>) -> &scene::Node<E> {
        &self.nodes[index.0 as usize]
    }

    /// Returns all nodes as a slice
    pub fn nodes(&self) -> &[scene::Node<E>] {
        &self.nodes
    }

    /// Returns the sampler at the given index
    pub fn sampler(&self, index: Index<texture::Sampler<E>>) -> &texture::Sampler<E> {
        &self.samplers[index.0 as usize]
    }

    /// Returns all samplers as a slice
    pub fn samplers(&self) -> &[texture::Sampler<E>] {
        &self.samplers
    }

    /// Returns the scene at the given index
    pub fn scene(&self, index: Index<scene::Scene<E>>) -> &scene::Scene<E> {
        &self.scenes[index.0 as usize]
    }

    /// Returns all scenes as a slice
    pub fn scenes(&self) -> &[scene::Scene<E>] {
        &self.scenes
    }

    /// Returns the skin at the given index
    pub fn skin(&self, index: Index<skin::Skin<E>>) -> &skin::Skin<E> {
        &self.skins[index.0 as usize]
    }

    /// Returns all skins as a slice
    pub fn skins(&self) -> &[skin::Skin<E>] {
        &self.skins
    }

    /// Returns the texture at the given index
    pub fn texture(&self, index: Index<texture::Texture<E>>) -> &texture::Texture<E> {
        &self.textures[index.0 as usize]
    }

    /// Returns all textures as a slice
    pub fn textures(&self) -> &[texture::Texture<E>] {
        &self.textures
    }

    /// Performs a search for any indices that are out of range of the array
    /// they reference. Returns true if all indices are within range.
    #[doc(hidden)]
    pub fn range_check(&self) -> Result<(), ()> {
        macro_rules! range_check {
            ($field:ident) => {
                for item in self.$field.iter() {
                    let _ = item.range_check(self)?;
                }
            }
        }
        range_check!(accessors);
        range_check!(animations);
        range_check!(buffers);
        range_check!(buffer_views);
        range_check!(cameras);
        range_check!(images);
        range_check!(materials);
        range_check!(meshes);
        range_check!(nodes);
        range_check!(samplers);
        range_check!(scenes);
        range_check!(skins);
        range_check!(textures);
        let _ = self.try_get(&self.default_scene)?;
        Ok(())
    }
}

impl<T> Index<T> {
    /// Creates a new `Index` representing an offset into an array containing `T`
    fn new(value: u32) -> Self {
        Index(value, std::marker::PhantomData)
    }

    /// Returns the internal offset value
    pub fn value(&self) -> u32 {
        self.0
    }
}

impl<T> serde::Serialize for Index<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ::serde::Serializer
    {
        serializer.serialize_u64(self.value() as u64)
    }
}

impl<T> serde::Deserialize for Index<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: serde::Deserializer
    {
        struct Visitor<T>(std::marker::PhantomData<T>);
        impl<T> serde::de::Visitor for Visitor<T> {
            type Value = Index<T>;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("GLenum")
            }

            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
                where E: serde::de::Error
            {
                Ok(Index::new(value as u32))
            }
        }
        deserializer.deserialize_u64(Visitor::<T>(std::marker::PhantomData))
    }
}

macro_rules! impl_get {
    ($ty:ty, $field:ident) => {
        impl<'a, E: Extras> Get<$ty> for Root<E> {
            fn get(&self, index: &Index<$ty>) -> &$ty {
                &self.$field[index.value() as usize]
            }
        }
    }
}

macro_rules! impl_try_get {
    ($ty:ty, $field:ident) => {
        #[doc(hidden)]
        impl<'a, E: Extras> TryGet<$ty> for Root<E> {
            fn try_get(&self, index: &Index<$ty>) -> Result<&$ty, ()> {
                self.$field.get(index.value() as usize).ok_or(())
            }
        }
    }
}

impl_get!(accessor::Accessor<E>, accessors);
impl_get!(animation::Animation<E>, animations);
impl_get!(buffer::Buffer<E>, buffers);
impl_get!(buffer::BufferView<E>, buffer_views);
impl_get!(camera::Camera<E>, cameras);
impl_get!(image::Image<E>, images);
impl_get!(material::Material<E>, materials);
impl_get!(mesh::Mesh<E>, meshes);
impl_get!(scene::Node<E>, nodes);
impl_get!(texture::Sampler<E>, samplers);
impl_get!(scene::Scene<E>, scenes);
impl_get!(skin::Skin<E>, skins);
impl_get!(texture::Texture<E>, textures);

impl_try_get!(accessor::Accessor<E>, accessors);
impl_try_get!(animation::Animation<E>, animations);
impl_try_get!(buffer::Buffer<E>, buffers);
impl_try_get!(buffer::BufferView<E>, buffer_views);
impl_try_get!(camera::Camera<E>, cameras);
impl_try_get!(image::Image<E>, images);
impl_try_get!(material::Material<E>, materials);
impl_try_get!(mesh::Mesh<E>, meshes);
impl_try_get!(scene::Node<E>, nodes);
impl_try_get!(texture::Sampler<E>, samplers);
impl_try_get!(scene::Scene<E>, scenes);
impl_try_get!(skin::Skin<E>, skins);
impl_try_get!(texture::Texture<E>, textures);
<|endoftext|>


<commit_before>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! This mod contains the platform-specific implementations for Windows based on the winapi crate.

use std::fs;
use std::io;
use std::mem;
use std::os;
use std::os::windows::io::AsRawHandle;
use std::ptr;

extern crate winapi;

#[derive(Debug)]
pub struct PlatformData {
    // On Windows, the file must be kept open for the lifetime of the mapping.
    #[allow(dead_code)] // The field is not dead, the destructor is effectful.
    file: fs::File,
    mapping_handle: winapi::um::winnt::HANDLE,
}

impl Drop for PlatformData {
    fn drop (&mut self) {
        if self.mapping_handle != ptr::null_mut() {
            let success = unsafe { winapi::um::handleapi::CloseHandle(self.mapping_handle) };
            assert!(success != 0);
        }
    }
}

pub fn map_file(file: fs::File) -> io::Result<(*const u8, usize, PlatformData)> {
    let file_handle = file.as_raw_handle();
    let length = try!(file.metadata()).len();

    if length > usize::max_value() as u64 {
        return Err(io::Error::new(io::ErrorKind::Other, "file is larger than address space"));
    }

    let mut platform_data = PlatformData {
        file: file,
        mapping_handle: ptr::null_mut(),
    };

    // Don't try to map anything if the file is empty.
    if length == 0 {
        return Ok((ptr::null(), 0, platform_data));
    }

    // Memory-mapping a file on Windows is a two-step process: first we create a file mapping
    // object, and then we create a view of that mapping in the virtual address space.
    platform_data.mapping_handle = unsafe {
        winapi::um::memoryapi::CreateFileMappingW(
            file_handle as *mut winapi::ctypes::c_void,
            ptr::null_mut(),                  // Use default security policy.
            winapi::um::winnt::PAGE_READONLY, // The memory will be read-only.
            0, 0,                             // The mapping size is the size of the file.
            ptr::null_mut()                   // The mapping does not have a name.
        )
    };

    if platform_data.mapping_handle == ptr::null_mut() {
        return Err(io::Error::last_os_error());
    }

    let result = unsafe {
        winapi::um::memoryapi::MapViewOfFile(
            platform_data.mapping_handle,
            winapi::um::memoryapi::FILE_MAP_READ,     // The memory mapping will be read-only.
            0, 0,                                     // Start offset of the mapping is 0.
            length as winapi::shared::basetsd::SIZE_T // Map the entire file.
        )
    };

    if result == ptr::null_mut() {
        Err(io::Error::last_os_error())
    } else {
        Ok((result as *const u8, length as usize, platform_data))
    }
}

pub fn unmap_file(buffer: *const u8, _length: usize) {
    let success = unsafe {
        winapi::um::memoryapi::UnmapViewOfFile(buffer as *mut winapi::ctypes::c_void)
    };
    assert!(success != 0);
}

/// See also `unix::get_resident`.
pub fn get_resident(_buffer: *const u8, _length: usize, residency: &mut [bool]) {
    // As far as I am aware, Windows does not expose a way to query whether pages are resident.
    // There is no equivalent of `mincore()`. The closest thing is `VirtualQuery()`, but the
    // `state` value in the `MEMORY_BASIC_INFORMATION` struct that it fills does not indicate
    // whether the page is resident.

    // Lie and pretend everything is resident.
    for x in residency {
        *x = true;
    }
}

/// See also `unix::prefetch`.
pub fn prefetch(buffer: *const u8, length: usize) {
    let mut entry = winapi::um::memoryapi::WIN32_MEMORY_RANGE_ENTRY {
        VirtualAddress: buffer as *mut winapi::ctypes::c_void,
        NumberOfBytes: length as winapi::shared::basetsd::SIZE_T,
    };

    unsafe {
        let current_process_handle = winapi::um::processthreadsapi::GetCurrentProcess();
        winapi::um::memoryapi::PrefetchVirtualMemory(
            current_process_handle, // Prefetch for the current process.
            1, &mut entry,          // An array of length 1 that contains `entry`.
            0                       // Reserved flag that must be 0.
        );
    }

    // The return value of `PrefetchVirtualMemory` is ignored. MSDN says the function may fail if
    // the system is under memory pressure. (It is not entirely clear whether "fail" means
    // "returns a nonzero value", but I assume it does.)
}

pub fn get_page_size() -> usize {
    // Fill the `SYSTEM_INFO` struct with zeroes. It will be filled by
    // `GetSystemInfo` later but Rust requires it to be initialized.
    let mut sysinfo: winapi::um::sysinfoapi::SYSTEM_INFO = unsafe { mem::zeroed() };
    unsafe { winapi::um::sysinfoapi::GetSystemInfo(&mut sysinfo); }
    sysinfo.dwPageSize as usize
}
<commit_msg>Remove unused import<commit_after>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! This mod contains the platform-specific implementations for Windows based on the winapi crate.

use std::fs;
use std::io;
use std::mem;
use std::os::windows::io::AsRawHandle;
use std::ptr;

extern crate winapi;

#[derive(Debug)]
pub struct PlatformData {
    // On Windows, the file must be kept open for the lifetime of the mapping.
    #[allow(dead_code)] // The field is not dead, the destructor is effectful.
    file: fs::File,
    mapping_handle: winapi::um::winnt::HANDLE,
}

impl Drop for PlatformData {
    fn drop (&mut self) {
        if self.mapping_handle != ptr::null_mut() {
            let success = unsafe { winapi::um::handleapi::CloseHandle(self.mapping_handle) };
            assert!(success != 0);
        }
    }
}

pub fn map_file(file: fs::File) -> io::Result<(*const u8, usize, PlatformData)> {
    let file_handle = file.as_raw_handle();
    let length = try!(file.metadata()).len();

    if length > usize::max_value() as u64 {
        return Err(io::Error::new(io::ErrorKind::Other, "file is larger than address space"));
    }

    let mut platform_data = PlatformData {
        file: file,
        mapping_handle: ptr::null_mut(),
    };

    // Don't try to map anything if the file is empty.
    if length == 0 {
        return Ok((ptr::null(), 0, platform_data));
    }

    // Memory-mapping a file on Windows is a two-step process: first we create a file mapping
    // object, and then we create a view of that mapping in the virtual address space.
    platform_data.mapping_handle = unsafe {
        winapi::um::memoryapi::CreateFileMappingW(
            file_handle as *mut winapi::ctypes::c_void,
            ptr::null_mut(),                  // Use default security policy.
            winapi::um::winnt::PAGE_READONLY, // The memory will be read-only.
            0, 0,                             // The mapping size is the size of the file.
            ptr::null_mut()                   // The mapping does not have a name.
        )
    };

    if platform_data.mapping_handle == ptr::null_mut() {
        return Err(io::Error::last_os_error());
    }

    let result = unsafe {
        winapi::um::memoryapi::MapViewOfFile(
            platform_data.mapping_handle,
            winapi::um::memoryapi::FILE_MAP_READ,     // The memory mapping will be read-only.
            0, 0,                                     // Start offset of the mapping is 0.
            length as winapi::shared::basetsd::SIZE_T // Map the entire file.
        )
    };

    if result == ptr::null_mut() {
        Err(io::Error::last_os_error())
    } else {
        Ok((result as *const u8, length as usize, platform_data))
    }
}

pub fn unmap_file(buffer: *const u8, _length: usize) {
    let success = unsafe {
        winapi::um::memoryapi::UnmapViewOfFile(buffer as *mut winapi::ctypes::c_void)
    };
    assert!(success != 0);
}

/// See also `unix::get_resident`.
pub fn get_resident(_buffer: *const u8, _length: usize, residency: &mut [bool]) {
    // As far as I am aware, Windows does not expose a way to query whether pages are resident.
    // There is no equivalent of `mincore()`. The closest thing is `VirtualQuery()`, but the
    // `state` value in the `MEMORY_BASIC_INFORMATION` struct that it fills does not indicate
    // whether the page is resident.

    // Lie and pretend everything is resident.
    for x in residency {
        *x = true;
    }
}

/// See also `unix::prefetch`.
pub fn prefetch(buffer: *const u8, length: usize) {
    let mut entry = winapi::um::memoryapi::WIN32_MEMORY_RANGE_ENTRY {
        VirtualAddress: buffer as *mut winapi::ctypes::c_void,
        NumberOfBytes: length as winapi::shared::basetsd::SIZE_T,
    };

    unsafe {
        let current_process_handle = winapi::um::processthreadsapi::GetCurrentProcess();
        winapi::um::memoryapi::PrefetchVirtualMemory(
            current_process_handle, // Prefetch for the current process.
            1, &mut entry,          // An array of length 1 that contains `entry`.
            0                       // Reserved flag that must be 0.
        );
    }

    // The return value of `PrefetchVirtualMemory` is ignored. MSDN says the function may fail if
    // the system is under memory pressure. (It is not entirely clear whether "fail" means
    // "returns a nonzero value", but I assume it does.)
}

pub fn get_page_size() -> usize {
    // Fill the `SYSTEM_INFO` struct with zeroes. It will be filled by
    // `GetSystemInfo` later but Rust requires it to be initialized.
    let mut sysinfo: winapi::um::sysinfoapi::SYSTEM_INFO = unsafe { mem::zeroed() };
    unsafe { winapi::um::sysinfoapi::GetSystemInfo(&mut sysinfo); }
    sysinfo.dwPageSize as usize
}
<|endoftext|>


<commit_before>use std::default::Default;

extern crate time;

extern crate ansi_term;
use ansi_term::Colour::{Red, Green, Yellow, Blue, Purple, Cyan};

extern crate mysql;
use mysql::conn::MyOpts;
use mysql::conn::pool::MyPool;
use mysql::value::from_row;
use std::collections::BTreeMap;

pub mod error;
use self::error::Error;

pub mod model;
pub mod api_result;

extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson, Json};

fn main() {
    println!("--- {} ---", Red
        //.blink()
        .bold().paint("Test error Model").to_string());

    let code    = Error::get_code(&Error::Success);
    let message = Error::get_message(&Error::Success);
    println!("{{\"code\": {},\"message\":{:?}}}", code, message);

    println!("--- END ---");

    println!("\n--- {} ---", Green.bold().paint("Time").to_string());
    let time_now = time::now();
    println!("{:?}", time_now);

    let time = time::get_time();
    println!("{:?}", time);

    let time_str = time::strftime("%Y-%m-%d %H:%M:%S", &time_now);
    println!("{:?}", time_str);
    println!("--- END ---");

    println!("\n--- {} ---", Yellow.bold().paint("JSON encode decode").to_string());
    let json_str = "{\"code\":0,\"message\":\"OK\",\"data\":{\"keyword\":\"Rust, api, php, nginx\"},\"ip\":[\"192.168.0.168\",\"127.0.0.1\"]}";
    println!("json_str: {}", Blue.paint(json_str.to_string()));
    //let json: api_result::Body = json::decode(&json_str).unwrap();
    let mut obj: BTreeMap<String, json::Json> = BTreeMap::new();
    obj.insert("os".to_string(), json::Json::from_str("{\"page\": 11, \"os\": \"Linux, Unix, MacOS\"}").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    obj.insert("test".to_string(), json::Json::from_str("[\"just test\"]").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    let json_obj = api_result::Body {
        code: code,
        message: message.to_string(),
        data: obj,
    };
    let encode_str = json_obj.to_json();
    println!("encode_str: {}", encode_str.to_string());
    println!("--- END ---");

    println!("\n--- {} ---", Purple.bold().paint("BTreeMap".to_string()));
    // BTreeMap 的 key 只能是同一种类型
    let mut map   = BTreeMap::new();
    let mut n_map = BTreeMap::new();
    n_map.insert(0, "Hi, world");
    n_map.insert(1, "a");
    n_map.insert(2, "b");
    map.insert("key", "value");
    map.insert("os", "linux terminal");
    let n_keys: Vec<_>      = n_map.keys().cloned().collect();
    let n_values: Vec<&str> = n_map.values().cloned().collect();
    let keys: Vec<&str>   = map.keys().cloned().collect();
    let values: Vec<&str> = map.values().cloned().collect();
    println!("n_map->keys:   {:?}", n_keys);
    println!("n_map->values: {:?}", n_values);
    println!("map->keys:   {:?}", keys);
    println!("map->values: {:?}", values);
    for (k, v) in map.iter() {
        println!("map.{} = {}", k, v);
    }
    println!("--- END ---");

    println!("\n--- {} ---", Cyan.bold().paint("UserModel"));
    let empty_user = model::user::UserModel::create_empty();
    // error: cannot assign to immutable field
    //empty_user.id = 110;
    println!("empty_user -> {}", empty_user);
    let mut user = model::user::UserModel::create(1, "Admin".to_string(), "15801398759".to_string(), "abc@qq.com".to_string());
    println!("debug for user: {}", user);
    user.id = 100;
    user.nickname = "OP".to_string();
    println!("debug for user after modify: {}", user);
    let user_json = json::encode(&user).unwrap();
    println!("user_json: {}", user_json);

    // CREATE TABLE  `test`.`user` (
    //  `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT  '主键',
    //  `nickname` VARCHAR( 128 ) NOT NULL ,
    //  `mobile` VARCHAR( 32 ) NOT NULL ,
    //  `email` VARCHAR( 64 ) NOT NULL
    // ) ENGINE = INNODB;
    println!("\n--- {} ---", Red.bold().paint("MySQL example".to_string()));
    let opts = MyOpts {
        user: Some("dev".to_string()),
        pass: Some("dev".to_string()),
        //init: vec!["SET NAMES utf8; use test;".to_owned()], // 加入此行无法写数据.
        ..Default::default()
    };
    let pool = MyPool::new(opts).unwrap();
    //let nickname = user.nickname;
    //let mobile   = user.mobile;
    //let email    = user.email;
    //let res = pool.prepare("INSERT INTO test.user SET nickname = ?, mobile = ?, email = ?").and_then(|mut stmt| {
    //    stmt.execute((nickname, mobile, email));
    //    Ok(())
    //});
    //println!("res: {:?}", res);
    let mut users = vec![
        model::user::UserModel{id : 1, nickname: "admin".to_string(), mobile: "15811119890".to_string(), email: "158@qq.com".to_string()},
    ];
    users.push(user);
    for mut stmt in pool.prepare(r"INSERT INTO test.user
            (id, nickname, mobile, email)
            VALUES
            (NULL, ?, ?, ?)").into_iter() {
        for p in users.iter() {
            // `execute` takes ownership of `params` so we pass account name by reference.
            // Unwrap each result just to make sure no errors happended.
            stmt.execute((&p.nickname, &p.mobile, &p.email)).unwrap();
        }
    }
}
<commit_msg>add some code.<commit_after>use std::default::Default;

extern crate time;

extern crate ansi_term;
use ansi_term::Colour::{Red, Green, Yellow, Blue, Purple, Cyan};

extern crate mysql;
use mysql::conn::MyOpts;
use mysql::conn::pool::MyPool;
use mysql::value::from_row;
use std::collections::BTreeMap;

pub mod error;
use self::error::Error;

pub mod model;
pub mod api_result;

extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson, Json};

fn main() {
    println!("--- {} ---", Red
        //.blink()
        .bold().paint("Test error Model").to_string());

    let code    = Error::get_code(&Error::Success);
    let message = Error::get_message(&Error::Success);
    println!("{{\"code\": {},\"message\":{:?}}}", code, message);

    println!("--- END ---");

    println!("\n--- {} ---", Green.bold().paint("Time").to_string());
    let time_now = time::now();
    println!("{:?}", time_now);

    let time = time::get_time();
    println!("{:?}", time);

    let time_str = time::strftime("%Y-%m-%d %H:%M:%S", &time_now);
    println!("{:?}", time_str);
    println!("--- END ---");

    println!("\n--- {} ---", Yellow.bold().paint("JSON encode decode").to_string());
    let json_str = "{\"code\":0,\"message\":\"OK\",\"data\":{\"keyword\":\"Rust, api, php, nginx\"},\"ip\":[\"192.168.0.168\",\"127.0.0.1\"]}";
    println!("json_str: {}", Blue.paint(json_str.to_string()));
    //let json: api_result::Body = json::decode(&json_str).unwrap();
    let mut obj: BTreeMap<String, json::Json> = BTreeMap::new();
    obj.insert("os".to_string(), json::Json::from_str("{\"page\": 11, \"os\": \"Linux, Unix, MacOS\"}").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    obj.insert("test".to_string(), json::Json::from_str("[\"just test\"]").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    let json_obj = api_result::Body {
        code: code,
        message: message.to_string(),
        data: obj,
    };
    let encode_str = json_obj.to_json();
    println!("encode_str: {}", encode_str.to_string());
    println!("--- END ---");

    println!("\n--- {} ---", Purple.bold().paint("BTreeMap".to_string()));
    // BTreeMap 的 key 只能是同一种类型
    let mut map   = BTreeMap::new();
    let mut n_map = BTreeMap::new();
    n_map.insert(0, "Hi, world");
    n_map.insert(1, "a");
    n_map.insert(2, "b");
    map.insert("key", "value");
    map.insert("os", "linux terminal");
    let n_keys: Vec<_>      = n_map.keys().cloned().collect();
    let n_values: Vec<&str> = n_map.values().cloned().collect();
    let keys: Vec<&str>   = map.keys().cloned().collect();
    let values: Vec<&str> = map.values().cloned().collect();
    println!("n_map->keys:   {:?}", n_keys);
    println!("n_map->values: {:?}", n_values);
    println!("map->keys:   {:?}", keys);
    println!("map->values: {:?}", values);
    for (k, v) in map.iter() {
        println!("map.{} = {}", k, v);
    }
    println!("--- END ---");

    println!("\n--- {} ---", Cyan.bold().paint("UserModel"));
    let empty_user = model::user::UserModel::create_empty();
    // error: cannot assign to immutable field
    //empty_user.id = 110;
    println!("empty_user -> {}", empty_user);
    let mut user = model::user::UserModel::create(1, "Admin".to_string(), "15801398759".to_string(), "abc@qq.com".to_string());
    println!("debug for user: {}", user);
    user.id = 100;
    user.nickname = "OP".to_string();
    println!("debug for user after modify: {}", user);
    let user_json = json::encode(&user).unwrap();
    println!("user_json: {}", user_json);

    // CREATE TABLE  `test`.`user` (
    //  `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT  '主键',
    //  `nickname` VARCHAR( 128 ) NOT NULL ,
    //  `mobile` VARCHAR( 32 ) NOT NULL ,
    //  `email` VARCHAR( 64 ) NOT NULL
    // ) ENGINE = INNODB;
    println!("\n--- {} ---", Red.bold().paint("MySQL example".to_string()));
    let opts = MyOpts {
        user: Some("dev".to_string()),
        pass: Some("dev".to_string()),
        //init: vec!["SET NAMES utf8; use test;".to_owned()], // 加入此行无法写数据.
        ..Default::default()
    };
    let pool = MyPool::new(opts).unwrap();
    //let method = "insert";
    let method = "select";
    if "insert" == method {
        println!("{}", Yellow.blink().bold().paint("INSERT"));
        let mut users = vec![
            model::user::UserModel{id : 1, nickname: "admin".to_string(), mobile: "15811119890".to_string(), email: "158@qq.com".to_string()},
        ];
        users.push(user);
        for mut stmt in pool.prepare(r"INSERT INTO test.user
                (id, nickname, mobile, email)
                VALUES
                (NULL, ?, ?, ?)").into_iter() {
            for p in users.iter() {
                // `execute` takes ownership of `params` so we pass account name by reference.
                // Unwrap each result just to make sure no errors happended.
                stmt.execute((&p.nickname, &p.mobile, &p.email));
            }
        }
    } else {
        println!("{}", Yellow.blink().bold().paint("SELECT"));
    }
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate time;
extern crate libc;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};

struct JsonFilesystem;

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(JsonFilesystem, &mountpoint, &[]);
}
<commit_msg>First stab at JSON.<commit_after>extern crate fuse;
extern crate time;
extern crate libc;
extern crate serialize;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (i, key) in self.tree.keys().enumerate() {
                    reply.add(1, i as u64, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let data = json::from_str("{\"foo\": \"bar\", \"answer\": 42}").unwrap();
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem { tree: tree.clone() };
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>use std::io::{Error, Read, ErrorKind};
use std::mem::transmute;
use std::cmp::min;
use std::ptr::copy_nonoverlapping;

use sodiumoxide::crypto::secretbox;
use sodiumoxide::utils::memzero;

use crypto::{CYPHER_HEADER_SIZE, CYPHER_HEADER_SIZE_U16, MAX_PACKET_SIZE, MAX_PACKET_USIZE,
             PlainHeader, decrypt_header_inplace, decrypt_packet_inplace};

const BUFFER_SIZE: usize = CYPHER_HEADER_SIZE + MAX_PACKET_USIZE;

/// The error value signaling that a header is not correctly authenticated.
pub const UNAUTHENTICATED_HEADER: &'static str = "read unauthenticated header";

/// The error value signaling that a header claims an invalid packet length.
pub const INVALID_LENGTH: &'static str = "read header containing invalid length";

/// The error value used signaling that a packet is not correctly authenticated.
pub const UNAUTHENTICATED_PACKET: &'static str = "read unauthenticated packet";

/// The error value signaling that the box stream reached an unauthenticated eof.
pub const UNAUTHENTICATED_EOF: &'static str = "reached unauthenticated eof";

// Implements the base functionality for creating decrypting wrappers around `io::Read`s.
pub struct Decryptor {
    // Bytes are read into this buffer and get decrypted in-place
    buffer: [u8; BUFFER_SIZE],
    state: State,
}

impl Decryptor {
    pub fn new() -> Decryptor {
        Decryptor {
            buffer: [0; BUFFER_SIZE],
            state: ReadCypherHeader { offset: 0 },
        }
    }

    // A Read wrapper using the decryptor should delegate to this method in its `read` implementation.
    //
    // If this returns Ok(0) and the provided buffer was not 0 bytes in length, a final header was read
    // and no more data will be emitted. If the underlying Read emitted 0 bytes although it was not
    // given a 0 length buffer, this results in an io::Error of kind `UnexpectedEof` (since EOF
    // must be signaled by the final header).
    pub fn read<R: Read>(&mut self,
                         buf: &mut [u8],
                         reader: &mut R,
                         key: &secretbox::Key,
                         nonce: &mut secretbox::Nonce)
                         -> Result<usize, Error> {
        match self.state {
            ReadCypherHeader { offset } => {
                debug_assert!(offset < CYPHER_HEADER_SIZE_U16);

                let new_offset = offset +
                                 (read_nonzero(reader,
                                               &mut self.buffer[(offset as usize)..
                                                    CYPHER_HEADER_SIZE])? as
                                  u16);

                if new_offset < CYPHER_HEADER_SIZE_U16 {
                    self.state = ReadCypherHeader { offset: new_offset };
                    return self.read(buf, reader, key, nonce);
                } else {
                    let is_header_valid =
                        unsafe {
                            decrypt_header_inplace(&mut *(self.buffer.as_mut_ptr() as
                                                          *mut [u8; CYPHER_HEADER_SIZE]),
                                                   &key.0,
                                                   &mut nonce.0)
                        };

                    if is_header_valid {
                        let plain_header = unsafe { self.plain_header() };

                        if plain_header.is_final_header() {
                            return Ok(0);
                        } else {
                            if plain_header.get_packet_len() > MAX_PACKET_SIZE {
                                return Err(Error::new(ErrorKind::InvalidData, INVALID_LENGTH));
                            } else {
                                self.state = ReadCypherPacket {
                                    offset: 0,
                                    length: plain_header.get_packet_len(),
                                };
                                return self.read(buf, reader, key, nonce);
                            }
                        }
                    } else {
                        return Err(Error::new(ErrorKind::InvalidData, UNAUTHENTICATED_HEADER));
                    }
                }
            }

            ReadCypherPacket { offset, length } => {
                debug_assert!(offset < length);
                debug_assert!(length <= MAX_PACKET_SIZE);

                let new_offset = offset +
                                 (read_nonzero(reader,
                                               &mut self.buffer[CYPHER_HEADER_SIZE + (offset as usize)..
                                                    CYPHER_HEADER_SIZE +
                                                    (length as usize)])? as
                                  u16);

                if new_offset < length {
                    self.state = ReadCypherPacket {
                        offset: new_offset,
                        length: length,
                    };
                    return self.read(buf, reader, key, nonce);
                } else {
                    let plain_header = unsafe { self.plain_header() };

                    let is_packet_valid = unsafe {
                        decrypt_packet_inplace(self.buffer
                                                   .as_mut_ptr()
                                                   .offset(CYPHER_HEADER_SIZE as isize),
                                               &plain_header,
                                               &key.0,
                                               &mut nonce.0)
                    };

                    if is_packet_valid {
                        self.state = Readable {
                            offset: 0,
                            length: length,
                        };
                        return self.read(buf, reader, key, nonce);
                    } else {
                        return Err(Error::new(ErrorKind::InvalidData, UNAUTHENTICATED_PACKET));
                    }
                }
            }

            Readable { offset, length } => {
                debug_assert!(offset < length);
                debug_assert!(length <= MAX_PACKET_SIZE);

                let read = min(buf.len(), (length - offset) as usize);

                unsafe {
                    copy_nonoverlapping(self.buffer
                                            .as_ptr()
                                            .offset(CYPHER_HEADER_SIZE as isize +
                                                    offset as isize),
                                        buf.as_mut_ptr(),
                                        read);
                }

                if offset + (read as u16) < length {
                    self.state = Readable {
                        offset: offset + (read as u16),
                        length: length,
                    };
                } else {
                    self.state = ReadCypherHeader { offset: 0 }
                }

                return Ok(read);
            }
        }
    }

    // This unsafely casts the first 2 + secretbox::MACBYTES bytes of the buffer as a PlainHeader.
    // Everything goes horribly wrong if these bytes don't actually contain a decrypted header.
    unsafe fn plain_header(&self) -> PlainHeader {
        transmute::<[u8; secretbox::MACBYTES + 2], PlainHeader>(*(self.buffer.as_ptr() as
                                                                  *const [u8;
                                                                          secretbox::MACBYTES + 2]))
    }
}

/// Zero buffered data on dropping.
impl Drop for Decryptor {
    fn drop(&mut self) {
        memzero(&mut self.buffer);
    }
}

// State of the decryptor state machine. When `read` is called on the Decryptor, it advances
// through the state machine, providing as many bytes as possible until either the given buffer is
// full, or the underlying AsyncRead blocks.
//
// Initial state is ReadCypherHeader{offset: 0}.
enum State {
    // Read (CYPHER_HEADER_SIZE - offset) bytes from the given Readable to buffer[offset], then
    // offset += read_bytes.
    // Once offset == CYPHER_HEADER_SIZE, the CypherHeader is verified, decrypted in place, and the
    //  state machine advances to ReadCypherPacket {offset: 0, length: length_from_header}.
    //
    // Invariants: offset < CYPHER_HEADER_SIZE (since the state changes once it reaches CYPHER_HEADER_SIZE)
    ReadCypherHeader { offset: u16 },
    // Read (length - offset) bytes from the given Readable to buffer[CYPHER_HEADER_SIZE + offset],
    // then offset += read_bytes.
    // Once offset == length, the CypherPacket is verified, decrypted in place, and the state
    // machine advances to Readable {offset: 0, length: length}.
    //
    // Invariants: offset < length, length <= MAX_PACKET_SIZE
    ReadCypherPacket { offset: u16, length: u16 },
    // `read` should read (length - offset) bytes from buffer[CYPHER_HEADER_SIZE + offset], then
    // offset += written_bytes.
    // Once offset == length, the state machine advances to WriteCypherHeader { offset: 0}.
    //
    // Invariants: offset < length, length <= MAX_PACKET_SIZE
    Readable { offset: u16, length: u16 },
}
use decryptor::State::*;

// Helper function which delegates to `Reader::read`, but returns an Error of kind UnexpectedEof
// if zero bytes were read although `buf` had length greater than 0.
fn read_nonzero<R: Read>(r: &mut R, buf: &mut [u8]) -> Result<usize, Error> {
    let read = r.read(buf)?;
    if read == 0 && buf.len() > 0 {
        return Err(Error::new(ErrorKind::UnexpectedEof, UNAUTHENTICATED_EOF));
    } else {
        return Ok(read);
    }
}
<commit_msg>Disallow 0 length packets<commit_after>use std::io::{Error, Read, ErrorKind};
use std::mem::transmute;
use std::cmp::min;
use std::ptr::copy_nonoverlapping;

use sodiumoxide::crypto::secretbox;
use sodiumoxide::utils::memzero;

use crypto::{CYPHER_HEADER_SIZE, CYPHER_HEADER_SIZE_U16, MAX_PACKET_SIZE, MAX_PACKET_USIZE,
             PlainHeader, decrypt_header_inplace, decrypt_packet_inplace};

const BUFFER_SIZE: usize = CYPHER_HEADER_SIZE + MAX_PACKET_USIZE;

/// The error value signaling that a header is not correctly authenticated.
pub const UNAUTHENTICATED_HEADER: &'static str = "read unauthenticated header";

/// The error value signaling that a header claims an invalid packet length.
pub const INVALID_LENGTH: &'static str = "read header containing invalid length";

/// The error value used signaling that a packet is not correctly authenticated.
pub const UNAUTHENTICATED_PACKET: &'static str = "read unauthenticated packet";

/// The error value signaling that the box stream reached an unauthenticated eof.
pub const UNAUTHENTICATED_EOF: &'static str = "reached unauthenticated eof";

// Implements the base functionality for creating decrypting wrappers around `io::Read`s.
pub struct Decryptor {
    // Bytes are read into this buffer and get decrypted in-place
    buffer: [u8; BUFFER_SIZE],
    state: State,
}

impl Decryptor {
    pub fn new() -> Decryptor {
        Decryptor {
            buffer: [0; BUFFER_SIZE],
            state: ReadCypherHeader { offset: 0 },
        }
    }

    // A Read wrapper using the decryptor should delegate to this method in its `read` implementation.
    //
    // If this returns Ok(0) and the provided buffer was not 0 bytes in length, a final header was read
    // and no more data will be emitted. If the underlying Read emitted 0 bytes although it was not
    // given a 0 length buffer, this results in an io::Error of kind `UnexpectedEof` (since EOF
    // must be signaled by the final header).
    pub fn read<R: Read>(&mut self,
                         buf: &mut [u8],
                         reader: &mut R,
                         key: &secretbox::Key,
                         nonce: &mut secretbox::Nonce)
                         -> Result<usize, Error> {
        match self.state {
            ReadCypherHeader { offset } => {
                debug_assert!(offset < CYPHER_HEADER_SIZE_U16);

                let new_offset = offset +
                                 (read_nonzero(reader,
                                               &mut self.buffer[(offset as usize)..
                                                    CYPHER_HEADER_SIZE])? as
                                  u16);

                if new_offset < CYPHER_HEADER_SIZE_U16 {
                    self.state = ReadCypherHeader { offset: new_offset };
                    return self.read(buf, reader, key, nonce);
                } else {
                    let is_header_valid =
                        unsafe {
                            decrypt_header_inplace(&mut *(self.buffer.as_mut_ptr() as
                                                          *mut [u8; CYPHER_HEADER_SIZE]),
                                                   &key.0,
                                                   &mut nonce.0)
                        };

                    if is_header_valid {
                        let plain_header = unsafe { self.plain_header() };

                        if plain_header.is_final_header() {
                            return Ok(0);
                        } else {
                            let len = plain_header.get_packet_len();
                            if len > MAX_PACKET_SIZE || len == 0 {
                                return Err(Error::new(ErrorKind::InvalidData, INVALID_LENGTH));
                            } else {
                                self.state = ReadCypherPacket {
                                    offset: 0,
                                    length: len,
                                };
                                return self.read(buf, reader, key, nonce);
                            }
                        }
                    } else {
                        return Err(Error::new(ErrorKind::InvalidData, UNAUTHENTICATED_HEADER));
                    }
                }
            }

            ReadCypherPacket { offset, length } => {
                debug_assert!(offset < length);
                debug_assert!(length <= MAX_PACKET_SIZE);

                let new_offset = offset +
                                 (read_nonzero(reader,
                                               &mut self.buffer[CYPHER_HEADER_SIZE + (offset as usize)..
                                                    CYPHER_HEADER_SIZE +
                                                    (length as usize)])? as
                                  u16);

                if new_offset < length {
                    self.state = ReadCypherPacket {
                        offset: new_offset,
                        length: length,
                    };
                    return self.read(buf, reader, key, nonce);
                } else {
                    let plain_header = unsafe { self.plain_header() };

                    let is_packet_valid = unsafe {
                        decrypt_packet_inplace(self.buffer
                                                   .as_mut_ptr()
                                                   .offset(CYPHER_HEADER_SIZE as isize),
                                               &plain_header,
                                               &key.0,
                                               &mut nonce.0)
                    };

                    if is_packet_valid {
                        self.state = Readable {
                            offset: 0,
                            length: length,
                        };
                        return self.read(buf, reader, key, nonce);
                    } else {
                        return Err(Error::new(ErrorKind::InvalidData, UNAUTHENTICATED_PACKET));
                    }
                }
            }

            Readable { offset, length } => {
                debug_assert!(offset < length);
                debug_assert!(length <= MAX_PACKET_SIZE);

                let read = min(buf.len(), (length - offset) as usize);

                unsafe {
                    copy_nonoverlapping(self.buffer
                                            .as_ptr()
                                            .offset(CYPHER_HEADER_SIZE as isize +
                                                    offset as isize),
                                        buf.as_mut_ptr(),
                                        read);
                }

                if offset + (read as u16) < length {
                    self.state = Readable {
                        offset: offset + (read as u16),
                        length: length,
                    };
                } else {
                    self.state = ReadCypherHeader { offset: 0 }
                }

                return Ok(read);
            }
        }
    }

    // This unsafely casts the first 2 + secretbox::MACBYTES bytes of the buffer as a PlainHeader.
    // Everything goes horribly wrong if these bytes don't actually contain a decrypted header.
    unsafe fn plain_header(&self) -> PlainHeader {
        transmute::<[u8; secretbox::MACBYTES + 2], PlainHeader>(*(self.buffer.as_ptr() as
                                                                  *const [u8;
                                                                          secretbox::MACBYTES + 2]))
    }
}

/// Zero buffered data on dropping.
impl Drop for Decryptor {
    fn drop(&mut self) {
        memzero(&mut self.buffer);
    }
}

// State of the decryptor state machine. When `read` is called on the Decryptor, it advances
// through the state machine, providing as many bytes as possible until either the given buffer is
// full, or the underlying AsyncRead blocks.
//
// Initial state is ReadCypherHeader{offset: 0}.
enum State {
    // Read (CYPHER_HEADER_SIZE - offset) bytes from the given Readable to buffer[offset], then
    // offset += read_bytes.
    // Once offset == CYPHER_HEADER_SIZE, the CypherHeader is verified, decrypted in place, and the
    //  state machine advances to ReadCypherPacket {offset: 0, length: length_from_header}.
    //
    // Invariants: offset < CYPHER_HEADER_SIZE (since the state changes once it reaches CYPHER_HEADER_SIZE)
    ReadCypherHeader { offset: u16 },
    // Read (length - offset) bytes from the given Readable to buffer[CYPHER_HEADER_SIZE + offset],
    // then offset += read_bytes.
    // Once offset == length, the CypherPacket is verified, decrypted in place, and the state
    // machine advances to Readable {offset: 0, length: length}.
    //
    // Invariants: offset < length, length <= MAX_PACKET_SIZE
    ReadCypherPacket { offset: u16, length: u16 },
    // `read` should read (length - offset) bytes from buffer[CYPHER_HEADER_SIZE + offset], then
    // offset += written_bytes.
    // Once offset == length, the state machine advances to WriteCypherHeader { offset: 0}.
    //
    // Invariants: offset < length, length <= MAX_PACKET_SIZE
    Readable { offset: u16, length: u16 },
}
use decryptor::State::*;

// Helper function which delegates to `Reader::read`, but returns an Error of kind UnexpectedEof
// if zero bytes were read although `buf` had length greater than 0.
fn read_nonzero<R: Read>(r: &mut R, buf: &mut [u8]) -> Result<usize, Error> {
    let read = r.read(buf)?;
    if read == 0 && buf.len() > 0 {
        return Err(Error::new(ErrorKind::UnexpectedEof, UNAUTHENTICATED_EOF));
    } else {
        return Ok(read);
    }
}
<|endoftext|>