<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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::rt::env::max_cached_stacks;
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
              MapNonStandardFlags, MapVirtual};
use std::libc;

/// A task's stack. The name "Stack" is a vestige of segmented stacks.
pub struct Stack {
    priv buf: MemoryMap,
    priv min_size: uint,
    priv valgrind_id: libc::c_uint,
}

// Try to use MAP_STACK on platforms that support it (it's what we're doing
// anyway), but some platforms don't support it at all. For example, it appears
// that there's a bug in freebsd that MAP_STACK implies MAP_FIXED (so it always
// fails): http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
#[cfg(not(windows), not(target_os = "freebsd"))]
static STACK_FLAGS: libc::c_int = libc::MAP_STACK | libc::MAP_PRIVATE |
                                  libc::MAP_ANON;
#[cfg(target_os = "freebsd")]
static STACK_FLAGS: libc::c_int = libc::MAP_PRIVATE | libc::MAP_ANON;
#[cfg(windows)]
static STACK_FLAGS: libc::c_int = 0;

impl Stack {
    /// Allocate a new stack of `size`. If size = 0, this will fail. Use
    /// `dummy_stack` if you want a zero-sized stack.
    pub fn new(size: uint) -> Stack {
        // Map in a stack. Eventually we might be able to handle stack
        // allocation failure, which would fail to spawn the task. But there's
        // not many sensible things to do on OOM.  Failure seems fine (and is
        // what the old stack allocation did).
        let stack = match MemoryMap::new(size, [MapReadable, MapWritable,
                                         MapNonStandardFlags(STACK_FLAGS)]) {
            Ok(map) => map,
            Err(e) => fail!("mmap for stack of size {} failed: {}", size, e)
        };

        // Change the last page to be inaccessible. This is to provide safety;
        // when an FFI function overflows it will (hopefully) hit this guard
        // page. It isn't guaranteed, but that's why FFI is unsafe. buf.data is
        // guaranteed to be aligned properly.
        if !protect_last_page(&stack) {
            fail!("Could not memory-protect guard page. stack={:?}, errno={}",
                  stack, errno());
        }

        let mut stk = Stack {
            buf: stack,
            min_size: size,
            valgrind_id: 0
        };

        // FIXME: Using the FFI to call a C macro. Slow
        stk.valgrind_id = unsafe {
            rust_valgrind_stack_register(stk.start(), stk.end())
        };
        return stk;
    }

    /// Create a 0-length stack which starts (and ends) at 0.
    pub unsafe fn dummy_stack() -> Stack {
        Stack {
            buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual },
            min_size: 0,
            valgrind_id: 0
        }
    }

    /// Point to the low end of the allocated stack
    pub fn start(&self) -> *uint {
        self.buf.data as *uint
    }

    /// Point one uint beyond the high end of the allocated stack
    pub fn end(&self) -> *uint {
        unsafe {
            self.buf.data.offset(self.buf.len as int) as *uint
        }
    }
}

#[cfg(unix)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // This may seem backwards: the start of the segment is the last page?
        // Yes! The stack grows from higher addresses (the end of the allocated
        // block) to lower addresses (the start of the allocated block).
        let last_page = stack.data as *libc::c_void;
        libc::mprotect(last_page, page_size() as libc::size_t,
                       libc::PROT_NONE) != -1
    }
}

#[cfg(windows)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // see above
        let last_page = stack.data as *mut libc::c_void;
        let mut old_prot: libc::DWORD = 0;
        libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
                             libc::PAGE_NOACCESS,
                             &mut old_prot as libc::LPDWORD) != 0
    }
}

impl Drop for Stack {
    fn drop(&mut self) {
        unsafe {
            // FIXME: Using the FFI to call a C macro. Slow
            rust_valgrind_stack_deregister(self.valgrind_id);
        }
    }
}

pub struct StackPool {
    // Ideally this would be some datastructure that preserved ordering on
    // Stack.min_size.
    priv stacks: ~[Stack],
}

impl StackPool {
    pub fn new() -> StackPool {
        StackPool {
            stacks: ~[],
        }
    }

    pub fn take_stack(&mut self, min_size: uint) -> Stack {
        // Ideally this would be a binary search
        match self.stacks.iter().position(|s| s.min_size < min_size) {
            Some(idx) => self.stacks.swap_remove(idx),
            None      => Stack::new(min_size)
        }
    }

    pub fn give_stack(&mut self, stack: Stack) {
        if self.stacks.len() <= max_cached_stacks() {
            self.stacks.push(stack)
        }
    }
}

extern {
    fn rust_valgrind_stack_register(start: *libc::uintptr_t,
                                    end: *libc::uintptr_t) -> libc::c_uint;
    fn rust_valgrind_stack_deregister(id: libc::c_uint);
}
<commit_msg>Fix a bug where cached stacks weren't re-used<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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::rt::env::max_cached_stacks;
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
              MapNonStandardFlags, MapVirtual};
use std::libc;

/// A task's stack. The name "Stack" is a vestige of segmented stacks.
pub struct Stack {
    priv buf: MemoryMap,
    priv min_size: uint,
    priv valgrind_id: libc::c_uint,
}

// Try to use MAP_STACK on platforms that support it (it's what we're doing
// anyway), but some platforms don't support it at all. For example, it appears
// that there's a bug in freebsd that MAP_STACK implies MAP_FIXED (so it always
// fails): http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
#[cfg(not(windows), not(target_os = "freebsd"))]
static STACK_FLAGS: libc::c_int = libc::MAP_STACK | libc::MAP_PRIVATE |
                                  libc::MAP_ANON;
#[cfg(target_os = "freebsd")]
static STACK_FLAGS: libc::c_int = libc::MAP_PRIVATE | libc::MAP_ANON;
#[cfg(windows)]
static STACK_FLAGS: libc::c_int = 0;

impl Stack {
    /// Allocate a new stack of `size`. If size = 0, this will fail. Use
    /// `dummy_stack` if you want a zero-sized stack.
    pub fn new(size: uint) -> Stack {
        // Map in a stack. Eventually we might be able to handle stack
        // allocation failure, which would fail to spawn the task. But there's
        // not many sensible things to do on OOM.  Failure seems fine (and is
        // what the old stack allocation did).
        let stack = match MemoryMap::new(size, [MapReadable, MapWritable,
                                         MapNonStandardFlags(STACK_FLAGS)]) {
            Ok(map) => map,
            Err(e) => fail!("mmap for stack of size {} failed: {}", size, e)
        };

        // Change the last page to be inaccessible. This is to provide safety;
        // when an FFI function overflows it will (hopefully) hit this guard
        // page. It isn't guaranteed, but that's why FFI is unsafe. buf.data is
        // guaranteed to be aligned properly.
        if !protect_last_page(&stack) {
            fail!("Could not memory-protect guard page. stack={:?}, errno={}",
                  stack, errno());
        }

        let mut stk = Stack {
            buf: stack,
            min_size: size,
            valgrind_id: 0
        };

        // FIXME: Using the FFI to call a C macro. Slow
        stk.valgrind_id = unsafe {
            rust_valgrind_stack_register(stk.start(), stk.end())
        };
        return stk;
    }

