<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.

//! Readers and Writers for in-memory buffers
//!
//! # XXX
//!
//! * Should probably have something like this for strings.
//! * Should they implement Closable? Would take extra state.

use cmp::min;
use prelude::*;
use super::*;
use vec;

/// Writes to an owned, growable byte vector
pub struct MemWriter {
    priv buf: ~[u8],
    priv pos: uint,
}

impl MemWriter {
    pub fn new() -> MemWriter {
        MemWriter { buf: vec::with_capacity(128), pos: 0 }
    }
}

impl Writer for MemWriter {
    fn write(&mut self, buf: &[u8]) {
        // Make sure the internal buffer is as least as big as where we
        // currently are
        let difference = self.pos as i64 - self.buf.len() as i64;
        if difference > 0 {
            self.buf.grow(difference as uint, &0);
        }

        // Figure out what bytes will be used to overwrite what's currently
        // there (left), and what will be appended on the end (right)
        let cap = self.buf.len() - self.pos;
        let (left, right) = if cap <= buf.len() {
            (buf.slice_to(cap), buf.slice_from(cap))
        } else {
            (buf, &[])
        };

        // Do the necessary writes
        if left.len() > 0 {
            vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos),
                                    left, left.len());
        }
        if right.len() > 0 {
            self.buf.push_all(right);
        }

        // Bump us forward
        self.pos += buf.len();
    }
}

impl Seek for MemWriter {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, pos: i64, style: SeekStyle) {
        match style {
            SeekSet => { self.pos = pos as uint; }
            SeekEnd => { self.pos = self.buf.len() + pos as uint; }
            SeekCur => { self.pos += pos as uint; }
        }
    }
}

impl Decorator<~[u8]> for MemWriter {
    fn inner(self) -> ~[u8] { self.buf }
    fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf }
    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf }
}

/// Reads from an owned byte vector
pub struct MemReader {
    priv buf: ~[u8],
    priv pos: uint
}

impl MemReader {
    pub fn new(buf: ~[u8]) -> MemReader {
        MemReader {
            buf: buf,
            pos: 0
        }
    }
}

impl Reader for MemReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
    }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl Seek for MemReader {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

impl Decorator<~[u8]> for MemReader {

    fn inner(self) -> ~[u8] {
        match self {
            MemReader { buf: buf, _ } => buf
        }
    }

    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
        match *self {
            MemReader { buf: ref buf, _ } => buf
        }
    }

    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
        match *self {
            MemReader { buf: ref mut buf, _ } => buf
        }
    }
}

/// Writes to a fixed-size byte slice
pub struct BufWriter<'self> {
    priv buf: &'self mut [u8],
    priv pos: uint
}

