<commit_before>use std::io::{self, Read, Write};

use IntoRawMode;

#[cfg(feature = "nightly")]
use std::io::{Chars, CharsError};

/// A key.
#[derive(Debug)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Invalid character code.
    Invalid,
    /// IO error.
    Error(io::Error),
    /// Null byte.
    Null,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// An iterator over input keys.
#[cfg(feature = "nightly")]
pub struct Keys<I> {
    chars: I,
}

#[cfg(feature = "nightly")]
impl<I: Iterator<Item = Result<char, CharsError>>> Iterator for Keys<I> {
    type Item = Key;

    fn next(&mut self) -> Option<Key> {
        match self.chars.next() {
            Some(Ok('\x1B')) => Some(match self.chars.next() {
                Some(Ok('[')) => match self.chars.next() {
                    Some(Ok('D')) => Key::Left,
                    Some(Ok('C')) => Key::Right,
                    Some(Ok('A')) => Key::Up,
                    Some(Ok('B')) => Key::Down,
                    _ => Key::Invalid,
                },
                Some(Ok(c)) => Key::Alt(c),
                Some(Err(_)) | None => Key::Invalid,
            }),
            Some(Ok('\n')) | Some(Ok('\r')) => Some(Key::Char('\n')),
            Some(Ok('\t')) => Some(Key::Char('\t')),
            Some(Ok('\x7F')) => Some(Key::Backspace),
            Some(Ok(c @ '\x01' ... '\x1A')) => Some(Key::Ctrl((c as u8 - 0x1  + b'a') as char)),
            Some(Ok(c @ '\x1C' ... '\x1F')) => Some(Key::Ctrl((c as u8 - 0x1C + b'4') as char)),
            None => None,
            Some(Ok('\0')) => Some(Key::Null),
            Some(Ok(c)) => Some(Key::Char(c)),
            Some(Err(e)) => Some(Key::Error(io::Error::new(io::ErrorKind::InvalidData, e))),
        }
    }
}

/// Extension to `Read` trait.
pub trait TermRead {
    /// An iterator over key inputs.
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<Chars<Self>> where Self: Sized;

    /// Read a line.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_line(&mut self) -> io::Result<Option<String>>;

    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
        let _raw = try!(writer.into_raw_mode());
        self.read_line()
    }
}

impl<R: Read> TermRead for R {
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<Chars<R>> {
        Keys {
            chars: self.chars(),
        }
    }

    fn read_line(&mut self) -> io::Result<Option<String>> {
        let mut buf = Vec::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(e) => return Err(e),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(0x7f) => { passbuf.pop(); },
                Ok(b'\n') | Ok(b'\r') => break,
                Ok(c) => buf.push(c),
            }
        }

        let string = try!(String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
        Ok(Some(string))
    }
}

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

    #[cfg(feature = "nightly")]
    #[test]
    fn test_keys() {
        let mut i = b"\x1Bayo\x7F\x1B[D".keys();

        assert_eq!(i.next(), Some(Key::Alt('a')));
        assert_eq!(i.next(), Some(Key::Char('y')));
        assert_eq!(i.next(), Some(Key::Char('o')));
        assert_eq!(i.next(), Some(Key::Backspace));
        assert_eq!(i.next(), Some(Key::Left));
        assert_eq!(i.next(), None);
    }

    #[test]
    fn test_passwd() {
        let test1 = "this is the first test";
        let test2 = "this is the second test";
        let mut sink = io::sink();

        assert_eq!(&test1.as_bytes().read_passwd(&mut sink).unwrap().unwrap(), test1);
        assert_eq!(&test2.as_bytes().read_passwd(&mut sink).unwrap().unwrap(), test2);
    }

    #[test]
    fn test_passwd_backspace() {
        let test1 = "this is the\x7f first\x7f\x7f test";
        let test2 = "this is the seco\x7fnd test\x7f";
        let mut sink = io::sink();

        assert_eq!(&test1.as_bytes().read_passwd(&mut sink).unwrap().unwrap(), "this is th fir test");
        assert_eq!(&test2.as_bytes().read_passwd(&mut sink).unwrap().unwrap(), "this is the secnd tes");
    }
}
<commit_msg>Add unit tests for read_line<commit_after>use std::io::{self, Read, Write};

use IntoRawMode;

#[cfg(feature = "nightly")]
use std::io::{Chars, CharsError};

/// A key.
#[derive(Debug)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Invalid character code.
    Invalid,
    /// IO error.
    Error(io::Error),
    /// Null byte.
    Null,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// An iterator over input keys.
#[cfg(feature = "nightly")]
pub struct Keys<I> {
    chars: I,
}

#[cfg(feature = "nightly")]
impl<I: Iterator<Item = Result<char, CharsError>>> Iterator for Keys<I> {
    type Item = Key;

    fn next(&mut self) -> Option<Key> {
        match self.chars.next() {
            Some(Ok('\x1B')) => Some(match self.chars.next() {
                Some(Ok('[')) => match self.chars.next() {
                    Some(Ok('D')) => Key::Left,
                    Some(Ok('C')) => Key::Right,
                    Some(Ok('A')) => Key::Up,
                    Some(Ok('B')) => Key::Down,
                    _ => Key::Invalid,
                },
                Some(Ok(c)) => Key::Alt(c),
                Some(Err(_)) | None => Key::Invalid,
            }),
            Some(Ok('\n')) | Some(Ok('\r')) => Some(Key::Char('\n')),
            Some(Ok('\t')) => Some(Key::Char('\t')),
            Some(Ok('\x7F')) => Some(Key::Backspace),
            Some(Ok(c @ '\x01' ... '\x1A')) => Some(Key::Ctrl((c as u8 - 0x1  + b'a') as char)),
            Some(Ok(c @ '\x1C' ... '\x1F')) => Some(Key::Ctrl((c as u8 - 0x1C + b'4') as char)),
            None => None,
            Some(Ok('\0')) => Some(Key::Null),
            Some(Ok(c)) => Some(Key::Char(c)),
            Some(Err(e)) => Some(Key::Error(io::Error::new(io::ErrorKind::InvalidData, e))),
        }
    }
}

/// Extension to `Read` trait.
pub trait TermRead {
    /// An iterator over key inputs.
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<Chars<Self>> where Self: Sized;

    /// Read a line.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_line(&mut self) -> io::Result<Option<String>>;

    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
        let _raw = try!(writer.into_raw_mode());
        self.read_line()
    }
}

impl<R: Read> TermRead for R {
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<Chars<R>> {
        Keys {
            chars: self.chars(),
        }
    }