    /// Create a 0-length stack which starts (and ends) at 0.
    pub unsafe fn dummy_stack() -> Stack {
        Stack {
            buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual },
            min_size: 0,
            valgrind_id: 0
        }
    }

    /// Point to the low end of the allocated stack
    pub fn start(&self) -> *uint {
        self.buf.data as *uint
    }

    /// Point one uint beyond the high end of the allocated stack
    pub fn end(&self) -> *uint {
        unsafe {
            self.buf.data.offset(self.buf.len as int) as *uint
        }
    }
}

#[cfg(unix)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // This may seem backwards: the start of the segment is the last page?
        // Yes! The stack grows from higher addresses (the end of the allocated
        // block) to lower addresses (the start of the allocated block).
        let last_page = stack.data as *libc::c_void;
        libc::mprotect(last_page, page_size() as libc::size_t,
                       libc::PROT_NONE) != -1
    }
}

#[cfg(windows)]
fn protect_last_page(stack: &MemoryMap) -> bool {
    unsafe {
        // see above
        let last_page = stack.data as *mut libc::c_void;
        let mut old_prot: libc::DWORD = 0;
        libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
                             libc::PAGE_NOACCESS,
                             &mut old_prot as libc::LPDWORD) != 0
    }
}

impl Drop for Stack {
    fn drop(&mut self) {
        unsafe {
            // FIXME: Using the FFI to call a C macro. Slow
            rust_valgrind_stack_deregister(self.valgrind_id);
        }
    }
}

pub struct StackPool {
    // Ideally this would be some datastructure that preserved ordering on
    // Stack.min_size.
    priv stacks: ~[Stack],
}

impl StackPool {
    pub fn new() -> StackPool {
        StackPool {
            stacks: ~[],
        }
    }

    pub fn take_stack(&mut self, min_size: uint) -> Stack {
        // Ideally this would be a binary search
        match self.stacks.iter().position(|s| min_size <= s.min_size) {
            Some(idx) => self.stacks.swap_remove(idx),
            None => Stack::new(min_size)
        }
    }

    pub fn give_stack(&mut self, stack: Stack) {
        if self.stacks.len() <= max_cached_stacks() {
            self.stacks.push(stack)
        }
    }
}

extern {
    fn rust_valgrind_stack_register(start: *libc::uintptr_t,
                                    end: *libc::uintptr_t) -> libc::c_uint;
    fn rust_valgrind_stack_deregister(id: libc::c_uint);
}

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

    #[test]
    fn stack_pool_caches() {
        let mut p = StackPool::new();
        let s = p.take_stack(10);
        p.give_stack(s);
        let s = p.take_stack(4);
        assert_eq!(s.min_size, 10);
        p.give_stack(s);
        let s = p.take_stack(14);
        assert_eq!(s.min_size, 14);
        p.give_stack(s);
    }

    #[test]
    fn stack_pool_caches_exact() {
        let mut p = StackPool::new();
        let mut s = p.take_stack(10);
        s.valgrind_id = 100;
        p.give_stack(s);

        let s = p.take_stack(10);
        assert_eq!(s.min_size, 10);
        assert_eq!(s.valgrind_id, 100);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Networking primitives for TCP/UDP communication
//!
//! > **NOTE**: This module is very much a work in progress and is under active
//! > development. At this time it is still recommended to use the `old_io`
//! > module while the details of this module shake out.

#![unstable(feature = "net")]

use prelude::v1::*;

use io::{self, Error, ErrorKind};
use num::Int;
use sys_common::net2 as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;

mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;

/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq)]
pub enum Shutdown {
    /// Indicates that the reading portion of this stream/socket should be shut
    /// down. All currently blocked and future reads will return `Ok(0)`.
    Read,
    /// Indicates that the writing portion of this stream/socket should be shut
    /// down. All currently blocked and future writes will return an error.
    Write,
    /// Shut down both the reading and writing portions of this stream.
    ///
    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
    Both
}

fn hton<I: Int>(i: I) -> I { i.to_be() }
fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }

fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        Error::new(ErrorKind::InvalidInput,
                   "could not resolve to any addresses", None)
    }))
}

/// An iterator over `SocketAddr` values returned from a host lookup operation.
pub struct LookupHost(net_imp::LookupHost);

impl Iterator for LookupHost {
    type Item = io::Result<SocketAddr>;
    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}

/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Examples
///
/// ```no_run
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
///     println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
    net_imp::lookup_host(host).map(LookupHost)
}
<commit_msg>Auto merge of #23394 - tanadeau:remove-old_io-notes, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Networking primitives for TCP/UDP communication
//!
//! > **NOTE**: This module is very much a work in progress and is under active
//! > development.

#![unstable(feature = "net")]

use prelude::v1::*;

use io::{self, Error, ErrorKind};
use num::Int;
use sys_common::net2 as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;

mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;

/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq)]
pub enum Shutdown {
    /// Indicates that the reading portion of this stream/socket should be shut
    /// down. All currently blocked and future reads will return `Ok(0)`.
    Read,
    /// Indicates that the writing portion of this stream/socket should be shut
    /// down. All currently blocked and future writes will return an error.
    Write,
    /// Shut down both the reading and writing portions of this stream.
    ///
    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
    Both
}

fn hton<I: Int>(i: I) -> I { i.to_be() }
fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }

fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        Error::new(ErrorKind::InvalidInput,
                   "could not resolve to any addresses", None)
    }))
}

/// An iterator over `SocketAddr` values returned from a host lookup operation.
pub struct LookupHost(net_imp::LookupHost);

impl Iterator for LookupHost {
    type Item = io::Result<SocketAddr>;
    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}

/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Examples
///
/// ```no_run
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
///     println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
    net_imp::lookup_host(host).map(LookupHost)
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! The Rust prelude. Imported into every module by default.

// Reexported core operators
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Sized};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use io::{print, println};