impl<'self> BufWriter<'self> {
    pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> {
        BufWriter {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Writer for BufWriter<'self> {
    fn write(&mut self, _buf: &[u8]) { fail!() }

    fn flush(&mut self) { fail!() }
}

impl<'self> Seek for BufWriter<'self> {
    fn tell(&self) -> u64 { fail!() }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

/// Reads from a fixed-size byte slice
pub struct BufReader<'self> {
    priv buf: &'self [u8],
    priv pos: uint
}

impl<'self> BufReader<'self> {
    pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> {
        BufReader {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Reader for BufReader<'self> {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
     }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl<'self> Seek for BufReader<'self> {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

///Calls a function with a MemWriter and returns
///the writer's stored vector.
pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
    let mut writer = MemWriter::new();
    writeFn(&mut writer);
    writer.inner()
}

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

    #[test]
    fn test_mem_writer() {
        let mut writer = MemWriter::new();
        assert_eq!(writer.tell(), 0);
        writer.write([0]);
        assert_eq!(writer.tell(), 1);
        writer.write([1, 2, 3]);
        writer.write([4, 5, 6, 7]);
        assert_eq!(writer.tell(), 8);
        assert_eq!(*writer.inner_ref(), ~[0, 1, 2, 3, 4, 5, 6, 7]);

        writer.seek(0, SeekSet);
        assert_eq!(writer.tell(), 0);
        writer.write([3, 4]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 3, 4, 5, 6, 7]);

        writer.seek(1, SeekCur);
        writer.write([0, 1]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 7]);

        writer.seek(-1, SeekEnd);
        writer.write([1, 2]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2]);

        writer.seek(1, SeekEnd);
        writer.write([1]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
    }

    #[test]
    fn test_mem_reader() {
        let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_buf_reader() {
        let in_buf = ~[0, 1, 2, 3, 4, 5, 6, 7];
        let mut reader = BufReader::new(in_buf);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_with_mem_writer() {
        let buf = with_mem_writer(|wr| wr.write([1,2,3,4,5,6,7]));
        assert_eq!(buf, ~[1,2,3,4,5,6,7]);
    }
}
<commit_msg>auto merge of #10451 : zkamsler/rust/buf_writer, r=alexcrichton<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.

//! Readers and Writers for in-memory buffers
//!
//! # XXX
//!
//! * Should probably have something like this for strings.
//! * Should they implement Closable? Would take extra state.
use cmp::max;
use cmp::min;
use prelude::*;
use super::*;
use vec;

/// Writes to an owned, growable byte vector
pub struct MemWriter {
    priv buf: ~[u8],
    priv pos: uint,
}

impl MemWriter {
    pub fn new() -> MemWriter {
        MemWriter { buf: vec::with_capacity(128), pos: 0 }
    }
}

impl Writer for MemWriter {
    fn write(&mut self, buf: &[u8]) {
        // Make sure the internal buffer is as least as big as where we
        // currently are
        let difference = self.pos as i64 - self.buf.len() as i64;
        if difference > 0 {
            self.buf.grow(difference as uint, &0);
        }

        // Figure out what bytes will be used to overwrite what's currently
        // there (left), and what will be appended on the end (right)
        let cap = self.buf.len() - self.pos;
        let (left, right) = if cap <= buf.len() {
            (buf.slice_to(cap), buf.slice_from(cap))
        } else {
            (buf, &[])
        };

        // Do the necessary writes
        if left.len() > 0 {
            vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos),
                                    left, left.len());
        }
        if right.len() > 0 {
            self.buf.push_all(right);
        }

        // Bump us forward
        self.pos += buf.len();
    }
}

// FIXME(#10432)
impl Seek for MemWriter {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, pos: i64, style: SeekStyle) {
        // compute offset as signed and clamp to prevent overflow
        let offset = match style {
            SeekSet => { 0 }
            SeekEnd => { self.buf.len() }
            SeekCur => { self.pos }
        } as i64;

        self.pos = max(0, offset+pos) as uint;
    }
}

impl Decorator<~[u8]> for MemWriter {
    fn inner(self) -> ~[u8] { self.buf }
    fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf }
    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf }
}

/// Reads from an owned byte vector
pub struct MemReader {
    priv buf: ~[u8],
    priv pos: uint
}

impl MemReader {
    pub fn new(buf: ~[u8]) -> MemReader {
        MemReader {
            buf: buf,
            pos: 0
        }
    }
}

impl Reader for MemReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
    }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl Seek for MemReader {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

impl Decorator<~[u8]> for MemReader {

    fn inner(self) -> ~[u8] {
        match self {
            MemReader { buf: buf, _ } => buf
        }
    }

    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
        match *self {
            MemReader { buf: ref buf, _ } => buf
        }
    }

    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
        match *self {
            MemReader { buf: ref mut buf, _ } => buf
        }
    }
}

/// Writes to a fixed-size byte slice
///
/// If a write will not fit in the buffer, it raises the `io_error`
/// condition and does not write any data.
pub struct BufWriter<'self> {
    priv buf: &'self mut [u8],
    priv pos: uint
}

impl<'self> BufWriter<'self> {
    pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> {
        BufWriter {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Writer for BufWriter<'self> {
    fn write(&mut self, buf: &[u8]) {
        // raises a condition if the entire write does not fit in the buffer
        let max_size = self.buf.len();
        if self.pos >= max_size || (self.pos + buf.len()) > max_size {
            io_error::cond.raise(IoError {
                kind: OtherIoError,
                desc: "Trying to write past end of buffer",
                detail: None
            });
            return;
        }

        vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos),
                                buf, buf.len());
        self.pos += buf.len();
    }
}

// FIXME(#10432)
impl<'self> Seek for BufWriter<'self> {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, pos: i64, style: SeekStyle) {
        // compute offset as signed and clamp to prevent overflow
        let offset = match style {
            SeekSet => { 0 }
            SeekEnd => { self.buf.len() }
            SeekCur => { self.pos }
        } as i64;

        self.pos = max(0, offset+pos) as uint;
    }
}

/// Reads from a fixed-size byte slice
pub struct BufReader<'self> {
    priv buf: &'self [u8],
    priv pos: uint
}

impl<'self> BufReader<'self> {
    pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> {
        BufReader {
            buf: buf,
            pos: 0
        }
    }
}

impl<'self> Reader for BufReader<'self> {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        { if self.eof() { return None; } }