    fn read_line(&mut self) -> io::Result<Option<String>> {
        let mut buf = Vec::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(e) => return Err(e),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(0x7f) => { buf.pop(); },
                Ok(b'\n') | Ok(b'\r') => break,
                Ok(c) => buf.push(c),
            }
        }

        let string = try!(String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
        Ok(Some(string))
    }
}

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

    #[cfg(feature = "nightly")]
    #[test]
    fn test_keys() {
        let mut i = b"\x1Bayo\x7F\x1B[D".keys();

        assert_eq!(i.next(), Some(Key::Alt('a')));
        assert_eq!(i.next(), Some(Key::Char('y')));
        assert_eq!(i.next(), Some(Key::Char('o')));
        assert_eq!(i.next(), Some(Key::Backspace));
        assert_eq!(i.next(), Some(Key::Left));
        assert_eq!(i.next(), None);
    }

    fn line_match(a: &str, b: Option<&str>) {
        let mut sink = io::sink();

        let line = a.as_bytes().read_line().unwrap();
        let pass = a.as_bytes().read_passwd(&mut sink).unwrap();

        // godammit rustc

        assert_eq!(line, pass);

        if let Some(l) = line {
            assert_eq!(Some(l.as_str()), b);
        } else {
            assert!(b.is_none());
        }
    }

    #[test]
    fn test_read() {
        let test1 = "this is the first test";
        let test2 = "this is the second test";

        line_match(test1, Some(test1));
        line_match(test2, Some(test2));
    }

    #[test]
    fn test_backspace() {
        line_match("this is the\x7f first\x7f\x7f test", Some("this is th fir test"));
        line_match("this is the seco\x7fnd test\x7f", Some("this is the secnd tes"));
    }

    #[test]
    fn test_end() {
        line_match("abc\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ", Some("abc"));
        line_match("hello\rhttps://www.youtube.com/watch?v=yPYZpwSpKmA", Some("hello"));
    }

    #[test]
    fn test_abort() {
        line_match("abc\x03https://www.youtube.com/watch?v=dQw4w9WgXcQ", None);
        line_match("hello\x04https://www.youtube.com/watch?v=yPYZpwSpKmA", None);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Low-level bindings to OSX/macOS/iOS's `CommonCrypto` library.

#![warn(missing_docs)]

extern crate hex;
extern crate libc;

use libc::{c_int, c_uint, c_ulong, c_ulonglong};

/// Total number of operations.
const MD5_CBLOCK: usize = 64;
/// Number of operations per round.
const MD5_LBLOCK: usize = MD5_CBLOCK / 4;
/// Number of bytes for an MD5 hash.
pub const MD5_DIGEST_LENGTH: usize = 16;

const SHA_LBLOCK: usize = 16;
/// Number of bytes for an SHA1 hash.
pub const SHA1_DIGEST_LENGTH: usize = 20;
/// Number of bytes for an SHA256 hash.
pub const SHA256_DIGEST_LENGTH: usize = 32;
/// Number of bytes for an SHA512 hash.
pub const SHA512_DIGEST_LENGTH: usize = 64;

/// Struct used to generate MD5 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_MD5_CTX {
    A: c_uint,
    B: c_uint,
    C: c_uint,
    D: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; MD5_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA1 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA_CTX {
    h0: c_uint,
    h1: c_uint,
    h2: c_uint,
    h3: c_uint,
    h4: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; SHA_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA256 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA256_CTX {
    h: [c_ulong; 8],
    Nl: c_ulong,
    Nh: c_ulong,
    data: [c_ulong; SHA_LBLOCK],
    num: c_uint,
    md_len: c_uint,
}

/// Struct used to generate SHA512 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA512_CTX {
    h: [c_ulonglong; 8],
    Nl: c_ulonglong,
    Nh: c_ulonglong,
    data: [c_ulonglong; SHA_LBLOCK],
    num: c_uint,
    md_len: c_uint,
}

extern "C" {
    /// Initializes MD5 hasher. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Init(ctx: *mut CC_MD5_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Update(ctx: *mut CC_MD5_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates MD5 hash. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Final(md: *mut u8, ctx: *mut CC_MD5_CTX) -> c_int;
    /// Initializes SHA1 hasher. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Init(ctx: *mut CC_SHA_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Update(ctx: *mut CC_SHA_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA1 hash. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Final(md: *mut u8, ctx: *mut CC_SHA_CTX) -> c_int;
    /// Initializes SHA256 hasher. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Init(ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Update(ctx: *mut CC_SHA256_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA256 hash. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Final(md: *mut u8, ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Initializes SHA512 hasher. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Init(ctx: *mut CC_SHA512_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA512 hash. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int;
}

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

    const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog";
    const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6";

	#[test]
    fn md5_hash () {
        let mut ctx = CC_MD5_CTX::default();
        let mut md = [0u8; MD5_DIGEST_LENGTH];
        unsafe {
            assert_eq!(CC_MD5_Init(&mut ctx), 1);
            assert_eq!(CC_MD5_Update(&mut ctx, TO_HASH.as_ptr(), TO_HASH.len()), 1);
            assert_eq!(CC_MD5_Final(md.as_mut_ptr(), &mut ctx), 1);
        }
        assert_eq!(md.to_vec().to_hex(), TO_HASH_MD5);
    }
}
<commit_msg>Add the rest of the hash tests<commit_after>// Copyright (c) 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Low-level bindings to OSX/macOS/iOS's `CommonCrypto` library.

#![warn(missing_docs)]

extern crate hex;
extern crate libc;

use libc::{c_int, c_uint, c_ulong, c_ulonglong};

/// Total number of operations.
const MD5_CBLOCK: usize = 64;
/// Number of operations per round.
const MD5_LBLOCK: usize = MD5_CBLOCK / 4;
/// Number of bytes for an MD5 hash.
pub const MD5_DIGEST_LENGTH: usize = 16;

const SHA_LBLOCK: usize = 16;
/// Number of bytes for an SHA1 hash.
pub const SHA1_DIGEST_LENGTH: usize = 20;
/// Number of bytes for an SHA256 hash.
pub const SHA256_DIGEST_LENGTH: usize = 32;
/// Number of bytes for an SHA512 hash.
pub const SHA512_DIGEST_LENGTH: usize = 64;

/// Struct used to generate MD5 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_MD5_CTX {
    A: c_uint,
    B: c_uint,
    C: c_uint,
    D: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; MD5_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA1 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA_CTX {
    h0: c_uint,
    h1: c_uint,
    h2: c_uint,
    h3: c_uint,
    h4: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; SHA_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA256 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA256_CTX {
    h: [c_ulong; 8],
    Nl: c_ulong,
    Nh: c_ulong,
    data: [c_ulong; SHA_LBLOCK],
    num: c_uint,
    md_len: c_uint,
}

/// Struct used to generate SHA512 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA512_CTX {
    h: [c_ulonglong; 8],
    Nl: c_ulonglong,
    Nh: c_ulonglong,
    data: [c_ulonglong; SHA_LBLOCK],
    num: c_uint,
    md_len: c_uint,
}

extern "C" {
    /// Initializes MD5 hasher. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Init(ctx: *mut CC_MD5_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Update(ctx: *mut CC_MD5_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates MD5 hash. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Final(md: *mut u8, ctx: *mut CC_MD5_CTX) -> c_int;
    /// Initializes SHA1 hasher. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Init(ctx: *mut CC_SHA_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Update(ctx: *mut CC_SHA_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA1 hash. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Final(md: *mut u8, ctx: *mut CC_SHA_CTX) -> c_int;
    /// Initializes SHA256 hasher. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Init(ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Update(ctx: *mut CC_SHA256_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA256 hash. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Final(md: *mut u8, ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Initializes SHA512 hasher. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Init(ctx: *mut CC_SHA512_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA512 hash. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int;
}

#[cfg(test)]
mod test {
    use hex::ToHex;

    const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog";
    const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6";
    const TO_HASH_SHA1: &'static str = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12";
    const TO_HASH_SHA256: &'static str = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592";
    const TO_HASH_SHA512: &'static str = "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6";

    macro_rules! test_hash {
        (
            $test_name: ident,
            $ctx_ty: ident,
            $digest_len: ident,
            $init_func: ident,
            $update_func: ident,
            $final_func: ident,
            $expected_hash: ident
        ) => {
            #[test]
            fn $test_name() {
                let mut ctx = super::$ctx_ty::default();
                let mut md = [0u8; super::$digest_len];
                unsafe {
                    assert_eq!(super::$init_func(&mut ctx), 1);
                    assert_eq!(super::$update_func(&mut ctx, TO_HASH.as_ptr(), TO_HASH.len()), 1);
                    assert_eq!(super::$final_func(md.as_mut_ptr(), &mut ctx), 1);
                }
                assert_eq!(md.to_vec().to_hex(), $expected_hash);
            }
        }
    }

    test_hash!(md5_hash,
               CC_MD5_CTX,
               MD5_DIGEST_LENGTH,
               CC_MD5_Init,
               CC_MD5_Update,
               CC_MD5_Final,
               TO_HASH_MD5);
    test_hash!(sha1_hash,
               CC_SHA_CTX,
               SHA1_DIGEST_LENGTH,
               CC_SHA1_Init,
               CC_SHA1_Update,
               CC_SHA1_Final,
               TO_HASH_SHA1);
    test_hash!(sha256_hash,
               CC_SHA256_CTX,
               SHA256_DIGEST_LENGTH,
               CC_SHA256_Init,
               CC_SHA256_Update,
               CC_SHA256_Final,
               TO_HASH_SHA256);
    test_hash!(sha512_hash,
               CC_SHA512_CTX,
               SHA512_DIGEST_LENGTH,
               CC_SHA512_Init,
               CC_SHA512_Update,
               CC_SHA512_Final,
               TO_HASH_SHA512);
}
<|endoftext|>


<commit_before>
use std;
use input;
use event::{
    GenericEvent,
    PressEvent,
    ReleaseEvent,
    UpdateEvent,
};
use {
    Action,
    After,
    AlwaysSucceed,
    Behavior,
    Failure,
    If,
    Fail,
    Pressed,
    Released,
    Running,
    Select,
    Sequence,
    Status,
    Success,
    Wait,
    WaitForever,
    WhenAll,
    WhenAny,
    While,
};

pub static RUNNING: (Status, f64) = (Running, 0.0);