// Reexported types and traits
pub use clone::{Clone, DeepClone};
pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use char::Char;
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::Times;
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrVector, StrSlice, OwnedStr, StrUtil};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5};
pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9};
pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use vec::{VectorVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;

<commit_msg>auto merge of #6907 : steveklabnik/rust/prelude_docs, r=graydon<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

/*!

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default.

For example, it would be annoying to add `use io::println;` to every single
program, and the vast majority of Rust programs will wish to print to standard
output. Therefore, it makes sense to import it into every program.

Rust's prelude has three main parts:

1. io::print and io::println.
2. Core operators, such as `Add`, `Mul`, and `Not`.
3. Various types and traits, such as `Clone`, `Eq`, and `comm::Chan`.

*/

// Reexported core operators
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Sized};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use io::{print, println};

// Reexported types and traits
pub use clone::{Clone, DeepClone};
pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use char::Char;
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
pub use old_iter::{ExtendedMutableIter};
pub use iter::Times;
pub use num::{Num, NumCast};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use path::GenericPath;
pub use path::Path;
pub use path::PosixPath;
pub use path::WindowsPath;
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrVector, StrSlice, OwnedStr, StrUtil};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5};
pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9};
pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use vec::{VectorVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};

// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
pub use task::spawn;

<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};
    use slice::SlicePrelude;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::{SlicePrelude};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::{SlicePrelude};

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>rollup merge of #19101: vhbit/ios-rng-fix<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};
    use slice::SlicePrelude;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::{SlicePrelude};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::{SlicePrelude};

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::color;
use crate::errors::*;
use crate::read_write::{
    decode, fixpoint_decode, AttributeReader, DataWriter, Encoding, NodeReader, NodeWriter,
    OpenMode, PositionEncoding, WriteEncoded, WriteLE,
};
use crate::{attribute_extension, AttributeData, AttributeDataType, Point, PointsBatch};
use byteorder::{LittleEndian, ReadBytesExt};
use cgmath::Vector3;
use num_traits::identities::Zero;
use std::collections::{BTreeMap, HashMap};
use std::io::{self, BufReader, ErrorKind, Read};
use std::path::PathBuf;

pub struct RawNodeReader {
    xyz_reader: BufReader<Box<dyn Read>>,
    attribute_readers: HashMap<String, AttributeReader>,
    encoding: Encoding,
}

impl NodeReader for RawNodeReader {
    fn read(&mut self) -> io::Result<Point> {
        let mut point = Point {
            position: Vector3::zero(),
            color: color::RED.to_u8(), // is overwritten
            intensity: None,
        };

        // I tried pulling out this match by taking a function pointer to a 'decode_position'
        // function. This replaces a branch per point vs a function call per point and turned
        // out to be marginally slower.
        match self.encoding {
            Encoding::Plain => {
                point.position.x = self.xyz_reader.read_f64::<LittleEndian>()?;
                point.position.y = self.xyz_reader.read_f64::<LittleEndian>()?;
                point.position.z = self.xyz_reader.read_f64::<LittleEndian>()?;
            }
            Encoding::ScaledToCube(min, edge_length, ref pos) => match pos {
                PositionEncoding::Uint8 => {
                    point.position.x =
                        fixpoint_decode(self.xyz_reader.read_u8()?, min.x, edge_length);
                    point.position.y =
                        fixpoint_decode(self.xyz_reader.read_u8()?, min.y, edge_length);
                    point.position.z =
                        fixpoint_decode(self.xyz_reader.read_u8()?, min.z, edge_length);
                }
                PositionEncoding::Uint16 => {
                    point.position.x = fixpoint_decode(
                        self.xyz_reader.read_u16::<LittleEndian>()?,
                        min.x,
                        edge_length,
                    );
                    point.position.y = fixpoint_decode(
                        self.xyz_reader.read_u16::<LittleEndian>()?,
                        min.y,
                        edge_length,
                    );
                    point.position.z = fixpoint_decode(
                        self.xyz_reader.read_u16::<LittleEndian>()?,
                        min.z,
                        edge_length,
                    );
                }
                PositionEncoding::Float32 => {
                    point.position.x = decode(
                        self.xyz_reader.read_f32::<LittleEndian>()?,
                        min.x,
                        edge_length,
                    );
                    point.position.y = decode(
                        self.xyz_reader.read_f32::<LittleEndian>()?,
                        min.y,
                        edge_length,
                    );
                    point.position.z = decode(
                        self.xyz_reader.read_f32::<LittleEndian>()?,
                        min.z,
                        edge_length,
                    );
                }
                PositionEncoding::Float64 => {
                    point.position.x = decode(
                        self.xyz_reader.read_f64::<LittleEndian>()?,
                        min.x,
                        edge_length,
                    );
                    point.position.y = decode(
                        self.xyz_reader.read_f64::<LittleEndian>()?,
                        min.y,
                        edge_length,
                    );
                    point.position.z = decode(
                        self.xyz_reader.read_f64::<LittleEndian>()?,
                        min.z,
                        edge_length,
                    );
                }
            },
        }

        if let Some(cr) = self.attribute_readers.get_mut("color") {
            point.color.red = cr.reader.read_u8()?;
            point.color.green = cr.reader.read_u8()?;
            point.color.blue = cr.reader.read_u8()?;
        }

        if let Some(ir) = self.attribute_readers.get_mut("intensity") {
            point.intensity = Some(ir.reader.read_f32::<LittleEndian>()?);
        }

        Ok(point)
    }
}