        let write_len = min(buf.len(), self.buf.len() - self.pos);
        {
            let input = self.buf.slice(self.pos, self.pos + write_len);
            let output = buf.mut_slice(0, write_len);
            assert_eq!(input.len(), output.len());
            vec::bytes::copy_memory(output, input, write_len);
        }
        self.pos += write_len;
        assert!(self.pos <= self.buf.len());

        return Some(write_len);
     }

    fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}

impl<'self> Seek for BufReader<'self> {
    fn tell(&self) -> u64 { self.pos as u64 }

    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}

///Calls a function with a MemWriter and returns
///the writer's stored vector.
pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
    let mut writer = MemWriter::new();
    writeFn(&mut writer);
    writer.inner()
}

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

    #[test]
    fn test_mem_writer() {
        let mut writer = MemWriter::new();
        assert_eq!(writer.tell(), 0);
        writer.write([0]);
        assert_eq!(writer.tell(), 1);
        writer.write([1, 2, 3]);
        writer.write([4, 5, 6, 7]);
        assert_eq!(writer.tell(), 8);
        assert_eq!(*writer.inner_ref(), ~[0, 1, 2, 3, 4, 5, 6, 7]);

        writer.seek(0, SeekSet);
        assert_eq!(writer.tell(), 0);
        writer.write([3, 4]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 3, 4, 5, 6, 7]);

        writer.seek(1, SeekCur);
        writer.write([0, 1]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 7]);

        writer.seek(-1, SeekEnd);
        writer.write([1, 2]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2]);

        writer.seek(1, SeekEnd);
        writer.write([1]);
        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
    }

    #[test]
    fn test_buf_writer() {
        let mut buf = [0 as u8, ..8];
        {
            let mut writer = BufWriter::new(buf);
            assert_eq!(writer.tell(), 0);
            writer.write([0]);
            assert_eq!(writer.tell(), 1);
            writer.write([1, 2, 3]);
            writer.write([4, 5, 6, 7]);
            assert_eq!(writer.tell(), 8);
        }
        assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]);
    }

    #[test]
    fn test_buf_writer_seek() {
        let mut buf = [0 as u8, ..8];
        {
            let mut writer = BufWriter::new(buf);
            assert_eq!(writer.tell(), 0);
            writer.write([1]);
            assert_eq!(writer.tell(), 1);

            writer.seek(2, SeekSet);
            assert_eq!(writer.tell(), 2);
            writer.write([2]);
            assert_eq!(writer.tell(), 3);

            writer.seek(-2, SeekCur);
            assert_eq!(writer.tell(), 1);
            writer.write([3]);
            assert_eq!(writer.tell(), 2);

            writer.seek(-1, SeekEnd);
            assert_eq!(writer.tell(), 7);
            writer.write([4]);
            assert_eq!(writer.tell(), 8);

        }
        assert_eq!(buf, [1, 3, 2, 0, 0, 0, 0, 4]);
    }

    #[test]
    fn test_buf_writer_error() {
        let mut buf = [0 as u8, ..2];
        let mut writer = BufWriter::new(buf);
        writer.write([0]);

        let mut called = false;
        do io_error::cond.trap(|err| {
            assert_eq!(err.kind, OtherIoError);
            called = true;
        }).inside {
            writer.write([0, 0]);
        }
        assert!(called);
    }

    #[test]
    fn test_mem_reader() {
        let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_buf_reader() {
        let in_buf = ~[0, 1, 2, 3, 4, 5, 6, 7];
        let mut reader = BufReader::new(in_buf);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }

    #[test]
    fn test_with_mem_writer() {
        let buf = with_mem_writer(|wr| wr.write([1,2,3,4,5,6,7]));
        assert_eq!(buf, ~[1,2,3,4,5,6,7]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-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 parser and macro expander.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "syntax"]
#![unstable(feature = "rustc_private")]
#![staged_api]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]

#![feature(associated_consts)]
#![feature(bitset)]
#![feature(copy_lifetime)]
#![feature(drain)]
#![feature(filling_drop)]
#![feature(libc)]
#![feature(ref_slice)]
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
#![feature(str_char)]
#![feature(str_escape)]
#![feature(unicode)]
#![feature(vec_push_all)]

extern crate fmt_macros;
extern crate serialize;
extern crate term;
extern crate libc;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving

// A variant of 'try!' that panics on Err(FatalError). This is used as a
// crutch on the way towards a non-panic!-prone parser. It should be used
// for fatal parsing errors; eventually we plan to convert all code using
// panictry to just use normal try
macro_rules! panictry {
    ($e:expr) => ({
        use std::result::Result::{Ok, Err};
        use diagnostic::FatalError;
        match $e {
            Ok(e) => e,
            Err(FatalError) => panic!(FatalError)
        }
    })
}

pub mod util {
    pub mod interner;
    #[cfg(test)]
    pub mod parser_testing;
    pub mod small_vector;
}

pub mod diagnostics {
    pub mod macros;
    pub mod plugin;
    pub mod registry;
    pub mod metadata;
}

pub mod syntax {
    pub use ext;
    pub use parse;
    pub use ast;
}

pub mod abi;
pub mod ast;
pub mod ast_util;
pub mod attr;
pub mod codemap;
pub mod config;
pub mod diagnostic;
pub mod feature_gate;
pub mod fold;
pub mod owned_slice;
pub mod parse;
pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub mod test;
pub mod visit;

pub mod print {
    pub mod pp;
    pub mod pprust;
}

pub mod ext {
    pub mod asm;
    pub mod base;
    pub mod build;
    pub mod cfg;
    pub mod concat;
    pub mod concat_idents;
    pub mod deriving;
    pub mod env;
    pub mod expand;
    pub mod format;
    pub mod log_syntax;
    pub mod mtwt;
    pub mod quote;
    pub mod pushpop_safe;
    pub mod source_util;
    pub mod trace_macros;

    pub mod tt {
        pub mod transcribe;
        pub mod macro_parser;
        pub mod macro_rules;
    }
}
<commit_msg>Remove unused feature<commit_after>// Copyright 2012-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 parser and macro expander.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "syntax"]
#![unstable(feature = "rustc_private")]
#![staged_api]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]

#![feature(associated_consts)]
#![feature(bitset)]
#![feature(drain)]
#![feature(filling_drop)]
#![feature(libc)]
#![feature(ref_slice)]
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
#![feature(str_char)]
#![feature(str_escape)]
#![feature(unicode)]
#![feature(vec_push_all)]

extern crate fmt_macros;
extern crate serialize;
extern crate term;
extern crate libc;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving

// A variant of 'try!' that panics on Err(FatalError). This is used as a
// crutch on the way towards a non-panic!-prone parser. It should be used
// for fatal parsing errors; eventually we plan to convert all code using
// panictry to just use normal try
macro_rules! panictry {
    ($e:expr) => ({
        use std::result::Result::{Ok, Err};
        use diagnostic::FatalError;
        match $e {
            Ok(e) => e,
            Err(FatalError) => panic!(FatalError)
        }
    })
}

pub mod util {
    pub mod interner;
    #[cfg(test)]
    pub mod parser_testing;
    pub mod small_vector;
}

pub mod diagnostics {
    pub mod macros;
    pub mod plugin;
    pub mod registry;
    pub mod metadata;
}

pub mod syntax {
    pub use ext;
    pub use parse;
    pub use ast;
}

pub mod abi;
pub mod ast;
pub mod ast_util;
pub mod attr;
pub mod codemap;
pub mod config;
pub mod diagnostic;
pub mod feature_gate;
pub mod fold;
pub mod owned_slice;
pub mod parse;
pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub mod test;
pub mod visit;

pub mod print {
    pub mod pp;
    pub mod pprust;
}

pub mod ext {
    pub mod asm;
    pub mod base;
    pub mod build;
    pub mod cfg;
    pub mod concat;
    pub mod concat_idents;
    pub mod deriving;
    pub mod env;
    pub mod expand;
    pub mod format;
    pub mod log_syntax;
    pub mod mtwt;
    pub mod quote;
    pub mod pushpop_safe;
    pub mod source_util;
    pub mod trace_macros;

    pub mod tt {
        pub mod transcribe;
        pub mod macro_parser;
        pub mod macro_rules;
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, TryIter};
use std::thread;

use super::iokit::*;
use core_foundation_sys::base::*;
use core_foundation_sys::runloop::*;
use runloop::RunLoop;

extern crate libc;
use libc::c_void;

extern crate mach;
use mach::kern_return::KERN_SUCCESS;

pub struct IOHIDDeviceID {
    pub device_id: u64 // TODO: Does this work on non-64-bit systems?
}

impl IOHIDDeviceID {
    pub fn from_ref(device_ref: IOHIDDeviceRef) -> IOHIDDeviceID {
        IOHIDDeviceID{ device_id: device_ref as u64 }
    }

    pub fn as_ref(&self) -> IOHIDDeviceRef {
        self.device_id as IOHIDDeviceRef
    }
}

pub enum Event {
    Add { device_id: IOHIDDeviceID },
    Remove { device_id: IOHIDDeviceID },
}

pub struct Monitor {
    // Receive events from the thread.
    rx: Receiver<Event>,
    // Handle to the thread loop.
    thread: RunLoop
}

impl Monitor {
    pub fn new() -> io::Result<Self> {
        let (tx, rx) = channel();

        let thread = RunLoop::new(move |alive| {
            let (removal_tx, removal_rx) = channel::<IOHIDDeviceRef>();
            let (added_tx, added_rx) = channel::<IOHIDDeviceRef>();

            let hid_manager = unsafe {
                let hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
                IOHIDManagerSetDeviceMatching(hid_manager, ptr::null());
                if IOHIDManagerOpen(hid_manager, kIOHIDManagerOptionNone) != KERN_SUCCESS {
                    panic!("Couldn't open a HID Manager");
                }
                hid_manager
            };

            let boxed_added_tx = Box::new(added_tx);
            let added_tx_ptr = Box::into_raw(boxed_added_tx) as *mut libc::c_void;
            let boxed_removal_tx = Box::new(removal_tx);
            let removal_tx_ptr = Box::into_raw(boxed_removal_tx) as *mut libc::c_void;

            unsafe {
                IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, device_register_cb, removal_tx_ptr);
                IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, device_register_cb, added_tx_ptr);
                IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
            }

            // Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input reports into the
            // various call
            while alive() {
                println!("Run loop running, handle={:?}", thread::current());

                for device_ref in added_rx.try_iter() {
                    tx.send(Event::Add { device_id: IOHIDDeviceID::from_ref(device_ref) }).unwrap();
                }
                for device_ref in removal_rx.try_iter() {
                    tx.send(Event::Remove { device_id: IOHIDDeviceID::from_ref(device_ref) }).unwrap();
                }

                if unsafe { CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, 0) } == kCFRunLoopRunStopped {
                    println!("Device stopped.");
                    // TODO: drop the removal_tx_ptr
                    break;
                }
            }

            if unsafe { IOHIDManagerClose(hid_manager, kIOHIDManagerOptionNone) } != KERN_SUCCESS {
                panic!("Couldn't close the HID Manager");
            }

            Ok(())
        }, 0 /* no timeout */)?;

        Ok(Self { rx, thread })
    }

    pub fn events<'a>(&'a self) -> TryIter<'a, Event> {
        self.rx.try_iter()
    }

    // This might block.
    pub fn stop(&mut self) {
        self.thread.cancel();
    }
}