/// Keeps track of a behavior.
#[deriving(Clone, Decodable, Encodable, PartialEq)]
pub enum State<A, S> {
    /// Returns `Success` when button is pressed.
    PressedState(input::Button),
    /// Returns `Success` when button is released.
    ReleasedState(input::Button),
    /// Executes an action.
    ActionState(A, Option<S>),
    /// Converts `Success` into `Failure` and vice versa.
    FailState(Box<State<A, S>>),
    /// Ignores failures and always return `Success`.
    AlwaysSucceedState(Box<State<A, S>>),
    /// Keeps track of waiting for a period of time before continuing.
    ///
    /// f64: Total time in seconds to wait
    ///
    /// f64: Time elapsed in seconds
    WaitState(f64, f64),
    /// Waits forever.
    WaitForeverState,
    /// Keeps track of an `If` behavior.
    /// If status is `Running`, then it evaluates the condition.
    /// If status is `Success`, then it evaluates the success behavior.
    /// If status is `Failure`, then it evaluates the failure behavior.
    IfState(Box<Behavior<A>>, Box<Behavior<A>>, Status, Box<State<A, S>>),
    /// Keeps track of a `Select` behavior.
    SelectState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `Sequence` behavior.
    SequenceState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `While` behavior.
    WhileState(Box<State<A, S>>, Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `WhenAll` behavior.
    WhenAllState(Vec<Option<State<A, S>>>),
    /// Keeps track of a `WhenAny` behavior.
    WhenAnyState(Vec<Option<State<A, S>>>),
    /// Keeps track of an `After` behavior.
    AfterState(uint, Vec<State<A, S>>),
}

// `Sequence` and `Select` share same algorithm.
//
// `Sequence` fails if any fails and succeeds when all succeeds.
// `Select` succeeds if any succeeds and fails when all fails.
fn sequence<A: Clone, S, E: GenericEvent>(
    select: bool,
    upd: Option<f64>,
    seq: &Vec<Behavior<A>>,
    i: &mut uint,
    cursor: &mut Box<State<A, S>>,
    e: &E,
    f: |e: &E, dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if select {
        // `Select`
        (Failure, Success)
    } else {
        // `Sequence`
        (Success, Failure)
    };
    let mut remaining_dt = upd.unwrap_or(0.0);
    let mut remaining_e;
    while *i < seq.len() {
        match cursor.event(
            match upd {
                Some(_) => {
                    remaining_e = UpdateEvent::from_dt(remaining_dt).unwrap();
                    &remaining_e
                }
                _ => e
            },
            |e, dt, a, s| f(e, dt, a, s)) {
            (Running, _) => { break; },
            (s, new_dt) if s == inv_status => {
                return (inv_status, new_dt);
            }
            (s, new_dt) if s == status => {
                remaining_dt = match upd {
                    // Change update event with remaining delta time.
                    Some(_) => new_dt,
                    // Other events are 'consumed' and not passed to next.
                    // If this is the last event, then the sequence succeeded.
                    _ => if *i == seq.len() - 1 {
                            return (status, new_dt)
                        } else {
                            return RUNNING
                        }
                }
            }
            _ => unreachable!()
        };
        *i += 1;
        // If end of sequence,
        // return the 'dt' that is left.
        if *i >= seq.len() { return (status, remaining_dt); }
        // Create a new cursor for next event.
        // Use the same pointer to avoid allocation.
        **cursor  = State::new(seq[*i].clone());
    }
    RUNNING
}

// `WhenAll` and `WhenAny` share same algorithm.
//
// `WhenAll` fails if any fails and succeeds when all succeeds.
// `WhenAny` succeeds if any succeeds and fails when all fails.
fn when_all<A: Clone, S, E: GenericEvent>(
    any: bool,
    upd: Option<f64>,
    cursors: &mut Vec<Option<State<A, S>>>,
    e: &E,
    f: |e: &E, dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if any {
        // `WhenAny`
        (Failure, Success)
    } else {
        // `WhenAll`
        (Success, Failure)
    };
    // Get the least delta time left over.
    let mut min_dt = std::f64::MAX_VALUE;
    // Count number of terminated events.
    let mut terminated = 0;
    for cur in cursors.iter_mut() {
        match *cur {
            None => {}
            Some(ref mut cur) => {
                match cur.event(e, |e, dt, a, s| f(e, dt, a, s)) {
                    (Running, _) => { continue; },
                    (s, new_dt) if s == inv_status => {
                        // Fail for `WhenAll`.
                        // Succeed for `WhenAny`.
                        return (inv_status, new_dt);
                    }
                    (s, new_dt) if s == status => {
                        min_dt = min_dt.min(new_dt);
                    }
                    _ => unreachable!()
                }
            }
        }

        terminated += 1;
        *cur = None;
    }
    match terminated {
        // If there are no events, there is a whole 'dt' left.
        0 if cursors.len() == 0 => (status, match upd {
                Some(dt) => dt,
                // Other kind of events happen instantly.
                _ => 0.0
            }),
        // If all events terminated, the least delta time is left.
        n if cursors.len() == n => (status, min_dt),
        _ => RUNNING
    }
}

impl<A: Clone, S> State<A, S> {
    /// Creates a state from a behavior.
    pub fn new(behavior: Behavior<A>) -> State<A, S> {
        match behavior {
            Pressed(button) => PressedState(button),
            Released(button) => ReleasedState(button),
            Action(action) => ActionState(action, None),
            Fail(ev) => FailState(box State::new(*ev)),
            AlwaysSucceed(ev) => AlwaysSucceedState(box State::new(*ev)),
            Wait(dt) => WaitState(dt, 0.0),
            WaitForever => WaitForeverState,
            If(condition, success, failure) => {
                let state = State::new(*condition);
                IfState(success, failure, Running, box state)
            }
            Select(sel) => {
                let state = State::new(sel[0].clone());
                SelectState(sel, 0, box state)
            }
            Sequence(seq) => {
                let state = State::new(seq[0].clone());
                SequenceState(seq, 0, box state)
            }
            While(ev, rep) => {
                let state = State::new(rep[0].clone());
                WhileState(box State::new(*ev), rep, 0, box state)
            }
            WhenAll(all)
                => WhenAllState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
            WhenAny(all)
                => WhenAnyState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
            After(seq)
                => AfterState(0, seq.into_iter().map(
                    |ev| State::new(ev)).collect()),
        }
    }