impl RawNodeReader {
    #[allow(dead_code)]
    fn read_batch(&mut self, num_points: usize) -> io::Result<PointsBatch> {
        let mut batch = PointsBatch {
            position: vec![],
            attributes: BTreeMap::new(),
        };

        match self.encoding {
            Encoding::Plain => (0..num_points).try_for_each(|_| -> io::Result<()> {
                let x = self.xyz_reader.read_f64::<LittleEndian>()?;
                let y = self.xyz_reader.read_f64::<LittleEndian>()?;
                let z = self.xyz_reader.read_f64::<LittleEndian>()?;
                batch.position.push(Vector3::new(x, y, z));
                Ok(())
            })?,
            Encoding::ScaledToCube(min, edge_length, ref pos) => match pos {
                PositionEncoding::Uint8 => (0..num_points).try_for_each(|_| -> io::Result<()> {
                    let x = fixpoint_decode(self.xyz_reader.read_u8()?, min.x, edge_length);
                    let y = fixpoint_decode(self.xyz_reader.read_u8()?, min.y, edge_length);
                    let z = fixpoint_decode(self.xyz_reader.read_u8()?, min.z, edge_length);
                    batch.position.push(Vector3::new(x, y, z));
                    Ok(())
                })?,

                PositionEncoding::Uint16 => {
                    (0..num_points).try_for_each(|_| -> io::Result<()> {
                        let x = fixpoint_decode(
                            self.xyz_reader.read_u16::<LittleEndian>()?,
                            min.x,
                            edge_length,
                        );
                        let y = fixpoint_decode(
                            self.xyz_reader.read_u16::<LittleEndian>()?,
                            min.y,
                            edge_length,
                        );
                        let z = fixpoint_decode(
                            self.xyz_reader.read_u16::<LittleEndian>()?,
                            min.z,
                            edge_length,
                        );
                        batch.position.push(Vector3::new(x, y, z));
                        Ok(())
                    })?
                }

                PositionEncoding::Float32 => {
                    (0..num_points).try_for_each(|_| -> io::Result<()> {
                        let x = decode(
                            self.xyz_reader.read_f32::<LittleEndian>()?,
                            min.x,
                            edge_length,
                        );
                        let y = decode(
                            self.xyz_reader.read_f32::<LittleEndian>()?,
                            min.y,
                            edge_length,
                        );
                        let z = decode(
                            self.xyz_reader.read_f32::<LittleEndian>()?,
                            min.z,
                            edge_length,
                        );
                        batch.position.push(Vector3::new(x, y, z));
                        Ok(())
                    })?
                }

                PositionEncoding::Float64 => {
                    (0..num_points).try_for_each(|_| -> io::Result<()> {
                        let x = decode(
                            self.xyz_reader.read_f64::<LittleEndian>()?,
                            min.x,
                            edge_length,
                        );
                        let y = decode(
                            self.xyz_reader.read_f64::<LittleEndian>()?,
                            min.y,
                            edge_length,
                        );
                        let z = decode(
                            self.xyz_reader.read_f64::<LittleEndian>()?,
                            min.z,
                            edge_length,
                        );
                        batch.position.push(Vector3::new(x, y, z));
                        Ok(())
                    })?
                }
            },
        };

        self.attribute_readers.iter_mut().try_for_each(
            |(key, AttributeReader { data_type, reader })| -> io::Result<()> {
                match data_type {
                    AttributeDataType::U8 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_exact(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::U8(attr));
                    }
                    AttributeDataType::I64 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_i64_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::I64(attr));
                    }
                    AttributeDataType::U64 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_u64_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::U64(attr));
                    }
                    AttributeDataType::F32 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_f32_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::F32(attr));
                    }
                    AttributeDataType::F64 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_f64_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::F64(attr));
                    }
                    AttributeDataType::U8Vec3 => {
                        let mut attr = Vec::with_capacity(num_points);
                        let mut buffer = Vec::with_capacity(3 * num_points);
                        reader.read_exact(&mut buffer)?;
                        for i in 0..num_points {
                            attr.push(Vector3::new(buffer[i], buffer[i + 1], buffer[i + 2]));
                        }
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::U8Vec3(attr));
                    }
                    AttributeDataType::F64Vec3 => {
                        let mut attr = Vec::with_capacity(num_points);
                        let mut buffer = Vec::with_capacity(3 * num_points);
                        reader.read_f64_into::<LittleEndian>(&mut buffer)?;
                        for i in 0..num_points {
                            attr.push(Vector3::new(buffer[i], buffer[i + 1], buffer[i + 2]));
                        }
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::F64Vec3(attr));
                    }
                };
                Ok(())
            },
        )?;

        let num_points = batch.position.len();

        // If the attributes differ in length, something was wrong with the files.
        if batch
            .attributes
            .values()
            .all(|attr| attr.len() == num_points)
        {
            Ok(batch)
        } else {
            Err(io::Error::new(
                ErrorKind::InvalidData,
                "Attributes differ in length",
            ))
        }
    }
}

impl RawNodeReader {
    pub fn new(
        xyz_reader: Box<dyn Read>,
        attribute_readers: HashMap<String, AttributeReader>,
        encoding: Encoding,
    ) -> Result<Self> {
        let xyz_reader = BufReader::new(xyz_reader);

        Ok(Self {
            xyz_reader,
            attribute_readers,
            encoding,
        })
    }
}

pub struct RawNodeWriter {
    xyz_writer: DataWriter,
    attribute_writers: Vec<DataWriter>,
    stem: PathBuf,
    encoding: Encoding,
    open_mode: OpenMode,
}

impl NodeWriter<PointsBatch> for RawNodeWriter {
    fn new(path: impl Into<PathBuf>, encoding: Encoding, open_mode: OpenMode) -> Self {
        Self::new(path, encoding, open_mode)
    }

    fn write(&mut self, p: &PointsBatch) -> io::Result<()> {
        p.position
            .write_encoded(&self.encoding, &mut self.xyz_writer)?;

        if self.attribute_writers.is_empty() {
            for name in p.attributes.keys() {
                self.attribute_writers.push(DataWriter::new(
                    &self.stem.with_extension(attribute_extension(&name)),
                    self.open_mode,
                )?)
            }
        }

        for (i, data) in p.attributes.values().enumerate() {
            data.write_le(&mut self.attribute_writers[i])?;
        }

        Ok(())
    }
}

impl NodeWriter<Point> for RawNodeWriter {
    fn new(path: impl Into<PathBuf>, encoding: Encoding, open_mode: OpenMode) -> Self {
        Self::new(path, encoding, open_mode)
    }

    fn write(&mut self, p: &Point) -> io::Result<()> {
        p.position
            .write_encoded(&self.encoding, &mut self.xyz_writer)?;

        if self.attribute_writers.is_empty() {
            self.attribute_writers.push(DataWriter::new(
                &self.stem.with_extension(attribute_extension("color")),
                self.open_mode,
            )?);
            if p.intensity.is_some() {
                self.attribute_writers.push(DataWriter::new(
                    &self.stem.with_extension(attribute_extension("intensity")),
                    self.open_mode,
                )?);
            }
        }
        p.color.write_le(&mut self.attribute_writers[0])?;
        if let Some(i) = p.intensity {
            i.write_le(&mut self.attribute_writers[1])?;
        }

        Ok(())
    }
}

impl RawNodeWriter {
    pub fn new(path: impl Into<PathBuf>, encoding: Encoding, open_mode: OpenMode) -> Self {
        let stem: PathBuf = path.into();
        let xyz_writer = DataWriter::new(
            &stem.with_extension(attribute_extension("position")),
            open_mode,
        )
        .unwrap();
        let attribute_writers = Vec::new();
        Self {
            xyz_writer,
            attribute_writers,
            stem,
            encoding,
            open_mode,
        }
    }