// This is called from the RunLoop thread
extern "C" fn device_register_cb(context: *mut c_void,
                                 result: IOReturn,
                                 _: *mut c_void,
                                 device: IOHIDDeviceRef) {
    unsafe {
        let tx: &mut Sender<IOHIDDeviceRef> = &mut *(context as *mut Sender<IOHIDDeviceRef>);

        // context contains a Device which we populate as the out variable
        // let device: &mut Device = &mut *(context as *mut Device);

        // let device_ref = void_ref as IOHIDDeviceRef;
        println!("{:?} device_register_cb context={:?} result={:?} device_ref={:?}",
                 thread::current(), context, result, device);

        if let Err(e) = tx.send(device) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            println!("Problem returning device_register_cb data for thread: {}", e);
        };
    }
}
<commit_msg>Speed up and simplify communication in macOS HID device monitor<commit_after>use std::io;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, TryIter};
use std::thread;

use super::iokit::*;
use core_foundation_sys::base::*;
use core_foundation_sys::runloop::*;
use runloop::RunLoop;

extern crate libc;
use libc::c_void;

extern crate mach;
use mach::kern_return::KERN_SUCCESS;

pub struct IOHIDDeviceID {
    pub device_id: u64 // TODO: Does this work on non-64-bit systems?
}