    /// Updates the cursor that tracks an event.
    ///
    /// The action need to return status and remaining delta time.
    /// Returns status and the remaining delta time.
    pub fn event<E: GenericEvent>(
        &mut self,
        e: &E,
        f: |e: &E, dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
    ) -> (Status, f64) {
        let upd = e.update(|args| Some(args.dt)).unwrap_or(None);
        match (upd, self) {
            (None, &PressedState(button)) => {
                e.press(|button_pressed| {
                    if button_pressed != button { return RUNNING; }

                    // Button press is considered to happen instantly.
                    // There is no remaining delta time because
                    // this is input event.
                    (Success, 0.0)
                }).unwrap_or(RUNNING)
            }
            (None, &ReleasedState(button)) => {
                e.release(|button_released| {
                    if button_released != button { return RUNNING; }

                    // Button release is considered to happen instantly.
                    // There is no remaining delta time because
                    // this is input event.
                    (Success, 0.0)
                }).unwrap_or(RUNNING)
            }
            (_, &ActionState(ref action, ref mut state)) => {
                // Execute action.
                f(e, upd.unwrap_or(0.0), action, state)
            }
            (_, &FailState(ref mut cur)) => {
                match cur.event(e, f) {
                    (Running, dt) => (Running, dt),
                    (Failure, dt) => (Success, dt),
                    (Success, dt) => (Failure, dt),
                }
            }
            (_, &AlwaysSucceedState(ref mut cur)) => {
                match cur.event(e, f) {
                    (Running, dt) => (Running, dt),
                    (_, dt) => (Success, dt),
                }
            }
            (Some(dt), &WaitState(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    RUNNING
                }
            }
            (_, &IfState(ref success, ref failure,
                         ref mut status, ref mut state)) => {
                let mut remaining_dt = upd.unwrap_or(0.0);
                let mut remaining_e;
                // Run in a loop to evaluate success or failure with
                // remaining delta time after condition.
                loop {
                    *status = match *status {
                        Running => {
                            match state.event(e, |e, dt, a, s| f(e, dt, a, s)) {
                                (Running, dt) => { return (Running, dt); },
                                (Success, dt) => {
                                    **state = State::new((**success).clone());
                                    remaining_dt = dt;
                                    Success
                                }
                                (Failure, dt) => {
                                    **state = State::new((**failure).clone());
                                    remaining_dt = dt;
                                    Failure
                                }
                            }
                        }
                        _ => {
                            return state.event(match upd {
                                Some(_) => {
                                    remaining_e = UpdateEvent::from_dt(
                                        remaining_dt).unwrap();
                                    &remaining_e
                                }
                                _ => e
                            }, |e, dt, a, s| f(e, dt, a, s));
                        }
                    }
                }
            }
            (_, &SelectState(ref seq, ref mut i, ref mut cursor)) => {
                let select = true;
                sequence(select, upd, seq, i, cursor, e, f)
            }
            (_, &SequenceState(ref seq, ref mut i, ref mut cursor)) => {
                let select = false;
                sequence(select, upd, seq, i, cursor, e, f)
            }
            (_, &WhileState(ref mut ev_cursor, ref rep, ref mut i,
                            ref mut cursor)) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.event(e, |e, dt, a, s| f(e, dt, a, s)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_dt = upd.unwrap_or(0.0);
                let mut remaining_e;
                loop {
                    match cur.event(match upd {
                            Some(_) => {
                                remaining_e = UpdateEvent::from_dt(
                                    remaining_dt).unwrap();
                                &remaining_e
                            }
                            _ => e
                        },
                        |e, dt, a, s| f(e, dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match upd {
                                // Change update event with remaining delta time.
                                Some(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                _ => return RUNNING
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(rep[*i].clone());
                }
                RUNNING
            }
            (_, &WhenAllState(ref mut cursors)) => {
                let any = false;
                when_all(any, upd, cursors, e, f)
            }
            (_, &WhenAnyState(ref mut cursors)) => {
                let any = true;
                when_all(any, upd, cursors, e, f)
            }
            (_, &AfterState(ref mut i, ref mut cursors)) => {
                // Get the least delta time left over.
                let mut min_dt = std::f64::MAX_VALUE;
                for j in range(*i, cursors.len()) {
                    match cursors.get_mut(j).event(
                        e, |e, dt, a, s| f(e, dt, a, s)
                    ) {
                        (Running, _) => { min_dt = 0.0; }
                        (Success, new_dt) => {
                            // Remaining delta time must be less to succeed.
                            if *i == j && new_dt < min_dt {
                                *i += 1;
                                min_dt = new_dt;
                            } else {
                                // Return least delta time because
                                // that is when failure is detected.
                                return (Failure, min_dt.min(new_dt));
                            }
                        }
                        (Failure, new_dt) => {
                            return (Failure, new_dt);
                        }
                    };
                }
                if *i == cursors.len() {
                    (Success, min_dt)
                } else {
                    RUNNING
                }
            }
            _ => RUNNING
        }
    }
}
<commit_msg>Fix deprecation warning<commit_after>
use std;
use input;
use event::{
    GenericEvent,
    PressEvent,
    ReleaseEvent,
    UpdateEvent,
};
use {
    Action,
    After,
    AlwaysSucceed,
    Behavior,
    Failure,
    If,
    Fail,
    Pressed,
    Released,
    Running,
    Select,
    Sequence,
    Status,
    Success,
    Wait,
    WaitForever,
    WhenAll,
    WhenAny,
    While,
};

pub static RUNNING: (Status, f64) = (Running, 0.0);

/// Keeps track of a behavior.
#[deriving(Clone, Decodable, Encodable, PartialEq)]
pub enum State<A, S> {
    /// Returns `Success` when button is pressed.
    PressedState(input::Button),
    /// Returns `Success` when button is released.
    ReleasedState(input::Button),
    /// Executes an action.
    ActionState(A, Option<S>),
    /// Converts `Success` into `Failure` and vice versa.
    FailState(Box<State<A, S>>),
    /// Ignores failures and always return `Success`.
    AlwaysSucceedState(Box<State<A, S>>),
    /// Keeps track of waiting for a period of time before continuing.
    ///
    /// f64: Total time in seconds to wait
    ///
    /// f64: Time elapsed in seconds
    WaitState(f64, f64),
    /// Waits forever.
    WaitForeverState,
    /// Keeps track of an `If` behavior.
    /// If status is `Running`, then it evaluates the condition.
    /// If status is `Success`, then it evaluates the success behavior.
    /// If status is `Failure`, then it evaluates the failure behavior.
    IfState(Box<Behavior<A>>, Box<Behavior<A>>, Status, Box<State<A, S>>),
    /// Keeps track of a `Select` behavior.
    SelectState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `Sequence` behavior.
    SequenceState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `While` behavior.
    WhileState(Box<State<A, S>>, Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `WhenAll` behavior.
    WhenAllState(Vec<Option<State<A, S>>>),
    /// Keeps track of a `WhenAny` behavior.
    WhenAnyState(Vec<Option<State<A, S>>>),
    /// Keeps track of an `After` behavior.
    AfterState(uint, Vec<State<A, S>>),
}

// `Sequence` and `Select` share same algorithm.
//
// `Sequence` fails if any fails and succeeds when all succeeds.
// `Select` succeeds if any succeeds and fails when all fails.
fn sequence<A: Clone, S, E: GenericEvent>(
    select: bool,
    upd: Option<f64>,
    seq: &Vec<Behavior<A>>,
    i: &mut uint,
    cursor: &mut Box<State<A, S>>,
    e: &E,
    f: |e: &E, dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if select {
        // `Select`
        (Failure, Success)
    } else {
        // `Sequence`
        (Success, Failure)
    };
    let mut remaining_dt = upd.unwrap_or(0.0);
    let mut remaining_e;
    while *i < seq.len() {
        match cursor.event(
            match upd {
                Some(_) => {
                    remaining_e = UpdateEvent::from_dt(remaining_dt).unwrap();
                    &remaining_e
                }
                _ => e
            },
            |e, dt, a, s| f(e, dt, a, s)) {
            (Running, _) => { break; },
            (s, new_dt) if s == inv_status => {
                return (inv_status, new_dt);
            }
            (s, new_dt) if s == status => {
                remaining_dt = match upd {
                    // Change update event with remaining delta time.
                    Some(_) => new_dt,
                    // Other events are 'consumed' and not passed to next.
                    // If this is the last event, then the sequence succeeded.
                    _ => if *i == seq.len() - 1 {
                            return (status, new_dt)
                        } else {
                            return RUNNING
                        }
                }
            }
            _ => unreachable!()
        };
        *i += 1;
        // If end of sequence,
        // return the 'dt' that is left.
        if *i >= seq.len() { return (status, remaining_dt); }
        // Create a new cursor for next event.
        // Use the same pointer to avoid allocation.
        **cursor  = State::new(seq[*i].clone());
    }
    RUNNING
}

// `WhenAll` and `WhenAny` share same algorithm.
//
// `WhenAll` fails if any fails and succeeds when all succeeds.
// `WhenAny` succeeds if any succeeds and fails when all fails.
fn when_all<A: Clone, S, E: GenericEvent>(
    any: bool,
    upd: Option<f64>,
    cursors: &mut Vec<Option<State<A, S>>>,
    e: &E,
    f: |e: &E, dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if any {
        // `WhenAny`
        (Failure, Success)
    } else {
        // `WhenAll`
        (Success, Failure)
    };
    // Get the least delta time left over.
    let mut min_dt = std::f64::MAX_VALUE;
    // Count number of terminated events.
    let mut terminated = 0;
    for cur in cursors.iter_mut() {
        match *cur {
            None => {}
            Some(ref mut cur) => {
                match cur.event(e, |e, dt, a, s| f(e, dt, a, s)) {
                    (Running, _) => { continue; },
                    (s, new_dt) if s == inv_status => {
                        // Fail for `WhenAll`.
                        // Succeed for `WhenAny`.
                        return (inv_status, new_dt);
                    }
                    (s, new_dt) if s == status => {
                        min_dt = min_dt.min(new_dt);
                    }
                    _ => unreachable!()
                }
            }
        }

        terminated += 1;
        *cur = None;
    }
    match terminated {
        // If there are no events, there is a whole 'dt' left.
        0 if cursors.len() == 0 => (status, match upd {
                Some(dt) => dt,
                // Other kind of events happen instantly.
                _ => 0.0
            }),
        // If all events terminated, the least delta time is left.
        n if cursors.len() == n => (status, min_dt),
        _ => RUNNING
    }
}

impl<A: Clone, S> State<A, S> {
    /// Creates a state from a behavior.
    pub fn new(behavior: Behavior<A>) -> State<A, S> {
        match behavior {
            Pressed(button) => PressedState(button),
            Released(button) => ReleasedState(button),
            Action(action) => ActionState(action, None),
            Fail(ev) => FailState(box State::new(*ev)),
            AlwaysSucceed(ev) => AlwaysSucceedState(box State::new(*ev)),
            Wait(dt) => WaitState(dt, 0.0),
            WaitForever => WaitForeverState,
            If(condition, success, failure) => {
                let state = State::new(*condition);
                IfState(success, failure, Running, box state)
            }
            Select(sel) => {
                let state = State::new(sel[0].clone());
                SelectState(sel, 0, box state)
            }
            Sequence(seq) => {
                let state = State::new(seq[0].clone());
                SequenceState(seq, 0, box state)
            }
            While(ev, rep) => {
                let state = State::new(rep[0].clone());
                WhileState(box State::new(*ev), rep, 0, box state)
            }
            WhenAll(all)
                => WhenAllState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
            WhenAny(all)
                => WhenAnyState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
            After(seq)
                => AfterState(0, seq.into_iter().map(
                    |ev| State::new(ev)).collect()),
        }
    }

    /// Updates the cursor that tracks an event.
    ///
    /// The action need to return status and remaining delta time.
    /// Returns status and the remaining delta time.
    pub fn event<E: GenericEvent>(
        &mut self,
        e: &E,
        f: |e: &E, dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
    ) -> (Status, f64) {
        let upd = e.update(|args| Some(args.dt)).unwrap_or(None);
        match (upd, self) {
            (None, &PressedState(button)) => {
                e.press(|button_pressed| {
                    if button_pressed != button { return RUNNING; }

                    // Button press is considered to happen instantly.
                    // There is no remaining delta time because
                    // this is input event.
                    (Success, 0.0)
                }).unwrap_or(RUNNING)
            }
            (None, &ReleasedState(button)) => {
                e.release(|button_released| {
                    if button_released != button { return RUNNING; }

                    // Button release is considered to happen instantly.
                    // There is no remaining delta time because
                    // this is input event.
                    (Success, 0.0)
                }).unwrap_or(RUNNING)
            }
            (_, &ActionState(ref action, ref mut state)) => {
                // Execute action.
                f(e, upd.unwrap_or(0.0), action, state)
            }
            (_, &FailState(ref mut cur)) => {
                match cur.event(e, f) {
                    (Running, dt) => (Running, dt),
                    (Failure, dt) => (Success, dt),
                    (Success, dt) => (Failure, dt),
                }
            }
            (_, &AlwaysSucceedState(ref mut cur)) => {
                match cur.event(e, f) {
                    (Running, dt) => (Running, dt),
                    (_, dt) => (Success, dt),
                }
            }
            (Some(dt), &WaitState(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    RUNNING
                }
            }
            (_, &IfState(ref success, ref failure,
                         ref mut status, ref mut state)) => {
                let mut remaining_dt = upd.unwrap_or(0.0);
                let mut remaining_e;
                // Run in a loop to evaluate success or failure with
                // remaining delta time after condition.
                loop {
                    *status = match *status {
                        Running => {
                            match state.event(e, |e, dt, a, s| f(e, dt, a, s)) {
                                (Running, dt) => { return (Running, dt); },
                                (Success, dt) => {
                                    **state = State::new((**success).clone());
                                    remaining_dt = dt;
                                    Success
                                }
                                (Failure, dt) => {
                                    **state = State::new((**failure).clone());
                                    remaining_dt = dt;
                                    Failure
                                }
                            }
                        }
                        _ => {
                            return state.event(match upd {
                                Some(_) => {
                                    remaining_e = UpdateEvent::from_dt(
                                        remaining_dt).unwrap();
                                    &remaining_e
                                }
                                _ => e
                            }, |e, dt, a, s| f(e, dt, a, s));
                        }
                    }
                }
            }
            (_, &SelectState(ref seq, ref mut i, ref mut cursor)) => {
                let select = true;
                sequence(select, upd, seq, i, cursor, e, f)
            }
            (_, &SequenceState(ref seq, ref mut i, ref mut cursor)) => {
                let select = false;
                sequence(select, upd, seq, i, cursor, e, f)
            }
            (_, &WhileState(ref mut ev_cursor, ref rep, ref mut i,
                            ref mut cursor)) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.event(e, |e, dt, a, s| f(e, dt, a, s)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_dt = upd.unwrap_or(0.0);
                let mut remaining_e;
                loop {
                    match cur.event(match upd {
                            Some(_) => {
                                remaining_e = UpdateEvent::from_dt(
                                    remaining_dt).unwrap();
                                &remaining_e
                            }
                            _ => e
                        },
                        |e, dt, a, s| f(e, dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match upd {
                                // Change update event with remaining delta time.
                                Some(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                _ => return RUNNING
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(rep[*i].clone());
                }
                RUNNING
            }
            (_, &WhenAllState(ref mut cursors)) => {
                let any = false;
                when_all(any, upd, cursors, e, f)
            }
            (_, &WhenAnyState(ref mut cursors)) => {
                let any = true;
                when_all(any, upd, cursors, e, f)
            }
            (_, &AfterState(ref mut i, ref mut cursors)) => {
                // Get the least delta time left over.
                let mut min_dt = std::f64::MAX_VALUE;
                for j in range(*i, cursors.len()) {
                    match cursors[j].event(
                        e, |e, dt, a, s| f(e, dt, a, s)
                    ) {
                        (Running, _) => { min_dt = 0.0; }
                        (Success, new_dt) => {
                            // Remaining delta time must be less to succeed.
                            if *i == j && new_dt < min_dt {
                                *i += 1;
                                min_dt = new_dt;
                            } else {
                                // Return least delta time because
                                // that is when failure is detected.
                                return (Failure, min_dt.min(new_dt));
                            }
                        }
                        (Failure, new_dt) => {
                            return (Failure, new_dt);
                        }
                    };
                }
                if *i == cursors.len() {
                    (Success, min_dt)
                } else {
                    RUNNING
                }
            }
            _ => RUNNING
        }
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs,
       missing_debug_implementations, missing_copy_implementations,
       trivial_casts, trivial_numeric_casts,
       unsafe_code,
       unstable_features,
       unused_import_braces, unused_qualifications)]

//! Contains functions and structs for sending and receiving SNMP messages.
use std::net::UdpSocket;
use std::{io, time};

/// Various errors that can occur.
#[derive(Debug)]
pub enum SnmpError {
    /// The packet is too short to parse.
    PacketTooShort,
    /// The type specified in the packet is invalid.
    InvalidType,
    /// The packet could not be parsed in the wanted manner.
    ParsingError,
    /// An IO error occured when sending or receiving the packets.
    Io(io::Error),
}

impl From<io::Error> for SnmpError {
    fn from(error: io::Error) -> Self {
        SnmpError::Io(error)
    }
}

/// Contains functions and structs for sending and receiving SNMPv3 messages.
pub mod snmpv3 {
    use super::*;

    /// Sends a SMTPv3 message and returns the reply or an error specifiying what went wrong.
    ///
    /// #Examples
    /// ```
    /// rust_snmp::snmpv3::smtpv3_send("demo.snmplabs.com:161",
    ///                                           "public",
    ///                                           &[1, 3, 6, 1, 2, 1, 1, 5, 0]);
    /// ```
    pub fn smtpv3_send(addr: &str,
                       community: &str,
                       mibvals: &[u16]) {
        let mut buf: [u8; 1024] = [0; 1024];
        let mut mib: [u8; 1024] = [0; 1024];
        let orgmiblen = mibvals.len();
        let mut miblen = orgmiblen;

        let mut counter = 0;
        for mibval in mibvals.iter() {
            if mibval > &127u16 {
                mib[counter] = (128 + (mibval / 128)) as u8;
                mib[counter + 1] = (mibval - (mibval - ((mibval / 128) * 128))) as u8;
                counter += 2;
                miblen += 1;
            } else {
                mib[counter] = *mibval as u8;
                counter += 1;
            }
        }
        let mib = &mib[0..miblen];
        let miblen = miblen;
        let snmplen = 29 + community.len() + miblen - 1;

        // SNMP sequence start
        buf[0] = 0x30;
        buf[1] = (snmplen - 2) as u8;

        buf[2] = 0x02; // Integer
        buf[3] = 0x01; // Length
        buf[4] = 0x03; // SNMP version

        buf[5] = 0x02; // Integer type
        buf[6] = 0x04; // Length
        buf[7] = 0x00; // SNMP Request ID

        buf[5] = 0x02; // Integer type
        buf[6] = 0x08; // Length
        buf[7] = 0x04; // Message Max Size
        buf[8] = 0x00;
    }
}

<commit_msg>Work continues on snmpv3<commit_after>#![deny(missing_docs,
       missing_debug_implementations, missing_copy_implementations,
       trivial_casts, trivial_numeric_casts,
       unsafe_code,
       unstable_features,
       unused_import_braces, unused_qualifications)]

//! Contains functions and structs for sending and receiving SNMP messages.
use std::net::UdpSocket;
use std::{io, time};

/// Various errors that can occur.
#[derive(Debug)]
pub enum SnmpError {
    /// The packet is too short to parse.
    PacketTooShort,
    /// The type specified in the packet is invalid.
    InvalidType,
    /// The packet could not be parsed in the wanted manner.
    ParsingError,
    /// An IO error occured when sending or receiving the packets.
    Io(io::Error),
}

impl From<io::Error> for SnmpError {
    fn from(error: io::Error) -> Self {
        SnmpError::Io(error)
    }
}

/// Contains functions and structs for sending and receiving SNMPv3 messages.
pub mod snmpv3 {
    use super::*;

    /// Sends a SMTPv3 message and returns the reply or an error specifiying what went wrong.
    ///
    /// #Examples
    /// ```
    /// rust_snmp::snmpv3::smtpv3_send("demo.snmplabs.com:161",
    ///                                           "public",
    ///                                           &[1, 3, 6, 1, 2, 1, 1, 5, 0]);
    /// ```
    pub fn smtpv3_send(addr: &str,
                       community: &str,
                       mibvals: &[u16]) {
        let mut buf: [u8; 1024] = [0; 1024];
        let mut mib: [u8; 1024] = [0; 1024];
        let orgmiblen = mibvals.len();
        let mut miblen = orgmiblen;

        let mut counter = 0;
        for mibval in mibvals.iter() {
            if mibval > &127u16 {
                mib[counter] = (128 + (mibval / 128)) as u8;
                mib[counter + 1] = (mibval - (mibval - ((mibval / 128) * 128))) as u8;
                counter += 2;
                miblen += 1;
            } else {
                mib[counter] = *mibval as u8;
                counter += 1;
            }
        }
        let mib = &mib[0..miblen];
        let miblen = miblen;
        let snmplen = 29 + community.len() + miblen - 1;

        // SNMP sequence start
        buf[0] = 0x30;
        buf[1] = (snmplen - 2) as u8;

        buf[2] = 0x02; // Integer
        buf[3] = 0x01; // Length
        buf[4] = 0x03; // SNMP version

        buf[5] = 0x30; // Sequence
        buf[6] = 0x11; // Length

        buf[7] = 0x02; // Integer
        buf[8] = 0x04; // Length
        buf[9] = 0x01; // Message ID
        buf[10] = 0x11;
        buf[11] = 0x41;
        buf[12] = 0x0F;

        buf[13] = 0x02; // Integer
        buf[14] = 0x03; // Length
        buf[15] = 0x00; // Max message size
        buf[16] = 0xFF;
        buf[17] = 0xE3;

        buf[18] = 0x04; // Octet
        buf[19] = 0x01; // Length
        buf[20] = 0b0000_0100; // Reportable, not encrypted or authenticated

        buf[21] = 0x02; // Integer
        buf[22] = 0x01; // Length
        buf[23] = 0x03; // USM

        buf[21] = 0x04; // Octet
        buf[22] = 0x10; // Length
        buf[23] = 0x03; // USM

        buf[21] = 0x02; // Integer
        buf[22] = 0x10; // Length
        buf[23] = 0x30; // Engine ID
        buf[24] = 0x0E;
        buf[25] = 0x04;
        buf[26] = 0x00;

        buf[27] = 0x02; // Integer
        buf[28] = 0x01; // Length
        buf[29] = 0x00; // Authoritative Engine Boots

        buf[27] = 0x02; // Integer
        buf[28] = 0x01; // Length
        buf[29] = 0x00; // Authoritative Engine Time

        // Username
        buf[28] = 0x04; // Octet
        buf[29] = 0x00; // Length

        // Authentication Parameters
        buf[28] = 0x04; // Octet
        buf[29] = 0x00; // Length

        // Privacy Parameters
        buf[28] = 0x04; // Octet
        buf[29] = 0x00; // Length

        buf[30] = 0x30; // Sequence
        buf[31] = 0x21; // Length

        // Context Engine ID
        buf[32] = 0x04; // Octet
        buf[33] = 0x0D; // Length
        buf[34] = 0x80; // Conformance: SNMPv3
        buf[35] = 0x00; // ID Net-SNMP
        buf[36] = 0x1F;
        buf[37] = 0x88;
        buf[38] = 0x80; // Net-SNMP Random
        buf[39] = 0x59; // Engine ID data
        buf[40] = 0xDC;
        buf[41] = 0x48;
        buf[42] = 0x61;
        buf[43] = 0x45; // Creation time
        buf[44] = 0xA2;
        buf[45] = 0x63;
        buf[46] = 0x22;

        // Context name
        buf[47] = 0x04; // Octet
        buf[48] = 0x00; // Length

        buf[49] = 0xA0; // GetRequest PDU
        buf[50] = 0x0E; // Length

        buf[51] = 0x02; // Integer
        buf[52] = 0x04; // Length
        buf[53] = 0x2C; // Request ID
        buf[54] = 0x18;
        buf[55] = 0x0D;
        buf[56] = 0xBB;

        buf[57] = 0x02; // Integer
        buf[58] = 0x01; // Length
        buf[59] = 0x00; // Error status

        buf[60] = 0x02; // Integer
        buf[61] = 0x01; // Length
        buf[62] = 0x00; // Error ID

        // Variable bindings
        buf[63] = 0x30; // Sequence
        buf[64] = 0x00; // Length
    }
}
<|endoftext|>


<commit_before>//! The `termios` crate provides Rust bindings for the POSIX termios API that is implemented on
//! most Unix operating systems. The termios API is defined in the [IEEE Std 1003.1 ("POSIX.1")
//! specification](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html).

extern crate libc;

use std::io;
use std::mem;
use std::default::Default;
use std::os::unix::io::RawFd;

use libc::{c_int,pid_t};

pub use os::{cc_t,speed_t,tcflag_t}; // types
pub use os::{VEOF,VEOL,VERASE,VINTR,VKILL,VMIN,VQUIT,VSTART,VSTOP,VSUSP,VTIME}; // c_cc subscripts
pub use os::{BRKINT,ICRNL,IGNBRK,IGNCR,IGNPAR,INLCR,INPCK,ISTRIP,IXANY,IXOFF,IXON,PARMRK}; // input modes
pub use os::{OPOST,ONLCR,OCRNL,ONOCR,ONLRET,OFILL,NLDLY,NL0,NL1,CRDLY,CR0,CR1,CR2,CR3,TABDLY,TAB0,TAB1,TAB2,TAB3,BSDLY,BS0,BS1,VTDLY,VT0,VT1,FFDLY,FF0,FF1}; // output modes
pub use os::{B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400}; // baud rate selection
pub use os::{CSIZE,CS5,CS6,CS7,CS8,CSTOPB,CREAD,PARENB,PARODD,HUPCL,CLOCAL}; // control modes
pub use os::{ECHO,ECHOE,ECHOK,ECHONL,ICANON,IEXTEN,ISIG,NOFLSH,TOSTOP}; // local modes
pub use os::{TCSANOW,TCSADRAIN,TCSAFLUSH}; // attribute selection
pub use os::{TCIFLUSH,TCIOFLUSH,TCOFLUSH,TCIOFF,TCION,TCOOFF,TCOON}; // line control

pub mod ffi;
pub mod os;

pub type Termios = os::termios;

impl Termios {
    /// Creates a `Termios` structure with its memory zeroed.
    pub fn zeroed() -> Self {
        unsafe { mem::zeroed() }
    }

    /// Creates a `Termios` structure based on the current settings of a file descriptor.
    pub fn from_fd(fd: RawFd) -> io::Result<Termios> {
        let mut termios = Termios::zeroed();

        match tcgetattr(fd, &mut termios) {
            Ok(_) => Ok(termios),
            Err(err) => Err(err)
        }
    }
}

impl Default for Termios {
    fn default() -> Self {
        Termios::zeroed()
    }
}

/// Gets the input baud rate stored in a `Termios` structure.
///
/// # Examples
///
/// ```
/// # use termios::{Termios,B9600,cfsetispeed,cfgetispeed};
/// let mut tios = Termios::zeroed();
/// cfsetispeed(&mut tios, B9600).unwrap();
/// assert_eq!(cfgetispeed(&tios), B9600);
/// ```
pub fn cfgetispeed(termios: &Termios) -> speed_t {
    unsafe { ffi::cfgetispeed(termios) }
}

/// Gets the output baud rate stored in a `Termios` structure.
///
/// # Examples
///
/// ```
/// # use termios::{Termios,B9600,cfsetospeed,cfgetospeed};
/// let mut tios = Termios::zeroed();
/// cfsetospeed(&mut tios, B9600).unwrap();
/// assert_eq!(cfgetospeed(&tios), B9600);
/// ```
pub fn cfgetospeed(termios: &Termios) -> speed_t {
    unsafe { ffi::cfgetospeed(termios) }
}

/// Sets the input baud rate.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied by a subsequent call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Parameters
///
/// * `termios` should be a mutable reference to a `Termios` structure.
/// * `speed` should be one of the baud rate constants:
///   - `B0`
///   - `B50`
///   - `B75`
///   - `B110`
///   - `B134`
///   - `B150`
///   - `B200`
///   - `B300`
///   - `B600`
///   - `B1200`
///   - `B1800`
///   - `B2400`
///   - `B4800`
///   - `B9600`
///   - `B19200`
///   - `B38400`
///   - any OS-specific baud rate defined in [`termios::os`](os/index.html).
///
/// A value of `B0` for `speed` sets the input baud rate to be the same as the output baud rate.
///
/// # Examples
///
/// ```
/// # use termios::{Termios,B9600,cfsetispeed,cfgetispeed};
/// let mut tios = Termios::zeroed();
/// cfsetispeed(&mut tios, B9600).unwrap();
/// assert_eq!(cfgetispeed(&tios), B9600);
/// ```
pub fn cfsetispeed(termios: &mut Termios, speed: speed_t) -> io::Result<()> {
    io_result(unsafe { ffi::cfsetispeed(termios, speed) })
}

/// Sets the output baud rate.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied on a successful call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Parameters
///
/// * `termios` should be a mutable reference to a `Termios` structure.
/// * `speed` should be one of the baud rate constants:
///   - `B0` (hang up)
///   - `B50`
///   - `B75`
///   - `B110`
///   - `B134`
///   - `B150`
///   - `B200`
///   - `B300`
///   - `B600`
///   - `B1200`
///   - `B1800`
///   - `B2400`
///   - `B4800`
///   - `B9600`
///   - `B19200`
///   - `B38400`
///   - any OS-specific baud rate defined in [`termios::os`](os/index.html).
///
/// A value of `B0` for `speed` deasserts the modem control lines when applied with
/// [`tcsetattr()`](fn.tcsetattr.html).  This normally has the effect of disconnecting the line.
///
/// # Examples
///
/// ```
/// # use termios::{Termios,B9600,cfsetospeed,cfgetospeed};
/// let mut tios = Termios::zeroed();
/// cfsetospeed(&mut tios, B9600).unwrap();
/// assert_eq!(cfgetospeed(&tios), B9600);
/// ```
pub fn cfsetospeed(termios: &mut Termios, speed: speed_t) -> io::Result<()> {
    io_result(unsafe { ffi::cfsetospeed(termios, speed) })
}

/// Sets input and output baud rates.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied on a successful call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Parameters
///
/// * `termios` should be a mutable reference to a `Termios` structure.
/// * `speed` should be one of the baud rate constants:
///   - `B0`
///   - `B50`
///   - `B75`
///   - `B110`
///   - `B134`
///   - `B150`
///   - `B200`
///   - `B300`
///   - `B600`
///   - `B1200`
///   - `B1800`
///   - `B2400`
///   - `B4800`
///   - `B9600`
///   - `B19200`
///   - `B38400`
///   - any OS-specific baud rate defined in [`termios::os`](os/index.html).
///
/// # Examples
///
/// ```
/// # use termios::{Termios,B9600,cfsetspeed,cfgetispeed,cfgetospeed};
/// let mut tios = Termios::zeroed();
/// cfsetspeed(&mut tios, B9600).unwrap();
/// assert_eq!(cfgetispeed(&tios), B9600);
/// assert_eq!(cfgetospeed(&tios), B9600);
/// ```
///
/// # Portability
///
/// This function is not part of the IEEE Std 1003.1 ("POSIX.1") specification, but it is available
/// on Linux, BSD, and OS X.
pub fn cfsetspeed(termios: &mut Termios, speed: speed_t) -> io::Result<()> {
    io_result(unsafe { ffi::cfsetspeed(termios, speed) })
}

/// Sets flags to disable all input and output processing.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied on a successful call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Portability
///
/// This function is not part of the IEEE Std 1003.1 ("POSIX.1") specification, but it is available
/// on Linux, BSD, and OS X.
pub fn cfmakeraw(termios: &mut Termios) {
    unsafe { ffi::cfmakeraw(termios) };
}

/// Blocks until all output written to the file descriptor is transmitted.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
pub fn tcdrain(fd: RawFd) -> io::Result<()> {
    io_result(unsafe { ffi::tcdrain(fd) })
}

/// Suspends or restarts transmission or reception of data.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `action` should be one of the following constants:
///   - `TCOOFF` suspends output.
///   - `TCOON` restarts output.
///   - `TCIOFF` transmits a STOP character, intended to cause the remote device to stop
///     transmitting.
///   - `TCION` transmits a START character, intended to cause the remote device to resume
///     transmitting.
pub fn tcflow(fd: RawFd, action: c_int) -> io::Result<()> {
    io_result(unsafe { ffi::tcflow(fd, action) })
}

/// Discards data waiting in the terminal device's buffers.
///
/// `tcflush()` discards data that has been written to the device by an application but has not yet
/// been transmitted by the hardware or data that has been received by the hardware but has not yet
/// been read by an application.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `queue_selector` should be one of:
///   - `TCIFLUSH` to discard data received but not read.
///   - `TCOFLUSH` to discard data written but not transmitted.
///   - `TCIOFLUSH` to discard both data received but not read and data written but not
///     transmitted.
pub fn tcflush(fd: RawFd, queue_selector: c_int) -> io::Result<()> {
    io_result(unsafe { ffi::tcflush(fd, queue_selector) })
}

/// Populates a `Termios` structure with parameters associated with a terminal.
///
/// Upon successful completion, the `Termios` structure referred to by the `termios` parameter will
/// contain the parameters associated with the terminal device referred to by `fd`.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `termios` should be a mutable reference to the `Termios` structure that will hold the
///   terminal device's parameters.
pub fn tcgetattr(fd: RawFd, termios: &mut Termios) -> io::Result<()> {
    io_result(unsafe { ffi::tcgetattr(fd, termios) })
}

/// Sets a terminal device's parameters.
///
/// `tcsetattr()` returns successfully if it was able to perform any of the requested actions, even
/// if other requested actions could not be performed. It will set all attributes that the
/// implementation supports and leave others unchanged. The `Termios` structure will not be updated
/// to reflect the changes that were applied.
///
/// In order to determine which parameters were applied to the terminal device, an application
/// should use [`tcgetattr()`](fn.tcgetattr.html) to obtain the latest state of the terminal
/// device. In particular, when attempting to change baud rates, [`tcgetattr()`](fn.tcgetattr.html)
/// can be used to determine which baud rates were actually selected.
///
/// If none of the requested actions could be performed, then `tcsetattr()` returns an error.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `action` should be one of the constants:
///   - `TCSANOW` applies the change immediately.
///   - `TCSADRAIN` applies the change after all output previously written to `fd` is transmitted.
///     This mode should be used when changing parameters that affect output.
///   - `TCSAFLUSH` applies the change after all output previously written to `fd` is transmitted.
///     All data received but not read is discarded before applying the change.
/// * `termios` should be a mutable reference to a `Termios` structure containing the parameters to
///   apply to the terminal device.
pub fn tcsetattr(fd: RawFd, action: c_int, termios: &Termios) -> io::Result<()> {
    io_result(unsafe { ffi::tcsetattr(fd, action, termios) })
}

/// Returns the process group ID of the controlling terminal's session.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a controlling terminal.
pub fn tcgetsid(fd: RawFd) -> pid_t {
    unsafe { ffi::tcgetsid(fd) }
}

/// Transmits data to generate a break condition.
///
/// If the terminal device is using asynchronous data transmission, `tcsendbreak()` transmits a
/// continuous stream of zero bits for a specific duration.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `duration` controls the duration of the transmitted zero bits. A value of 0 causes a
///   transmission between 0.25 and 0.5 seconds. A value other than 0 causes a transmission for an
///   implementation-defined period of time.
pub fn tcsendbreak(fd: RawFd, duration: c_int) -> io::Result<()> {
    io_result(unsafe { ffi::tcsendbreak(fd, duration) })
}

#[inline]
fn io_result(result: c_int) -> io::Result<()> {
    match result {
        0 => Ok(()),
        _ => Err(io::Error::last_os_error())
    }
}
<commit_msg>removes unsafe constructor<commit_after>//! The `termios` crate provides Rust bindings for the POSIX termios API that is implemented on
//! most Unix operating systems. The termios API is defined in the [IEEE Std 1003.1 ("POSIX.1")
//! specification](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html).

extern crate libc;

use std::io;
use std::mem;
use std::os::unix::io::RawFd;

use libc::{c_int,pid_t};

pub use os::{cc_t,speed_t,tcflag_t}; // types
pub use os::{VEOF,VEOL,VERASE,VINTR,VKILL,VMIN,VQUIT,VSTART,VSTOP,VSUSP,VTIME}; // c_cc subscripts
pub use os::{BRKINT,ICRNL,IGNBRK,IGNCR,IGNPAR,INLCR,INPCK,ISTRIP,IXANY,IXOFF,IXON,PARMRK}; // input modes
pub use os::{OPOST,ONLCR,OCRNL,ONOCR,ONLRET,OFILL,NLDLY,NL0,NL1,CRDLY,CR0,CR1,CR2,CR3,TABDLY,TAB0,TAB1,TAB2,TAB3,BSDLY,BS0,BS1,VTDLY,VT0,VT1,FFDLY,FF0,FF1}; // output modes
pub use os::{B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400}; // baud rate selection
pub use os::{CSIZE,CS5,CS6,CS7,CS8,CSTOPB,CREAD,PARENB,PARODD,HUPCL,CLOCAL}; // control modes
pub use os::{ECHO,ECHOE,ECHOK,ECHONL,ICANON,IEXTEN,ISIG,NOFLSH,TOSTOP}; // local modes
pub use os::{TCSANOW,TCSADRAIN,TCSAFLUSH}; // attribute selection
pub use os::{TCIFLUSH,TCIOFLUSH,TCOFLUSH,TCIOFF,TCION,TCOOFF,TCOON}; // line control

pub mod ffi;
pub mod os;

pub type Termios = os::termios;

impl Termios {
    /// Creates a `Termios` structure based on the current settings of a file descriptor.
    pub fn from_fd(fd: RawFd) -> io::Result<Termios> {
        let mut termios = unsafe { mem::uninitialized() };

        match tcgetattr(fd, &mut termios) {
            Ok(_) => Ok(termios),
            Err(err) => Err(err)
        }
    }
}

/// Gets the input baud rate stored in a `Termios` structure.
///
/// # Examples
///
/// ```
/// # use std::mem;
/// # use termios::{Termios,B9600,cfsetispeed,cfgetispeed};
/// # let mut termios = unsafe { mem::uninitialized() };
/// cfsetispeed(&mut termios, B9600).unwrap();
/// assert_eq!(cfgetispeed(&termios), B9600);
/// ```
pub fn cfgetispeed(termios: &Termios) -> speed_t {
    unsafe { ffi::cfgetispeed(termios) }
}

/// Gets the output baud rate stored in a `Termios` structure.
///
/// # Examples
///
/// ```
/// # use std::mem;
/// # use termios::{Termios,B9600,cfsetospeed,cfgetospeed};
/// # let mut termios = unsafe { mem::uninitialized() };
/// cfsetospeed(&mut termios, B9600).unwrap();
/// assert_eq!(cfgetospeed(&termios), B9600);
/// ```
pub fn cfgetospeed(termios: &Termios) -> speed_t {
    unsafe { ffi::cfgetospeed(termios) }
}

/// Sets the input baud rate.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied by a subsequent call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Parameters
///
/// * `termios` should be a mutable reference to a `Termios` structure.
/// * `speed` should be one of the baud rate constants:
///   - `B0`
///   - `B50`
///   - `B75`
///   - `B110`
///   - `B134`
///   - `B150`
///   - `B200`
///   - `B300`
///   - `B600`
///   - `B1200`
///   - `B1800`
///   - `B2400`
///   - `B4800`
///   - `B9600`
///   - `B19200`
///   - `B38400`
///   - any OS-specific baud rate defined in [`termios::os`](os/index.html).
///
/// A value of `B0` for `speed` sets the input baud rate to be the same as the output baud rate.
///
/// # Examples
///
/// ```
/// # use std::mem;
/// # use termios::{Termios,B9600,cfsetispeed,cfgetispeed};
/// # let mut termios = unsafe { mem::uninitialized() };
/// cfsetispeed(&mut termios, B9600).unwrap();
/// assert_eq!(cfgetispeed(&termios), B9600);
/// ```
pub fn cfsetispeed(termios: &mut Termios, speed: speed_t) -> io::Result<()> {
    io_result(unsafe { ffi::cfsetispeed(termios, speed) })
}

/// Sets the output baud rate.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied on a successful call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Parameters
///
/// * `termios` should be a mutable reference to a `Termios` structure.
/// * `speed` should be one of the baud rate constants:
///   - `B0` (hang up)
///   - `B50`
///   - `B75`
///   - `B110`
///   - `B134`
///   - `B150`
///   - `B200`
///   - `B300`
///   - `B600`
///   - `B1200`
///   - `B1800`
///   - `B2400`
///   - `B4800`
///   - `B9600`
///   - `B19200`
///   - `B38400`
///   - any OS-specific baud rate defined in [`termios::os`](os/index.html).
///
/// A value of `B0` for `speed` deasserts the modem control lines when applied with
/// [`tcsetattr()`](fn.tcsetattr.html).  This normally has the effect of disconnecting the line.
///
/// # Examples
///
/// ```
/// # use std::mem;
/// # use termios::{Termios,B9600,cfsetospeed,cfgetospeed};
/// # let mut termios = unsafe { mem::uninitialized() };
/// cfsetospeed(&mut termios, B9600).unwrap();
/// assert_eq!(cfgetospeed(&termios), B9600);
/// ```
pub fn cfsetospeed(termios: &mut Termios, speed: speed_t) -> io::Result<()> {
    io_result(unsafe { ffi::cfsetospeed(termios, speed) })
}

/// Sets input and output baud rates.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied on a successful call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Parameters
///
/// * `termios` should be a mutable reference to a `Termios` structure.
/// * `speed` should be one of the baud rate constants:
///   - `B0`
///   - `B50`
///   - `B75`
///   - `B110`
///   - `B134`
///   - `B150`
///   - `B200`
///   - `B300`
///   - `B600`
///   - `B1200`
///   - `B1800`
///   - `B2400`
///   - `B4800`
///   - `B9600`
///   - `B19200`
///   - `B38400`
///   - any OS-specific baud rate defined in [`termios::os`](os/index.html).
///
/// # Examples
///
/// ```
/// # use std::mem;
/// # use termios::{Termios,B9600,cfsetspeed,cfgetispeed,cfgetospeed};
/// # let mut termios = unsafe { mem::uninitialized() };
/// cfsetspeed(&mut termios, B9600).unwrap();
/// assert_eq!(cfgetispeed(&termios), B9600);
/// assert_eq!(cfgetospeed(&termios), B9600);
/// ```
///
/// # Portability
///
/// This function is not part of the IEEE Std 1003.1 ("POSIX.1") specification, but it is available
/// on Linux, BSD, and OS X.
pub fn cfsetspeed(termios: &mut Termios, speed: speed_t) -> io::Result<()> {
    io_result(unsafe { ffi::cfsetspeed(termios, speed) })
}

/// Sets flags to disable all input and output processing.
///
/// This function only sets the necessary values on the given `Termios` structure. The settings are
/// applied on a successful call to [`tcsetattr()`](fn.tcsetattr.html).
///
/// # Portability
///
/// This function is not part of the IEEE Std 1003.1 ("POSIX.1") specification, but it is available
/// on Linux, BSD, and OS X.
pub fn cfmakeraw(termios: &mut Termios) {
    unsafe { ffi::cfmakeraw(termios) };
}

/// Blocks until all output written to the file descriptor is transmitted.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
pub fn tcdrain(fd: RawFd) -> io::Result<()> {
    io_result(unsafe { ffi::tcdrain(fd) })
}

/// Suspends or restarts transmission or reception of data.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `action` should be one of the following constants:
///   - `TCOOFF` suspends output.
///   - `TCOON` restarts output.
///   - `TCIOFF` transmits a STOP character, intended to cause the remote device to stop
///     transmitting.
///   - `TCION` transmits a START character, intended to cause the remote device to resume
///     transmitting.
pub fn tcflow(fd: RawFd, action: c_int) -> io::Result<()> {
    io_result(unsafe { ffi::tcflow(fd, action) })
}

/// Discards data waiting in the terminal device's buffers.
///
/// `tcflush()` discards data that has been written to the device by an application but has not yet
/// been transmitted by the hardware or data that has been received by the hardware but has not yet
/// been read by an application.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `queue_selector` should be one of:
///   - `TCIFLUSH` to discard data received but not read.
///   - `TCOFLUSH` to discard data written but not transmitted.
///   - `TCIOFLUSH` to discard both data received but not read and data written but not
///     transmitted.
pub fn tcflush(fd: RawFd, queue_selector: c_int) -> io::Result<()> {
    io_result(unsafe { ffi::tcflush(fd, queue_selector) })
}

/// Populates a `Termios` structure with parameters associated with a terminal.
///
/// Upon successful completion, the `Termios` structure referred to by the `termios` parameter will
/// contain the parameters associated with the terminal device referred to by `fd`.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `termios` should be a mutable reference to the `Termios` structure that will hold the
///   terminal device's parameters.
pub fn tcgetattr(fd: RawFd, termios: &mut Termios) -> io::Result<()> {
    io_result(unsafe { ffi::tcgetattr(fd, termios) })
}

/// Sets a terminal device's parameters.
///
/// `tcsetattr()` returns successfully if it was able to perform any of the requested actions, even
/// if other requested actions could not be performed. It will set all attributes that the
/// implementation supports and leave others unchanged. The `Termios` structure will not be updated
/// to reflect the changes that were applied.
///
/// In order to determine which parameters were applied to the terminal device, an application
/// should use [`tcgetattr()`](fn.tcgetattr.html) to obtain the latest state of the terminal
/// device. In particular, when attempting to change baud rates, [`tcgetattr()`](fn.tcgetattr.html)
/// can be used to determine which baud rates were actually selected.
///
/// If none of the requested actions could be performed, then `tcsetattr()` returns an error.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `action` should be one of the constants:
///   - `TCSANOW` applies the change immediately.
///   - `TCSADRAIN` applies the change after all output previously written to `fd` is transmitted.
///     This mode should be used when changing parameters that affect output.
///   - `TCSAFLUSH` applies the change after all output previously written to `fd` is transmitted.
///     All data received but not read is discarded before applying the change.
/// * `termios` should be a mutable reference to a `Termios` structure containing the parameters to
///   apply to the terminal device.
pub fn tcsetattr(fd: RawFd, action: c_int, termios: &Termios) -> io::Result<()> {
    io_result(unsafe { ffi::tcsetattr(fd, action, termios) })
}

/// Returns the process group ID of the controlling terminal's session.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a controlling terminal.
pub fn tcgetsid(fd: RawFd) -> pid_t {
    unsafe { ffi::tcgetsid(fd) }
}

/// Transmits data to generate a break condition.
///
/// If the terminal device is using asynchronous data transmission, `tcsendbreak()` transmits a
/// continuous stream of zero bits for a specific duration.
///
/// # Parameters
///
/// * `fd` should be an open file descriptor associated with a terminal.
/// * `duration` controls the duration of the transmitted zero bits. A value of 0 causes a
///   transmission between 0.25 and 0.5 seconds. A value other than 0 causes a transmission for an
///   implementation-defined period of time.
pub fn tcsendbreak(fd: RawFd, duration: c_int) -> io::Result<()> {
    io_result(unsafe { ffi::tcsendbreak(fd, duration) })
}

#[inline]
fn io_result(result: c_int) -> io::Result<()> {
    match result {
        0 => Ok(()),
        _ => Err(io::Error::last_os_error())
    }
}
<|endoftext|>