    pub fn num_written(&self) -> i64 {
        let bytes_per_coordinate = match &self.encoding {
            Encoding::Plain => std::mem::size_of::<f64>(),
            Encoding::ScaledToCube(_, _, pos_enc) => pos_enc.bytes_per_coordinate(),
        } as i64;
        (self.xyz_writer.bytes_written() as i64 / bytes_per_coordinate / 3)
    }
}
<commit_msg>Make read_batch public. (#325)<commit_after>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::color;
use crate::errors::*;
use crate::read_write::{
    decode, fixpoint_decode, AttributeReader, DataWriter, Encoding, NodeReader, NodeWriter,
    OpenMode, PositionEncoding, WriteEncoded, WriteLE,
};
use crate::{attribute_extension, AttributeData, AttributeDataType, Point, PointsBatch};
use byteorder::{LittleEndian, ReadBytesExt};
use cgmath::Vector3;
use num_traits::identities::Zero;
use std::collections::{BTreeMap, HashMap};
use std::io::{self, BufReader, ErrorKind, Read};
use std::path::PathBuf;

pub struct RawNodeReader {
    xyz_reader: BufReader<Box<dyn Read>>,
    attribute_readers: HashMap<String, AttributeReader>,
    encoding: Encoding,
}

impl NodeReader for RawNodeReader {
    fn read(&mut self) -> io::Result<Point> {
        let mut point = Point {
            position: Vector3::zero(),
            color: color::RED.to_u8(), // is overwritten
            intensity: None,
        };

        // I tried pulling out this match by taking a function pointer to a 'decode_position'
        // function. This replaces a branch per point vs a function call per point and turned
        // out to be marginally slower.
        match self.encoding {
            Encoding::Plain => {
                point.position.x = self.xyz_reader.read_f64::<LittleEndian>()?;
                point.position.y = self.xyz_reader.read_f64::<LittleEndian>()?;
                point.position.z = self.xyz_reader.read_f64::<LittleEndian>()?;
            }
            Encoding::ScaledToCube(min, edge_length, ref pos) => match pos {
                PositionEncoding::Uint8 => {
                    point.position.x =
                        fixpoint_decode(self.xyz_reader.read_u8()?, min.x, edge_length);
                    point.position.y =
                        fixpoint_decode(self.xyz_reader.read_u8()?, min.y, edge_length);
                    point.position.z =
                        fixpoint_decode(self.xyz_reader.read_u8()?, min.z, edge_length);
                }
                PositionEncoding::Uint16 => {
                    point.position.x = fixpoint_decode(
                        self.xyz_reader.read_u16::<LittleEndian>()?,
                        min.x,
                        edge_length,
                    );
                    point.position.y = fixpoint_decode(
                        self.xyz_reader.read_u16::<LittleEndian>()?,
                        min.y,
                        edge_length,
                    );
                    point.position.z = fixpoint_decode(
                        self.xyz_reader.read_u16::<LittleEndian>()?,
                        min.z,
                        edge_length,
                    );
                }
                PositionEncoding::Float32 => {
                    point.position.x = decode(
                        self.xyz_reader.read_f32::<LittleEndian>()?,
                        min.x,
                        edge_length,
                    );
                    point.position.y = decode(
                        self.xyz_reader.read_f32::<LittleEndian>()?,
                        min.y,
                        edge_length,
                    );
                    point.position.z = decode(
                        self.xyz_reader.read_f32::<LittleEndian>()?,
                        min.z,
                        edge_length,
                    );
                }
                PositionEncoding::Float64 => {
                    point.position.x = decode(
                        self.xyz_reader.read_f64::<LittleEndian>()?,
                        min.x,
                        edge_length,
                    );
                    point.position.y = decode(
                        self.xyz_reader.read_f64::<LittleEndian>()?,
                        min.y,
                        edge_length,
                    );
                    point.position.z = decode(
                        self.xyz_reader.read_f64::<LittleEndian>()?,
                        min.z,
                        edge_length,
                    );
                }
            },
        }

        if let Some(cr) = self.attribute_readers.get_mut("color") {
            point.color.red = cr.reader.read_u8()?;
            point.color.green = cr.reader.read_u8()?;
            point.color.blue = cr.reader.read_u8()?;
        }

        if let Some(ir) = self.attribute_readers.get_mut("intensity") {
            point.intensity = Some(ir.reader.read_f32::<LittleEndian>()?);
        }

        Ok(point)
    }
}

impl RawNodeReader {
    pub fn read_batch(&mut self, num_points: usize) -> io::Result<PointsBatch> {
        let mut batch = PointsBatch {
            position: vec![],
            attributes: BTreeMap::new(),
        };

        match self.encoding {
            Encoding::Plain => (0..num_points).try_for_each(|_| -> io::Result<()> {
                let x = self.xyz_reader.read_f64::<LittleEndian>()?;
                let y = self.xyz_reader.read_f64::<LittleEndian>()?;
                let z = self.xyz_reader.read_f64::<LittleEndian>()?;
                batch.position.push(Vector3::new(x, y, z));
                Ok(())
            })?,
            Encoding::ScaledToCube(min, edge_length, ref pos) => match pos {
                PositionEncoding::Uint8 => (0..num_points).try_for_each(|_| -> io::Result<()> {
                    let x = fixpoint_decode(self.xyz_reader.read_u8()?, min.x, edge_length);
                    let y = fixpoint_decode(self.xyz_reader.read_u8()?, min.y, edge_length);
                    let z = fixpoint_decode(self.xyz_reader.read_u8()?, min.z, edge_length);
                    batch.position.push(Vector3::new(x, y, z));
                    Ok(())
                })?,

                PositionEncoding::Uint16 => {
                    (0..num_points).try_for_each(|_| -> io::Result<()> {
                        let x = fixpoint_decode(
                            self.xyz_reader.read_u16::<LittleEndian>()?,
                            min.x,
                            edge_length,
                        );
                        let y = fixpoint_decode(
                            self.xyz_reader.read_u16::<LittleEndian>()?,
                            min.y,
                            edge_length,
                        );
                        let z = fixpoint_decode(
                            self.xyz_reader.read_u16::<LittleEndian>()?,
                            min.z,
                            edge_length,
                        );
                        batch.position.push(Vector3::new(x, y, z));
                        Ok(())
                    })?
                }

                PositionEncoding::Float32 => {
                    (0..num_points).try_for_each(|_| -> io::Result<()> {
                        let x = decode(
                            self.xyz_reader.read_f32::<LittleEndian>()?,
                            min.x,
                            edge_length,
                        );
                        let y = decode(
                            self.xyz_reader.read_f32::<LittleEndian>()?,
                            min.y,
                            edge_length,
                        );
                        let z = decode(
                            self.xyz_reader.read_f32::<LittleEndian>()?,
                            min.z,
                            edge_length,
                        );
                        batch.position.push(Vector3::new(x, y, z));
                        Ok(())
                    })?
                }

                PositionEncoding::Float64 => {
                    (0..num_points).try_for_each(|_| -> io::Result<()> {
                        let x = decode(
                            self.xyz_reader.read_f64::<LittleEndian>()?,
                            min.x,
                            edge_length,
                        );
                        let y = decode(
                            self.xyz_reader.read_f64::<LittleEndian>()?,
                            min.y,
                            edge_length,
                        );
                        let z = decode(
                            self.xyz_reader.read_f64::<LittleEndian>()?,
                            min.z,
                            edge_length,
                        );
                        batch.position.push(Vector3::new(x, y, z));
                        Ok(())
                    })?
                }
            },
        };

        self.attribute_readers.iter_mut().try_for_each(
            |(key, AttributeReader { data_type, reader })| -> io::Result<()> {
                match data_type {
                    AttributeDataType::U8 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_exact(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::U8(attr));
                    }
                    AttributeDataType::I64 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_i64_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::I64(attr));
                    }
                    AttributeDataType::U64 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_u64_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::U64(attr));
                    }
                    AttributeDataType::F32 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_f32_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::F32(attr));
                    }
                    AttributeDataType::F64 => {
                        let mut attr = Vec::with_capacity(num_points);
                        reader.read_f64_into::<LittleEndian>(&mut attr)?;
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::F64(attr));
                    }
                    AttributeDataType::U8Vec3 => {
                        let mut attr = Vec::with_capacity(num_points);
                        let mut buffer = Vec::with_capacity(3 * num_points);
                        reader.read_exact(&mut buffer)?;
                        for i in 0..num_points {
                            attr.push(Vector3::new(buffer[i], buffer[i + 1], buffer[i + 2]));
                        }
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::U8Vec3(attr));
                    }
                    AttributeDataType::F64Vec3 => {
                        let mut attr = Vec::with_capacity(num_points);
                        let mut buffer = Vec::with_capacity(3 * num_points);
                        reader.read_f64_into::<LittleEndian>(&mut buffer)?;
                        for i in 0..num_points {
                            attr.push(Vector3::new(buffer[i], buffer[i + 1], buffer[i + 2]));
                        }
                        batch
                            .attributes
                            .insert(key.to_owned(), AttributeData::F64Vec3(attr));
                    }
                };
                Ok(())
            },
        )?;

        let num_points = batch.position.len();

        // If the attributes differ in length, something was wrong with the files.
        if batch
            .attributes
            .values()
            .all(|attr| attr.len() == num_points)
        {
            Ok(batch)
        } else {
            Err(io::Error::new(
                ErrorKind::InvalidData,
                "Attributes differ in length",
            ))
        }
    }
}