impl IOHIDDeviceID {
    pub fn from_ref(device_ref: IOHIDDeviceRef) -> IOHIDDeviceID {
        IOHIDDeviceID{ device_id: device_ref as u64 }
    }

    pub fn as_ref(&self) -> IOHIDDeviceRef {
        self.device_id as IOHIDDeviceRef
    }
}

pub enum Event {
    Add { device_id: IOHIDDeviceID },
    Remove { device_id: IOHIDDeviceID },
}

struct IOHIDManager {
    manager: IOHIDManagerRef
}

impl IOHIDManager {
    pub fn new(tx_ptr: *mut libc::c_void) -> io::Result<Self> {
        let manager = unsafe { IOHIDManagerCreate(kCFAllocatorDefault,
                                                  kIOHIDManagerOptionNone) };

        // TODO we should probably set up proper device matching
        unsafe { IOHIDManagerSetDeviceMatching(manager, ptr::null()) };

        if unsafe { IOHIDManagerOpen(manager, kIOHIDManagerOptionNone) } != KERN_SUCCESS {
            return Err(io::Error::new(io::ErrorKind::Other, "Couldn't open HID Manager"));
        }

        unsafe {
            IOHIDManagerRegisterDeviceMatchingCallback(
                manager, IOHIDManager::device_add_cb, tx_ptr);
            IOHIDManagerRegisterDeviceRemovalCallback(
                manager, IOHIDManager::device_remove_cb, tx_ptr);
            IOHIDManagerScheduleWithRunLoop(
                manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
        }

        Ok(Self { manager })
    }

    extern "C" fn device_add_cb(context: *mut c_void, _: IOReturn,
                                _: *mut c_void, device: IOHIDDeviceRef) {
        let tx = unsafe { &*(context as *mut Sender<Event>) };
        IOHIDManager::send_device_event(tx, Event::Add {
            device_id: IOHIDDeviceID::from_ref(device)
        });
    }

    extern "C" fn device_remove_cb(context: *mut c_void, _: IOReturn,
                                   _: *mut c_void, device: IOHIDDeviceRef) {
        let tx = unsafe { &*(context as *mut Sender<Event>) };
        IOHIDManager::send_device_event(tx, Event::Remove {
            device_id: IOHIDDeviceID::from_ref(device)
        });
    }

    fn send_device_event(tx: &Sender<Event>, event: Event) {
        if let Err(e) = tx.send(event) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            println!("Problem returning device_register_cb data for thread: {}", e);
        }
    }
}

impl Drop for IOHIDManager {
    fn drop(&mut self) {
        if unsafe { IOHIDManagerClose(self.manager, kIOHIDManagerOptionNone) } != KERN_SUCCESS {
            println!("Couldn't close the HID Manager");
        }
    }
}

pub struct Monitor {
    // Receive events from the thread.
    rx: Receiver<Event>,
    // Handle to the thread loop.
    thread: RunLoop
}

impl Monitor {
    pub fn new() -> io::Result<Self> {
        let (tx, rx) = channel();

        let thread = RunLoop::new(move |alive| {
            let tx_box = Box::new(tx);
            let tx_ptr = Box::into_raw(tx_box) as *mut libc::c_void;

            // This will keep `tx` alive only for the scope.
            let _tx = unsafe { Box::from_raw(tx_ptr) };

            // Create and initialize a scoped HID manager.
            let _manager = IOHIDManager::new(tx_ptr)?;

            // Run the Event Loop. CFRunLoopRunInMode() will dispatch HID
            // input reports into the various callbacks
            while alive() {
                println!("Run loop running, handle={:?}", thread::current());

                if unsafe { CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, 0) } == kCFRunLoopRunStopped {
                    println!("Device stopped.");
                    break;
                }
            }

            Ok(())
        }, 0 /* no timeout */)?;

        Ok(Self { rx, thread })
    }

    pub fn events<'a>(&'a self) -> TryIter<'a, Event> {
        self.rx.try_iter()
    }

    // This might block.
    pub fn stop(&mut self) {
        self.thread.cancel();
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(std_misc)]
#![feature(fs)]
#![feature(io)]
#![feature(process)]

//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::str;
use std::io::Read;
use std::fs::File;
use std::sync::{Once, ONCE_INIT};

static mut OS_TYPE: &'static str = "";
static OS_TYPE_INIT: Once = ONCE_INIT;

static mut OS_RELEASE: &'static str = "";
static OS_RELEASE_INIT: Once = ONCE_INIT;

static mut CPU_NUM: u32 = 0;
static CPU_NUM_INIT: Once = ONCE_INIT;

static mut CPU_SPEED: u64 = 0;
static CPU_SPEED_INIT: Once = ONCE_INIT;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free:  u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached:  u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free:  u64
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64
}