impl RawNodeReader {
    pub fn new(
        xyz_reader: Box<dyn Read>,
        attribute_readers: HashMap<String, AttributeReader>,
        encoding: Encoding,
    ) -> Result<Self> {
        let xyz_reader = BufReader::new(xyz_reader);

        Ok(Self {
            xyz_reader,
            attribute_readers,
            encoding,
        })
    }
}

pub struct RawNodeWriter {
    xyz_writer: DataWriter,
    attribute_writers: Vec<DataWriter>,
    stem: PathBuf,
    encoding: Encoding,
    open_mode: OpenMode,
}

impl NodeWriter<PointsBatch> for RawNodeWriter {
    fn new(path: impl Into<PathBuf>, encoding: Encoding, open_mode: OpenMode) -> Self {
        Self::new(path, encoding, open_mode)
    }

    fn write(&mut self, p: &PointsBatch) -> io::Result<()> {
        p.position
            .write_encoded(&self.encoding, &mut self.xyz_writer)?;

        if self.attribute_writers.is_empty() {
            for name in p.attributes.keys() {
                self.attribute_writers.push(DataWriter::new(
                    &self.stem.with_extension(attribute_extension(&name)),
                    self.open_mode,
                )?)
            }
        }

        for (i, data) in p.attributes.values().enumerate() {
            data.write_le(&mut self.attribute_writers[i])?;
        }

        Ok(())
    }
}

impl NodeWriter<Point> for RawNodeWriter {
    fn new(path: impl Into<PathBuf>, encoding: Encoding, open_mode: OpenMode) -> Self {
        Self::new(path, encoding, open_mode)
    }

    fn write(&mut self, p: &Point) -> io::Result<()> {
        p.position
            .write_encoded(&self.encoding, &mut self.xyz_writer)?;

        if self.attribute_writers.is_empty() {
            self.attribute_writers.push(DataWriter::new(
                &self.stem.with_extension(attribute_extension("color")),
                self.open_mode,
            )?);
            if p.intensity.is_some() {
                self.attribute_writers.push(DataWriter::new(
                    &self.stem.with_extension(attribute_extension("intensity")),
                    self.open_mode,
                )?);
            }
        }
        p.color.write_le(&mut self.attribute_writers[0])?;
        if let Some(i) = p.intensity {
            i.write_le(&mut self.attribute_writers[1])?;
        }

        Ok(())
    }
}

impl RawNodeWriter {
    pub fn new(path: impl Into<PathBuf>, encoding: Encoding, open_mode: OpenMode) -> Self {
        let stem: PathBuf = path.into();
        let xyz_writer = DataWriter::new(
            &stem.with_extension(attribute_extension("position")),
            open_mode,
        )
        .unwrap();
        let attribute_writers = Vec::new();
        Self {
            xyz_writer,
            attribute_writers,
            stem,
            encoding,
            open_mode,
        }
    }

    pub fn num_written(&self) -> i64 {
        let bytes_per_coordinate = match &self.encoding {
            Encoding::Plain => std::mem::size_of::<f64>(),
            Encoding::ScaledToCube(_, _, pos_enc) => pos_enc.bytes_per_coordinate(),
        } as i64;
        (self.xyz_writer.bytes_written() as i64 / bytes_per_coordinate / 3)
    }
}
<|endoftext|>


<commit_before>use cairo::{self, ImageSurface};
use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::{Parse, ParseValue, ParseValueToParseError};
use crate::property_bag::PropertyBag;
use crate::surface_utils::{iterators::Pixels, shared_surface::SharedImageSurface};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, PrimitiveWithInput};

/// Enumeration of the color channels the displacement map can source.
#[derive(Clone, Copy)]
enum ColorChannel {
    R,
    G,
    B,
    A,
}

/// The `feDisplacementMap` filter primitive.
pub struct FeDisplacementMap {
    base: PrimitiveWithInput,
    in2: Option<Input>,
    scale: f64,
    x_channel_selector: ColorChannel,
    y_channel_selector: ColorChannel,
}