extern {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, String> {
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_TYPE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();  // pop '\n'
                    std::mem::copy_lifetime(OS_TYPE, s.as_slice());
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_TYPE = str::from_utf8(
                        ffi::CStr::from_ptr(get_os_type()).to_bytes()).unwrap();
                }
            });
            Ok(OS_TYPE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, String> {
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_RELEASE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();
                    std::mem::copy_lifetime(OS_RELEASE, s.as_slice());
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_RELEASE = str::from_utf8(
                        ffi::CStr::from_ptr(get_os_release()).to_bytes()).unwrap();
                }
            });
            Ok(OS_RELEASE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, String> {
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_NUM_INIT.call_once(|| {
                CPU_NUM = get_cpu_num();
            });
            Ok(CPU_NUM)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, String> {
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_SPEED_INIT.call_once(|| {
                CPU_SPEED = if cfg!(target_os = "linux") {
                    // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
                    let mut f = File::open("/proc/cpuinfo").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    let mut lines = s.as_slice().split('\n');
                    for _ in 0..7 {
                        lines.next();
                    }
                    let mut words = lines.next().unwrap().split(':');
                    words.next();
                    let s = words.next().unwrap().trim().trim_right_matches('\n');
                    s.parse::<f64>().unwrap() as u64
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    get_cpu_speed()
                } else { 0 };
            });
            Ok(CPU_SPEED)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.as_slice().split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg { one: one, five: five, fifteen: fifteen} )
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.as_slice().splitn(3, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err("Unsupported system".to_string())
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(1, ' ');
    line.next();
    line.next().unwrap().trim_left().split(' ').next().unwrap()
        .parse::<u64>().unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo{ total: total, free: free, avail: avail,
                    buffers: buffers, cached: cached,
                    swap_total: swap_total, swap_free: swap_free})
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, String> {
    if cfg!(target_os = "linux") ||
        cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe { get_disk_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, String> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err("Unsupported system".to_string())
    }
}

<commit_msg>fix static bug on linux<commit_after>#![feature(core)]
#![feature(std_misc)]
#![feature(fs)]
#![feature(io)]
#![feature(process)]

//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::str;
use std::io::Read;
use std::fs::File;
use std::sync::{Once, ONCE_INIT};
use std::mem;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free:  u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached:  u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free:  u64
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64
}

extern {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, String> {
    static mut OS_TYPE: &'static str = "";
    static OS_TYPE_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_TYPE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();  // pop '\n'
                    OS_TYPE = mem::copy_lifetime(OS_TYPE, s.as_slice());
                    mem::forget(s);
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_TYPE = str::from_utf8(ffi::CStr::from_ptr(get_os_type())
                                   .to_bytes()).unwrap()
                }
            });
            Ok(OS_TYPE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, String> {
    static mut OS_RELEASE: &'static str = "";
    static OS_RELEASE_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            OS_RELEASE_INIT.call_once(|| {
                if cfg!(target_os = "linux") {
                    let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    s.pop();
                    OS_RELEASE = std::mem::copy_lifetime(OS_RELEASE, s.as_slice());
                    mem::forget(s);
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    OS_RELEASE = str::from_utf8(
                        ffi::CStr::from_ptr(get_os_release()).to_bytes()).unwrap();
                }
            });
            Ok(OS_RELEASE.to_string())
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, String> {
    static mut CPU_NUM: u32 = 0;
    static CPU_NUM_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_NUM_INIT.call_once(|| {
                CPU_NUM = get_cpu_num();
            });
            Ok(CPU_NUM)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, String> {
    static mut CPU_SPEED: u64 = 0;
    static CPU_SPEED_INIT: Once = ONCE_INIT;
    if cfg!(unix) || cfg!(windows) {
        unsafe {
            CPU_SPEED_INIT.call_once(|| {
                CPU_SPEED = if cfg!(target_os = "linux") {
                    // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
                    let mut f = File::open("/proc/cpuinfo").unwrap();
                    let mut s = String::new();
                    let _ = f.read_to_string(&mut s).unwrap();
                    let mut lines = s.as_slice().split('\n');
                    for _ in 0..7 {
                        lines.next();
                    }
                    let mut words = lines.next().unwrap().split(':');
                    words.next();
                    let s = words.next().unwrap().trim().trim_right_matches('\n');
                    s.parse::<f64>().unwrap() as u64
                } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
                    get_cpu_speed()
                } else { 0 };
            });
            Ok(CPU_SPEED)
        }
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.as_slice().split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg { one: one, five: five, fifteen: fifteen} )
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.as_slice().splitn(3, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err("Unsupported system".to_string())
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(1, ' ');
    line.next();
    line.next().unwrap().trim_left().split(' ').next().unwrap()
        .parse::<u64>().unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo{ total: total, free: free, avail: avail,
                    buffers: buffers, cached: cached,
                    swap_total: swap_total, swap_free: swap_free})
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, String> {
    if cfg!(target_os = "linux") ||
        cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe { get_disk_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, String> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err("Unsupported system".to_string())
    }
}

<|endoftext|>


<commit_before>#!/usr/bin/env rustx

fn main () {
   io::println("Hello!");
}

fn test () {
   assert 2 + 2 == 4;
}

<commit_msg>make _rustx.rs executable so it can be used to demonstrate #! mode<commit_after>#!/usr/bin/env rustx

fn main () {
   io::println("Hello!");
}

fn test () {
   assert 2 + 2 == 4;
}

<|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::Result::{Ok, Err};
    use slice::SliceExt;
    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::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// 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.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[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 { _dummy: () })
        }
    }

    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::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    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 thread::Thread;

    #[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);

            Thread::spawn(move|| {
                // 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();
                Thread::yield_now();
                let mut v = [0u8, .. 1000];

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

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>Revise std::thread API to join by default<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::Result::{Ok, Err};
    use slice::SliceExt;
    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::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// 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.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[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 { _dummy: () })
        }
    }

    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::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    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 thread::Thread;

    #[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);

            Thread::spawn(move|| {
                // 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();
                Thread::yield_now();
                let mut v = [0u8, .. 1000];

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

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


<commit_before>// Implements http://rosettacode.org/wiki/LZW_compression

use std::hashmap::HashMap;
use std::vec;
use std::str;

fn compress(original_str: &str) -> ~[int] {
   let original = original_str.as_bytes();
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(~[i as u8], i);
   }

   let mut result = ~[];
   let mut w:~[u8] = ~[];
   for &c in original.iter() {
      let mut wc = w.clone();
      wc.push(c);

      match dictionary.find(&wc) {
         Some(_) => w = wc,
         None => {
            result.push(*dictionary.get(&w));
            dictionary.insert(wc, dict_size);
            dict_size += 1;
            w = ~[c];
         }
      }
   }

   if w.len() > 0 {
      result.push(*dictionary.get(&w));
   }

   result
}

fn decompress(compressed: &[int]) -> ~str {
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(i, ~[i as u8]);
   }

   let mut w = ~[compressed[0] as u8];
   let compressed = compressed.slice(1, compressed.len());
   let mut result = w.clone();
   for &k in compressed.iter() {
      let entry =
         match dictionary.find(&k) {
            Some(v) => v.clone(),
            None if k == dict_size => vec::append_one(w.clone(), w[0]),
            None => fail!("Invalid compressed string")
         };

      result = vec::append(result, entry);
      dictionary.insert(dict_size, vec::append_one(w, entry[0]));
      dict_size += 1;
      w = entry;
   }

   str::from_utf8(result)
}

fn main() {
   let original = "TOBEORNOTTOBEORTOBEORNOT";
   let compressed = compress(original);

   for &v in compressed.iter() {
      print!("{} ", v);
   }

   let decompressed = decompress(compressed);
   println(decompressed);

   // Check if the decompressed string corresponds to the original string
   assert!(original == decompressed);
}
<commit_msg>Fixed up the lzw to work on the latest master<commit_after>// Implements http://rosettacode.org/wiki/LZW_compression

use std::hashmap::HashMap;
use std::vec;
use std::str;

fn compress(original_str: &str) -> ~[int] {
   let original = original_str.as_bytes();
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(~[i as u8], i);
   }

   let mut result = ~[];
   let mut w:~[u8] = ~[];
   for &c in original.iter() {
      let mut wc = w.clone();
      wc.push(c);

      match dictionary.find(&wc) {
         Some(_) => w = wc,
         None => {
            result.push(*dictionary.get(&w));
            dictionary.insert(wc, dict_size);
            dict_size += 1;
            w = ~[c];
         }
      }
   }

   if w.len() > 0 {
      result.push(*dictionary.get(&w));
   }

   result
}

fn decompress(compressed: &[int]) -> ~str {
   let mut dict_size = 256;
   let mut dictionary = HashMap::new();

   for i in range(0, dict_size) {
      dictionary.insert(i, ~[i as u8]);
   }

   let mut w = ~[compressed[0] as u8];
   let compressed = compressed.slice(1, compressed.len());
   let mut result = w.clone();
   for &k in compressed.iter() {
      let entry =
         match dictionary.find(&k) {
            Some(v) => v.clone(),
            None if k == dict_size => vec::append_one(w.clone(), w[0]),
            None => fail!("Invalid compressed string")
         };

      result = vec::append(result, entry);
      dictionary.insert(dict_size, vec::append_one(w, entry[0]));
      dict_size += 1;
      w = entry;
   }

   str::from_utf8_owned(result)
}

fn main() {
   let original = "TOBEORNOTTOBEORTOBEORNOT";
   let compressed = compress(original);

   for &v in compressed.iter() {
      print!("{} ", v);
   }

   let decompressed = decompress(compressed);
   println!("{:s}", decompressed);

   // Check if the decompressed string corresponds to the original string
   assert!(original == decompressed);
}
<|endoftext|>