impl Default for FeDisplacementMap {
    /// Constructs a new `DisplacementMap` with empty properties.
    #[inline]
    fn default() -> FeDisplacementMap {
        FeDisplacementMap {
            base: PrimitiveWithInput::new::<Self>(),
            in2: None,
            scale: 0.0,
            x_channel_selector: ColorChannel::A,
            y_channel_selector: ColorChannel::A,
        }
    }
}

impl NodeTrait for FeDisplacementMap {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "in2") => self.in2 = Some(attr.parse_to_parse_error(value)?),
                expanded_name!(svg "scale") => self.scale = attr.parse(value)?,

                expanded_name!(svg "xChannelSelector") => {
                    self.x_channel_selector = attr.parse(value)?
                }

                expanded_name!(svg "yChannelSelector") => {
                    self.y_channel_selector = attr.parse(value)?
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeDisplacementMap {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let displacement_input = ctx.get_input(draw_ctx, self.in2.as_ref())?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .add_input(&displacement_input)
            .into_irect(draw_ctx);

        // Displacement map's values need to be non-premultiplied.
        let displacement_surface = displacement_input.surface().unpremultiply(bounds)?;

        let (sx, sy) = ctx.paffine().transform_distance(self.scale, self.scale);

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        {
            let cr = cairo::Context::new(&output_surface);

            for (x, y, displacement_pixel) in Pixels::new(&displacement_surface, bounds) {
                let get_value = |channel| match channel {
                    ColorChannel::R => displacement_pixel.r,
                    ColorChannel::G => displacement_pixel.g,
                    ColorChannel::B => displacement_pixel.b,
                    ColorChannel::A => displacement_pixel.a,
                };

                let process = |x| f64::from(x) / 255.0 - 0.5;

                let dx = process(get_value(self.x_channel_selector));
                let dy = process(get_value(self.y_channel_selector));

                let x = f64::from(x);
                let y = f64::from(y);
                let ox = sx * dx;
                let oy = sy * dy;

                // Doing this in a loop doesn't look too bad performance wise, and allows not to
                // manually implement bilinear or other interpolation.
                cr.rectangle(x, y, 1.0, 1.0);
                cr.reset_clip();
                cr.clip();

                input.surface().set_as_source_surface(&cr, -ox, -oy);
                cr.paint();
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        // Performance TODO: this converts in back and forth to linear RGB while technically it's
        // only needed for in2.
        true
    }
}

impl Parse for ColorChannel {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ColorChannel, ValueErrorKind> {
        parse_identifiers!(
            parser,
            "R" => ColorChannel::R,
            "G" => ColorChannel::G,
            "B" => ColorChannel::B,
            "A" => ColorChannel::A,
        )
        .map_err(|_| ValueErrorKind::parse_error("parse error"))
    }
}
<commit_msg>Convert ColorChannel to CssParseError<commit_after>use cairo::{self, ImageSurface};
use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::{ParseToParseError, ParseValueToParseError};
use crate::property_bag::PropertyBag;
use crate::surface_utils::{iterators::Pixels, shared_surface::SharedImageSurface};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, PrimitiveWithInput};

/// Enumeration of the color channels the displacement map can source.
#[derive(Clone, Copy)]
enum ColorChannel {
    R,
    G,
    B,
    A,
}

/// The `feDisplacementMap` filter primitive.
pub struct FeDisplacementMap {
    base: PrimitiveWithInput,
    in2: Option<Input>,
    scale: f64,
    x_channel_selector: ColorChannel,
    y_channel_selector: ColorChannel,
}

impl Default for FeDisplacementMap {
    /// Constructs a new `DisplacementMap` with empty properties.
    #[inline]
    fn default() -> FeDisplacementMap {
        FeDisplacementMap {
            base: PrimitiveWithInput::new::<Self>(),
            in2: None,
            scale: 0.0,
            x_channel_selector: ColorChannel::A,
            y_channel_selector: ColorChannel::A,
        }
    }
}

impl NodeTrait for FeDisplacementMap {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "in2") => self.in2 = Some(attr.parse_to_parse_error(value)?),
                expanded_name!(svg "scale") => self.scale = attr.parse_to_parse_error(value)?,

                expanded_name!(svg "xChannelSelector") => {
                    self.x_channel_selector = attr.parse_to_parse_error(value)?
                }

                expanded_name!(svg "yChannelSelector") => {
                    self.y_channel_selector = attr.parse_to_parse_error(value)?
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeDisplacementMap {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let displacement_input = ctx.get_input(draw_ctx, self.in2.as_ref())?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .add_input(&displacement_input)
            .into_irect(draw_ctx);

        // Displacement map's values need to be non-premultiplied.
        let displacement_surface = displacement_input.surface().unpremultiply(bounds)?;

        let (sx, sy) = ctx.paffine().transform_distance(self.scale, self.scale);

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        {
            let cr = cairo::Context::new(&output_surface);

            for (x, y, displacement_pixel) in Pixels::new(&displacement_surface, bounds) {
                let get_value = |channel| match channel {
                    ColorChannel::R => displacement_pixel.r,
                    ColorChannel::G => displacement_pixel.g,
                    ColorChannel::B => displacement_pixel.b,
                    ColorChannel::A => displacement_pixel.a,
                };

                let process = |x| f64::from(x) / 255.0 - 0.5;

                let dx = process(get_value(self.x_channel_selector));
                let dy = process(get_value(self.y_channel_selector));

                let x = f64::from(x);
                let y = f64::from(y);
                let ox = sx * dx;
                let oy = sy * dy;

                // Doing this in a loop doesn't look too bad performance wise, and allows not to
                // manually implement bilinear or other interpolation.
                cr.rectangle(x, y, 1.0, 1.0);
                cr.reset_clip();
                cr.clip();

                input.surface().set_as_source_surface(&cr, -ox, -oy);
                cr.paint();
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        // Performance TODO: this converts in back and forth to linear RGB while technically it's
        // only needed for in2.
        true
    }
}

impl ParseToParseError for ColorChannel {
    fn parse_to_parse_error<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, CssParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "R" => ColorChannel::R,
            "G" => ColorChannel::G,
            "B" => ColorChannel::B,
            "A" => ColorChannel::A,
        )?)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod reply_markup;

use serde::de::DeserializeOwned;
use serde::ser::{Serialize, Serializer, Error};
use serde_json::{Value, to_value};

use types::*;

pub use self::reply_markup::*;

/// This trait represent how to parse response from the Telegram server.
pub trait Response {
    /// Response from the Telegram server.
    type Raw: DeserializeOwned;
    /// Response that should be returned.
    type Type;

    /// Map `Raw` to `Type`.
    fn map(Self::Raw) -> Self::Type;
}

/// Read `T` from the Telegram server and returns the same type.
pub struct IdResponse<T> {
    phantom: ::std::marker::PhantomData<T>
}

impl<T: DeserializeOwned> Response for IdResponse<T> {
    type Raw = T;
    type Type = T;

    fn map(value: Self::Raw) -> Self::Type {
        value
    }
}

/// Read `True` from the Telegram server and returns `()`.
pub struct TrueToUnitResponse;

impl Response for TrueToUnitResponse {
    type Raw = True;
    type Type = ();

    fn map(_: Self::Raw) -> Self::Type {
        ()
    }
}

/// Request corresponds to the specific Telegram API method.
pub trait Request: Serialize {
    /// How to parse response from the Telegram server.
    type Response: Response + Send + 'static;

    /// Name of the method.
    fn name(&self) -> &'static str;

    /// Detach request from lifetime bounds, so it can be transferred across thread boundaries.
    fn detach(&self) -> DetachedRequest<Self::Response> {
        DetachedRequest {
            name: self.name(),
            encoded: to_value(self).map_err(|err| format!("{}", err)),
            phantom: ::std::marker::PhantomData,
        }
    }
}

impl<'a, Req: Request> Request for &'a Req {
    type Response = Req::Response;

    fn name(&self) -> &'static str {
        (*self).name()
    }
}

impl<'a, Req: Request> Request for &'a mut Req {
    type Response = Req::Response;

    fn name(&self) -> &'static str {
        (**self).name()
    }
}

/// Partially serialized request.
pub struct DetachedRequest<Resp> {
    name: &'static str,
    encoded: Result<Value, String>,
    phantom: ::std::marker::PhantomData<Resp>,
}

impl<Resp: Response + Send + 'static> Request for DetachedRequest<Resp> {
    type Response = Resp;

    fn name(&self) -> &'static str {
        self.name
    }
}

impl<Resp> Serialize for DetachedRequest<Resp> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {

        match self.encoded {
            Ok(ref value) => value.serialize(serializer),
            Err(ref err) => Err(S::Error::custom(err)),
        }
    }
}

/// Use this trait to convert a complex type to corresponding request and send it to the chat.
pub trait ToRequest<'b> {
    /// Request type.
    type Request: Request;

    /// Convert type to request and send it to the chat.
    fn to_request<C>(&'b self, chat: C) -> Self::Request where C: ToChatRef;
}

/// Use this trait to convert a complex type to corresponding request and reply to the message.
pub trait ToReplyRequest<'b> {
    /// Request type.
    type Request: Request;

    /// Convert type to request and reply to the message.
    fn to_reply_request<M>(&'b self, message: M) -> Self::Request
        where M: ToMessageId + ToSourceChat;
}

/// Strongly typed ParseMode.
/// See [documentation](https://core.telegram.org/bots/api#formatting-options) for details.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize)]
pub enum ParseMode {
    /// Use markdown formatting.
    Markdown,
    /// Use HTML formatting.
    #[serde(rename = "HTML")]
    Html,
}
<commit_msg>refactor: avoid deprecated anonymous parameter<commit_after>#[macro_use]
pub mod reply_markup;

use serde::de::DeserializeOwned;
use serde::ser::{Serialize, Serializer, Error};
use serde_json::{Value, to_value};

use types::*;

pub use self::reply_markup::*;

/// This trait represent how to parse response from the Telegram server.
pub trait Response {
    /// Response from the Telegram server.
    type Raw: DeserializeOwned;
    /// Response that should be returned.
    type Type;

    /// Map `Raw` to `Type`.
    fn map(raw: Self::Raw) -> Self::Type;
}

/// Read `T` from the Telegram server and returns the same type.
pub struct IdResponse<T> {
    phantom: ::std::marker::PhantomData<T>
}

impl<T: DeserializeOwned> Response for IdResponse<T> {
    type Raw = T;
    type Type = T;

    fn map(raw: Self::Raw) -> Self::Type {
        raw
    }
}

/// Read `True` from the Telegram server and returns `()`.
pub struct TrueToUnitResponse;

impl Response for TrueToUnitResponse {
    type Raw = True;
    type Type = ();

    fn map(_: Self::Raw) -> Self::Type {
        ()
    }
}

/// Request corresponds to the specific Telegram API method.
pub trait Request: Serialize {
    /// How to parse response from the Telegram server.
    type Response: Response + Send + 'static;

    /// Name of the method.
    fn name(&self) -> &'static str;

    /// Detach request from lifetime bounds, so it can be transferred across thread boundaries.
    fn detach(&self) -> DetachedRequest<Self::Response> {
        DetachedRequest {
            name: self.name(),
            encoded: to_value(self).map_err(|err| format!("{}", err)),
            phantom: ::std::marker::PhantomData,
        }
    }
}

impl<'a, Req: Request> Request for &'a Req {
    type Response = Req::Response;

    fn name(&self) -> &'static str {
        (*self).name()
    }
}

impl<'a, Req: Request> Request for &'a mut Req {
    type Response = Req::Response;

    fn name(&self) -> &'static str {
        (**self).name()
    }
}

/// Partially serialized request.
pub struct DetachedRequest<Resp> {
    name: &'static str,
    encoded: Result<Value, String>,
    phantom: ::std::marker::PhantomData<Resp>,
}

impl<Resp: Response + Send + 'static> Request for DetachedRequest<Resp> {
    type Response = Resp;

    fn name(&self) -> &'static str {
        self.name
    }
}

impl<Resp> Serialize for DetachedRequest<Resp> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {

        match self.encoded {
            Ok(ref value) => value.serialize(serializer),
            Err(ref err) => Err(S::Error::custom(err)),
        }
    }
}

/// Use this trait to convert a complex type to corresponding request and send it to the chat.
pub trait ToRequest<'b> {
    /// Request type.
    type Request: Request;

    /// Convert type to request and send it to the chat.
    fn to_request<C>(&'b self, chat: C) -> Self::Request where C: ToChatRef;
}

/// Use this trait to convert a complex type to corresponding request and reply to the message.
pub trait ToReplyRequest<'b> {
    /// Request type.
    type Request: Request;

    /// Convert type to request and reply to the message.
    fn to_reply_request<M>(&'b self, message: M) -> Self::Request
        where M: ToMessageId + ToSourceChat;
}

/// Strongly typed ParseMode.
/// See [documentation](https://core.telegram.org/bots/api#formatting-options) for details.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize)]
pub enum ParseMode {
    /// Use markdown formatting.
    Markdown,
    /// Use HTML formatting.
    #[serde(rename = "HTML")]
    Html,
}
<|endoftext|>