<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

//! # Cap'n Proto Runtime Library
//!
//! [Cap'n Proto](http://kentonv.github.io/capnproto/) is an extremely efficient protocol for
//! sharing data and capabilities.
//!
//! The Rust implementation is split into three separate crates.
//!
//! Code generation is handled by [capnpc-rust](https://github.com/dwrensha/capnpc-rust).
//!
//! The present crate is the runtime library required by that generated code. It is hosted on Github
//! [here](https://github.com/dwrensha/capnproto-rust).
//!
//! [capnp-rpc-rust](https://github.com/dwrensha/capnp-rpc-rust) is an implementation of a
//! distributed object-capability layer.

#![feature(alloc, core, io, unsafe_destructor)]
#![allow(raw_pointer_derive)]

#![crate_name="capnp"]
#![crate_type = "lib"]

// reexports
pub use message::{MessageBuilder, BuilderOptions, MessageReader, ReaderOptions};
pub use message::MallocMessageBuilder;
pub use serialize::OwnedSpaceMessageReader;

pub mod any_pointer;
pub mod capability;
pub mod data;
pub mod data_list;
pub mod enum_list;
pub mod private;
pub mod io;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod serialize;
pub mod serialize_packed;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;

/// Eight bytes of memory with opaque interior.
///
/// This type is used to ensure that the data of a message is properly aligned.
#[derive(Copy)]
#[repr(C)]
pub struct Word {_unused_member : u64}

impl Word {
    /// Do this, but faster:
    /// `::std::iter::repeat(Word{ _unused_member : 0}).take(length).collect()`
    pub fn allocate_zeroed_vec(length : usize) -> ::std::vec::Vec<Word> {
        let mut result : ::std::vec::Vec<Word> = ::std::vec::Vec::with_capacity(length);
        unsafe {
            result.set_len(length);
            let p : *mut u8 = ::std::mem::transmute(result.as_mut_slice().as_mut_ptr());
            ::std::ptr::write_bytes(p, 0u8, length * ::std::mem::size_of::<Word>());
        }
        return result;
    }

    pub fn bytes_to_words<'a>(bytes : &'a [u8]) -> &'a [Word] {
        unsafe {
            ::std::slice::from_raw_parts(::std::mem::transmute(bytes.as_ptr()), bytes.len() / 8)
        }
    }

    pub fn words_to_bytes<'a>(words : &'a [Word]) -> &'a [u8] {
        unsafe {
            ::std::slice::from_raw_parts(::std::mem::transmute(words.as_ptr()), words.len() * 8)
        }
    }
}

/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
#[derive(Copy, PartialEq)]
pub struct MessageSize {
    pub word_count : u64,

    /// Size of the capability table.
    pub cap_count : u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

/// An enum value or union discriminant that was not found among those defined in a schema.
#[derive(PartialEq, Copy, Debug)]
pub struct NotInSchema(pub u16);

/// Because messages are lazily validated, the return type of any method that reads a pointer field
/// must be wrapped in a Result.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Things that can go wrong when you read a message.
#[derive(Debug, PartialEq)]
pub enum Error {
    Decode { description : &'static str,
             detail : Option<String> },
    Io(std::io::Error),
}

impl Error {
    pub fn new_decode_error(description : &'static str, detail : Option<String>) -> Error {
        Error::Decode { description : description, detail : detail}
    }
}

impl ::std::error::FromError<::std::io::Error> for Error {
    fn from_error(err : ::std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl ::std::error::FromError<NotInSchema> for Error {
    fn from_error(NotInSchema(x) : NotInSchema) -> Error {
        Error::new_decode_error("Enum value or union descriminant not in schema.",
                                Some(format!("value : {}", x)))
    }
}

impl ::std::error::FromError<::std::str::Utf8Error> for Error {
    fn from_error(err : ::std::str::Utf8Error) -> Error {
        Error::new_decode_error("Text contains non-utf8 data.",
                                Some(format!("{:?}", err)))
    }
}
<commit_msg>impl ::std::error::Error for capnp::Error<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

//! # Cap'n Proto Runtime Library
//!
//! [Cap'n Proto](http://kentonv.github.io/capnproto/) is an extremely efficient protocol for
//! sharing data and capabilities.
//!
//! The Rust implementation is split into three separate crates.
//!
//! Code generation is handled by [capnpc-rust](https://github.com/dwrensha/capnpc-rust).
//!
//! The present crate is the runtime library required by that generated code. It is hosted on Github
//! [here](https://github.com/dwrensha/capnproto-rust).
//!
//! [capnp-rpc-rust](https://github.com/dwrensha/capnp-rpc-rust) is an implementation of a
//! distributed object-capability layer.

#![feature(alloc, core, io, unsafe_destructor)]
#![allow(raw_pointer_derive)]

#![crate_name="capnp"]
#![crate_type = "lib"]

// reexports
pub use message::{MessageBuilder, BuilderOptions, MessageReader, ReaderOptions};
pub use message::MallocMessageBuilder;
pub use serialize::OwnedSpaceMessageReader;

pub mod any_pointer;
pub mod capability;
pub mod data;
pub mod data_list;
pub mod enum_list;
pub mod private;
pub mod io;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod serialize;
pub mod serialize_packed;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;

/// Eight bytes of memory with opaque interior.
///
/// This type is used to ensure that the data of a message is properly aligned.
#[derive(Copy)]
#[repr(C)]
pub struct Word {_unused_member : u64}

impl Word {
    /// Do this, but faster:
    /// `::std::iter::repeat(Word{ _unused_member : 0}).take(length).collect()`
    pub fn allocate_zeroed_vec(length : usize) -> ::std::vec::Vec<Word> {
        let mut result : ::std::vec::Vec<Word> = ::std::vec::Vec::with_capacity(length);
        unsafe {
            result.set_len(length);
            let p : *mut u8 = ::std::mem::transmute(result.as_mut_slice().as_mut_ptr());
            ::std::ptr::write_bytes(p, 0u8, length * ::std::mem::size_of::<Word>());
        }
        return result;
    }

    pub fn bytes_to_words<'a>(bytes : &'a [u8]) -> &'a [Word] {
        unsafe {
            ::std::slice::from_raw_parts(::std::mem::transmute(bytes.as_ptr()), bytes.len() / 8)
        }
    }

    pub fn words_to_bytes<'a>(words : &'a [Word]) -> &'a [u8] {
        unsafe {
            ::std::slice::from_raw_parts(::std::mem::transmute(words.as_ptr()), words.len() * 8)
        }
    }
}

/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
#[derive(Copy, PartialEq)]
pub struct MessageSize {
    pub word_count : u64,

    /// Size of the capability table.
    pub cap_count : u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

/// An enum value or union discriminant that was not found among those defined in a schema.
#[derive(PartialEq, Copy, Debug)]
pub struct NotInSchema(pub u16);

/// Because messages are lazily validated, the return type of any method that reads a pointer field
/// must be wrapped in a Result.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Things that can go wrong when you read a message.
#[derive(Debug, PartialEq)]
pub enum Error {
    Decode { description : &'static str,
             detail : Option<String> },
    Io(std::io::Error),
}

impl Error {
    pub fn new_decode_error(description : &'static str, detail : Option<String>) -> Error {
        Error::Decode { description : description, detail : detail}
    }
}

impl ::std::error::FromError<::std::io::Error> for Error {
    fn from_error(err : ::std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl ::std::error::FromError<NotInSchema> for Error {
    fn from_error(NotInSchema(x) : NotInSchema) -> Error {
        Error::new_decode_error("Enum value or union descriminant not in schema.",
                                Some(format!("value : {}", x)))
    }
}

impl ::std::error::FromError<::std::str::Utf8Error> for Error {
    fn from_error(err : ::std::str::Utf8Error) -> Error {
        Error::new_decode_error("Text contains non-utf8 data.",
                                Some(format!("{:?}", err)))
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, fmt : &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Decode { ref description, detail : Some(ref detail) } => {
                write!(fmt, "{} {}", description, detail)
            },
            Error::Decode { ref description, .. } => write!(fmt, "{}", description),
            Error::Io(ref io) => io.fmt(fmt),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Decode { ref description, .. } => description,
            Error::Io(ref io) => ::std::error::Error::description(io),
        }
    }
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Decode { .. } => None,
            Error::Io(ref io) => io.cause(),
        }
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
//! # ulid-rs
//!
//! This is a Rust implementation of the [ulid][ulid] project which provides
//! Universally Unique Lexicographically Sortable Identifiers.
//!
//! [ulid]: https://github.com/alizain/ulid
//!
//!
//! ## Quickstart
//!
//! ```rust
//! # use ulid::Ulid;
//! // Generate a ulid
//! let ulid = Ulid::new();
//!
//! // Generate a string for a ulid
//! let s = ulid.to_string();
//!
//! // Create from a String
//! let res = Ulid::from_string(&s);
//!
//! assert_eq!(ulid, res.unwrap());
//! ```

extern crate chrono;
#[macro_use] extern crate lazy_static;
extern crate rand;

mod base32;

use chrono::prelude::{DateTime, UTC, TimeZone};
pub use base32::EncodingError;

/// A Ulid is a unique 128-bit lexicographically sortable identifier
///
/// Canonically, it is represented as a 26 character Crockford Base32 encoded
/// string.
///
/// Of the 128-bits, the first 48 are a unix timestamp in milliseconds. The
/// remaining 80 are random. The first 48 provide for lexicographic sorting and
/// the remaining 80 ensure that the identifier is unique.
#[derive(Debug, PartialOrd, PartialEq, Clone)]
pub struct Ulid(u64, u64);

impl Ulid {

	/// Creates a new Ulid with the current time
	pub fn new() -> Ulid {
		Ulid::from_datetime(UTC::now())
	}

	/// Creates a new Ulid with the given datetime
	///
	/// This can be useful when migrating data to use Ulid identifiers
	pub fn from_datetime<T: TimeZone>(datetime: DateTime<T>) -> Ulid {
		let timestamp = datetime.timestamp() * 1000
			+ (datetime.timestamp_subsec_millis() as i64);

		let timebits = (timestamp & ((1<<48)-1)) as u64;

		return Ulid(
			timebits << 16 | rand::random::<u16>() as u64,
			rand::random::<u64>()
		);
	}

	/// Creates a Ulid from a Crockford Base32 encoded string
	///
	/// An EncodingError will be returned when the given string is not formated
	/// properly.
	pub fn from_string(encoded: &str) -> Result<Ulid, EncodingError> {
		return base32::decode(encoded)
			.map(|(msb, lsb)| Ulid(msb, lsb));
	}

	/// Gets the datetime of when this Ulid was created accurate to 1ms
	pub fn datetime(&self) -> DateTime<UTC> {
		let stamp = self.0 >> 16;
		let secs = stamp / 1000;
		let millis = stamp % 1000;
		return UTC.timestamp(secs as i64, (millis*1000000) as u32);
	}

	/// Creates a Crockford Base32 encoded string that represents this Ulid
	pub fn to_string(&self) -> String {
		return base32::encode(self.0, self.1);
	}

}

impl <'a> Into<String> for &'a Ulid {
	fn into(self) -> String {
		self.to_string()
	}
}

#[cfg(test)]
mod tests {
	use super::Ulid;
	use chrono::prelude::*;
	use chrono::Duration;

	#[test]
	fn test_dynamic() {
		let ulid = Ulid::new();
		let encoded = ulid.to_string();
		let ulid2 = Ulid::from_string(&encoded)
			.expect("failed to deserialize");

		println!("{}", encoded);
		println!("{:?}", ulid);
		println!("{:?}", ulid2);
		assert_eq!(ulid, ulid2);
	}

	#[test]
	fn test_static() {
		let s = Ulid(0x4141414141414141, 0x4141414141414141).to_string();
		let u = Ulid::from_string(&s).unwrap();
		assert_eq!(&s, "21850M2GA1850M2GA1850M2GA1");
		assert_eq!(u.0, 0x4141414141414141);
		assert_eq!(u.1, 0x4141414141414141);
	}

	#[test]
	fn test_order() {
		let dt = UTC::now();
		let ulid1 = Ulid::from_datetime(dt);
		let ulid2 = Ulid::from_datetime(dt + Duration::milliseconds(1));
		assert!(ulid1 < ulid2);
	}

	#[test]
	fn test_datetime() {
		let dt = UTC::now();
		let ulid = Ulid::from_datetime(dt);

		println!("{:?}, {:?}", dt, ulid.datetime());
		assert!(ulid.datetime() <= dt);
		assert!(ulid.datetime() + Duration::milliseconds(1) >= dt);
	}
}
<commit_msg>add timestamp getter and tuple conversions<commit_after>#![warn(missing_docs)]
//! # ulid-rs
//!
//! This is a Rust implementation of the [ulid][ulid] project which provides
//! Universally Unique Lexicographically Sortable Identifiers.
//!
//! [ulid]: https://github.com/alizain/ulid
//!
//!
//! ## Quickstart
//!
//! ```rust
//! # use ulid::Ulid;
//! // Generate a ulid
//! let ulid = Ulid::new();
//!
//! // Generate a string for a ulid
//! let s = ulid.to_string();
//!
//! // Create from a String
//! let res = Ulid::from_string(&s);
//!
//! assert_eq!(ulid, res.unwrap());
//! ```

extern crate chrono;
#[macro_use] extern crate lazy_static;
extern crate rand;

mod base32;

use chrono::prelude::{DateTime, UTC, TimeZone};
pub use base32::EncodingError;

/// A Ulid is a unique 128-bit lexicographically sortable identifier
///
/// Canonically, it is represented as a 26 character Crockford Base32 encoded
/// string.
///
/// Of the 128-bits, the first 48 are a unix timestamp in milliseconds. The
/// remaining 80 are random. The first 48 provide for lexicographic sorting and
/// the remaining 80 ensure that the identifier is unique.
#[derive(Debug, PartialOrd, PartialEq, Clone)]
pub struct Ulid(pub u64, pub u64);

impl Ulid {

	/// Creates a new Ulid with the current time
	pub fn new() -> Ulid {
		Ulid::from_datetime(UTC::now())
	}

	/// Creates a new Ulid with the given datetime
	///
	/// This can be useful when migrating data to use Ulid identifiers
	pub fn from_datetime<T: TimeZone>(datetime: DateTime<T>) -> Ulid {
		let timestamp = datetime.timestamp() * 1000
			+ (datetime.timestamp_subsec_millis() as i64);

		let timebits = (timestamp & ((1<<48)-1)) as u64;

		return Ulid(
			timebits << 16 | rand::random::<u16>() as u64,
			rand::random::<u64>()
		);
	}

	/// Creates a Ulid from a Crockford Base32 encoded string
	///
	/// An EncodingError will be returned when the given string is not formated
	/// properly.
	pub fn from_string(encoded: &str) -> Result<Ulid, EncodingError> {
		return base32::decode(encoded)
			.map(|(msb, lsb)| Ulid(msb, lsb));
	}

	/// Gets the datetime of when this Ulid was created accurate to 1ms
	pub fn datetime(&self) -> DateTime<UTC> {
		let stamp = self.0 >> 16;
		let secs = stamp / 1000;
		let millis = stamp % 1000;
		return UTC.timestamp(secs as i64, (millis*1000000) as u32);
	}

	/// Gets the timestamp section of this ulid
	pub fn timestamp_ms(&self) -> u64 {
		return self.0 >> 16;
	}

	/// Creates a Crockford Base32 encoded string that represents this Ulid
	pub fn to_string(&self) -> String {
		return base32::encode(self.0, self.1);
	}

}

impl <'a> Into<String> for &'a Ulid {
	fn into(self) -> String {
		self.to_string()
	}
}

impl From<(u64, u64)> for Ulid {
	fn from(tuple: (u64, u64)) -> Self {
		Ulid(tuple.0, tuple.1)
	}
}

impl Into<(u64, u64)> for Ulid {
	fn into(self) -> (u64, u64) {
		(self.0, self.1)
	}
}

#[cfg(test)]
mod tests {
	use super::Ulid;
	use chrono::prelude::*;
	use chrono::Duration;

	#[test]
	fn test_dynamic() {
		let ulid = Ulid::new();
		let encoded = ulid.to_string();
		let ulid2 = Ulid::from_string(&encoded)
			.expect("failed to deserialize");

		println!("{}", encoded);
		println!("{:?}", ulid);
		println!("{:?}", ulid2);
		assert_eq!(ulid, ulid2);
	}

	#[test]
	fn test_static() {
		let s = Ulid(0x4141414141414141, 0x4141414141414141).to_string();
		let u = Ulid::from_string(&s).unwrap();
		assert_eq!(&s, "21850M2GA1850M2GA1850M2GA1");
		assert_eq!(u.0, 0x4141414141414141);
		assert_eq!(u.1, 0x4141414141414141);
	}

	#[test]
	fn test_order() {
		let dt = UTC::now();
		let ulid1 = Ulid::from_datetime(dt);
		let ulid2 = Ulid::from_datetime(dt + Duration::milliseconds(1));
		assert!(ulid1 < ulid2);
	}

	#[test]
	fn test_datetime() {
		let dt = UTC::now();
		let ulid = Ulid::from_datetime(dt);

		println!("{:?}, {:?}", dt, ulid.datetime());
		assert!(ulid.datetime() <= dt);
		assert!(ulid.datetime() + Duration::milliseconds(1) >= dt);
	}

	#[test]
	fn test_timestamp() {
		let dt = UTC::now();
		let ulid = Ulid::from_datetime(dt);
		let ts = dt.timestamp() as u64 * 1000 + dt.timestamp_subsec_millis() as u64;

		assert_eq!(ulid.timestamp_ms(), ts);
	}
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate json;

pub mod request;
pub mod response;

pub use request::{get, post, put, head, delete};
pub use response::Response;

pub type RequestsResult = hyper::Result<Response>;

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

    #[test]
    fn simple_get() {
        const URL: &'static str = "http://httpbin.org/get";
        let res = get(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
        let data = res.json().unwrap();
        println!("{:?}", data);
        assert!(data["url"].is(URL));
        assert!(data["headers"]["Host"].is("httpbin.org"));
        assert!(data["headers"]["User-Agent"]
            .is(concat!("requests-rs/", env!("CARGO_PKG_VERSION"))));
    }

    #[test]
    fn simple_post() {
        const URL: &'static str = "http://httpbin.org/post";
        let res = post(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn simple_put() {
        const URL: &'static str = "http://httpbin.org/put";
        let res = put(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn simple_head() {
        const URL: &'static str = "http://httpbin.org/get";
        let res = head(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn simple_delete() {
        const URL: &'static str = "http://httpbin.org/delete";
        let res = delete(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn user_agent() {
        let useragent = concat!("{\n  \"user-agent\": \"requests-rs/",
                                env!("CARGO_PKG_VERSION"),
                                "\"\n}\n");
        const URL: &'static str = "http://httpbin.org/user-agent";
        let res = get(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
        assert_eq!(res.text(), Some(useragent));
    }

    #[test]
    fn user_agent_json() {

        const URL: &'static str = "http://httpbin.org/user-agent";
        let res = get(URL).unwrap();
        assert!(res.is_json());

        let ua = res.json().unwrap();
        assert!(ua["user-agent"].is(concat!("requests-rs/", env!("CARGO_PKG_VERSION"))));
    }
}
<commit_msg>Update for latest json API<commit_after>extern crate hyper;
extern crate json;

pub mod request;
pub mod response;

pub use request::{get, post, put, head, delete};
pub use response::Response;

pub type RequestsResult = hyper::Result<Response>;

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

    #[test]
    fn simple_get() {
        const URL: &'static str = "http://httpbin.org/get";
        let res = get(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
        let data = res.json().unwrap();
        println!("{:?}", data);
        assert_eq!(data["url"], URL);
        assert_eq!(data["headers"]["Host"], "httpbin.org");
        assert_eq!(data["headers"]["User-Agent"],
            concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
    }

    #[test]
    fn simple_post() {
        const URL: &'static str = "http://httpbin.org/post";
        let res = post(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn simple_put() {
        const URL: &'static str = "http://httpbin.org/put";
        let res = put(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn simple_head() {
        const URL: &'static str = "http://httpbin.org/get";
        let res = head(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn simple_delete() {
        const URL: &'static str = "http://httpbin.org/delete";
        let res = delete(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
    }

    #[test]
    fn user_agent() {
        let useragent = concat!("{\n  \"user-agent\": \"requests-rs/",
                                env!("CARGO_PKG_VERSION"),
                                "\"\n}\n");
        const URL: &'static str = "http://httpbin.org/user-agent";
        let res = get(URL).unwrap();
        assert_eq!(res.url(), URL);
        assert_eq!(res.status_code(), hyper::Ok);
        assert_eq!(res.reason(), "OK");
        assert_eq!(res.text(), Some(useragent));
    }

    #[test]
    fn user_agent_json() {

        const URL: &'static str = "http://httpbin.org/user-agent";
        let res = get(URL).unwrap();
        assert!(res.is_json());

        let ua = res.json().unwrap();
        assert_eq!(ua["user-agent"], concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate byteorder;

mod ntp;

use std::net::UdpSocket;
use time::Timespec;

const NTP_PORT: u16 = 123;
const UDP_LOCAL: &'static str = "0.0.0.0:35000";

/// `retrieve_ntp_timestamp` retrieves the current time from a NTP server.
///
/// # Arguments
///
/// * `host` - The NTP server (i.e. sundial.columbia.edu).
pub fn retrieve_ntp_timestamp(host: &str) -> Result<Timespec, std::io::Error> {
    let header = ntp::NTPHeader::new();
    let message = try!(header.encode());

    let socket = try!(UdpSocket::bind(UDP_LOCAL));

    let host = format!("{host}:{port}", host=host, port=NTP_PORT);
    try!(socket.send_to(&message[..], &host[..]));

    let mut buf = [0u8; 1000];

    // TODO: Rust doesn't support timeouts yet
    let (amt, _) = try!(socket.recv_from(buf.as_mut_slice()));

    drop(socket);

    let header = try!(ntp::NTPHeader::decode(amt, &buf));

    Ok(header.transmit_timestamp.as_timespec())
}

#[test]
fn receive_timestamp() {
    const NTP_SERVER: &'static str = "sundial.columbia.edu";

    let t1 = retrieve_ntp_timestamp(NTP_SERVER).unwrap();
    let t2 = retrieve_ntp_timestamp(NTP_SERVER).unwrap();

    assert!(t2 > t1);
}
<commit_msg>[WIP] enable io::Error::new for a while<commit_after>#![feature(io)]
extern crate time;
extern crate byteorder;

mod ntp;

use std::net::UdpSocket;
use time::Timespec;

const NTP_PORT: u16 = 123;
const UDP_LOCAL: &'static str = "0.0.0.0:35000";

/// `retrieve_ntp_timestamp` retrieves the current time from a NTP server.
///
/// # Arguments
///
/// * `host` - The NTP server (i.e. sundial.columbia.edu).
pub fn retrieve_ntp_timestamp(host: &str) -> Result<Timespec, std::io::Error> {
    let header = ntp::NTPHeader::new();
    let message = try!(header.encode());

    let socket = try!(UdpSocket::bind(UDP_LOCAL));

    let host = format!("{host}:{port}", host=host, port=NTP_PORT);
    try!(socket.send_to(&message[..], &host[..]));

    let mut buf = [0u8; 1000];

    // TODO: Rust doesn't support timeouts yet
    let (amt, _) = try!(socket.recv_from(buf.as_mut_slice()));

    drop(socket);

    let header = try!(ntp::NTPHeader::decode(amt, &buf));

    Ok(header.transmit_timestamp.as_timespec())
}

#[test]
fn receive_timestamp() {
    const NTP_SERVER: &'static str = "sundial.columbia.edu";

    let t1 = retrieve_ntp_timestamp(NTP_SERVER).unwrap();
    let t2 = retrieve_ntp_timestamp(NTP_SERVER).unwrap();

    assert!(t2 > t1);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

//! A wrapper around [cfitsio].
//!
//! This wrapper attempts to add some safety to the [cfitsio] library, and allows `.fits` files to
//! be read from rust.
//!
//! The main entry point to the code is `FitsFile::open` which creates a new file, and
//! `FitsFile::create` which creates a new file.
//!
//! [cfitsio]: https://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html

pub mod raw;

extern crate libc;

use raw::*;
use libc::{c_int, c_long, c_char, c_void};
use std::ptr;
use std::ffi;
use std::result;

/// Error type
#[derive(Debug)]
pub enum FitsError {
    FitsError {
        status: i32,
        message: String,
    },
}

pub type Result<T> = result::Result<T, FitsError>;

/// Internal function to get the fits error description from a status code
fn status_to_string(status: c_int) -> Option<String> {
    match status {
        0 => None,
        status => {
            let mut buffer: Vec<c_char> = vec![0; 31];
            unsafe {
                ffgerr(status, buffer.as_mut_ptr());
            }
            let result_str = String::from_utf8(buffer.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect())
                .unwrap();
            Some(result_str)
        }
    }
}

/// General type defining what kind of HDU we're talking about
#[derive(Eq, PartialEq, Debug)]
pub enum HduType {
    ImageHDU,
    AsciiTableHDU,
    BinTableHDU,
}

/// Wrapper around a C `fitsfile` pointer.
///
/// This handles [opening][FitsFile::open], [creating][FitsFile::create] and automatically
/// closing (through the `Drop` trait) the file.
///
/// All subsequent file access is controled through this object.
///
/// [FitsFile::open]: #method.open
/// [FitsFile::create]: #method.create
pub struct FitsFile {
    fptr: *mut fitsfile,
    status: c_int,
    pub filename: String,
}

impl FitsFile {
    /// Open a fits file for reading
    ///
    /// * `filename` - Filename to pass to `cfitsio`. Can conform to the
    /// [Extended Filename Syntax][extended-filename-syntax].
    ///
    /// [extended-filename-syntax]:
    ///     https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/node82.html
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    ///     match FitsFile::open("testdata/full_example.fits") {
    ///         Ok(f) => { },
    ///         Err(e) => panic!("{:?}", e),
    ///     }
    /// # }
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
        }

        return match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: filename.to_string(),
                })
            },
            status => Err(FitsError::FitsError {
                status: status,
                message: status_to_string(status).unwrap(),
            }),
        };

    }

    /// Create a new fits file
    ///
    /// An empty primary header is added so when the `drop` method is called, the file is valid.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate fitsio;
    /// # extern crate tempdir;
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let tdir = tempdir::TempDir::new("fitsio-").unwrap();
    /// # let tdir_path = tdir.path();
    /// # let filename = tdir_path.join("test.fits");
    /// # let filename = filename.to_str().unwrap();
    /// match FitsFile::create(filename) {
    ///     Ok(f) => println!("Fits file created ok"),
    ///     Err(e) => panic!("Error: {:?}", e),
    /// }
    /// # }
    /// ```
    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            ffinit(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   &mut status);
        }

        return match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: path.to_string(),
                })
            }
            status => Err(FitsError::FitsError {
                status: status,
                message: status_to_string(status).unwrap(),
            }),
        };
    }

    /// Function to check that the status code is ok.
    ///
    /// If the value of `self.status` is not 0 then exit the current process as an error has
    /// occurred.
    fn check(&self) {
        match self.status {
            0 => {}
            status => {
                panic!("Status code {} encountered, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }

    /// Returns the current HDU number, 0-indexed
    ///
    /// The FITS standard is 1-indexed (thanks Fortran), so this function
    /// converts the indexing to be 0-based so the primary HDU is at
    /// index 0.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// let f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// assert_eq!(f.current_hdu_number(), 0);
    /// ```
    pub fn current_hdu_number(&self) -> u32 {
        let mut hdu_num = 0;
        unsafe {
            ffghdn(self.fptr, &mut hdu_num);
        }
        self.check();
        assert!(hdu_num >= 1);
        (hdu_num - 1) as u32
    }

    /// Change the current HDU
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// assert_eq!(f.current_hdu_number(), 0);
    /// f.change_hdu(1);
    /// assert_eq!(f.current_hdu_number(), 1);
    /// # }
    /// ```
    pub fn change_hdu(&mut self, hdu_num: u32) {
        let mut _hdu_type = 0;
        unsafe {
            ffmahd(self.fptr,
                   (hdu_num + 1) as i32,
                   &mut _hdu_type,
                   &mut self.status);
        }
        self.check();
    }

    /// Get which type of HDU the current HDU is
    ///
    /// Results in one of the `HduType` options.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// // Primary HDUs are always image hdus
    /// assert_eq!(f.get_hdu_type(), HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu_type(&mut self) -> HduType {
        let mut hdu_type = 3;
        unsafe {
            ffghdt(self.fptr, &mut hdu_type, &mut self.status);
        }
        self.check();

        match hdu_type {
            0 => HduType::ImageHDU,
            1 => HduType::AsciiTableHDU,
            2 => HduType::BinTableHDU,
            _ => panic!("Unknown hdu type: {}", hdu_type),
        }
    }

    /// Return a `FitsHDU` object for the specified HDU
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// let primary_hdu = f.get_hdu(0);
    /// assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu(&mut self, index: usize) -> FitsHDU {
        self.change_hdu(index as u32);
        let hdu_type = self.get_hdu_type();

        let image_shape = if hdu_type == HduType::ImageHDU {
            let mut naxis = vec![0, 0];
            unsafe {
                ffgisz(self.fptr, 2, naxis.as_mut_ptr(), &mut self.status);
            }
            println!("{:?}", naxis);
            (naxis[0] as usize, naxis[1] as usize)
        } else {
            (0, 0)
        };

        FitsHDU {
            fitsfile: self,
            hdu_type: hdu_type,
            image_shape: image_shape,
        }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        unsafe {
            ffclos(self.fptr, &mut self.status);
        }
    }
}

/// Wrapper around a FITS HDU
///
/// This struct is the main interface around reading and writing the file contents.
pub struct FitsHDU<'a> {
    fitsfile: &'a FitsFile,
    pub hdu_type: HduType,
    image_shape: (usize, usize),
}

impl<'a> FitsHDU<'a> {
    /// Read a header key as a string
    ///
    /// The user is responsible for converting the value type from a string to whatever type the
    /// header key contains.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// let mut primary_hdu = f.get_hdu(0);
    /// // Image is 2-dimensional
    /// let naxis = primary_hdu.get_key("NAXIS").parse::<i32>().unwrap();
    /// assert_eq!(naxis, 2);
    /// # }
    /// ```
    pub fn get_key(&mut self, key: &str) -> String {
        let fptr = &self.fitsfile.fptr;
        let mut value: Vec<c_char> = vec![0; MAX_VALUE_LENGTH];
        let keyname = ffi::CString::new(key).unwrap();
        let mut status = 0;

        unsafe {
            ffgkys(*fptr,
                   keyname.as_ptr(),
                   value.as_mut_ptr(),
                   ptr::null_mut(),
                   &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                return String::from_utf8(value).unwrap();
            }
            _ => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }

    fn read_all_i32(&mut self, buffer: &mut Vec<i32>) {
        let npix = self.image_shape.0 * self.image_shape.1;
        buffer.resize(npix, 0);
        let mut status = 0;

        unsafe {
            ffgpv(self.fitsfile.fptr,
                  31, // TINT
                  1,
                  npix as i64,
                  ptr::null_mut() as *mut c_void,
                  buffer.as_mut_ptr() as *mut c_void,
                  ptr::null_mut(),
                  &mut status);
        }
        match status {
            0 => {}
            status => panic!("Bad status value: {}", status),
        }
        self.fitsfile.check();
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use super::status_to_string;

    #[test]
    fn returning_error_messages() {
        assert_eq!(status_to_string(105).unwrap(),
                   "couldn't create the named file");
    }

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("testdata/full_example.fits") {
            Ok(f) => assert_eq!(f.status, 0),
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(f) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn filename_is_stored() {
        let f = FitsFile::open("testdata/full_example.fits").unwrap();
        assert_eq!(f.filename, "testdata/full_example.fits");
    }

    #[test]
    fn change_hdu() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
        f.change_hdu(1);
        assert_eq!(f.current_hdu_number(), 1u32);
    }

    #[test]
    fn getting_current_hdu_number() {
        let f = FitsFile::open("testdata/full_example.fits").unwrap();
        assert_eq!(f.current_hdu_number(), 0u32);
    }

    #[test]
    fn getting_hdu_object() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();

        // TODO: get rid of these scopes
        //
        // They're there because `get_hdu` mutably borrows the `self` object and
        // the result is still in scope. We need to expire the `FitsHDU` objects
        // and hence the scopes.
        {
            let primary_hdu = f.get_hdu(0);
            assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
        }

        {
            let table_hdu = f.get_hdu(1);
            assert_eq!(table_hdu.hdu_type, HduType::BinTableHDU);
        }
    }

    #[test]
    fn reading_in_image_data() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
        let mut primary_hdu = f.get_hdu(0);
        let mut data = Vec::new();
        primary_hdu.read_all_i32(&mut data);
        assert_eq!(data[0], 108);
        assert_eq!(data[1], 176);
    }

    #[test]
    fn get_image_dimensions() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
        let primary_hdu = f.get_hdu(0);
        assert_eq!(primary_hdu.image_shape, (100, 100));
    }
}
<commit_msg>Simplify error struct<commit_after>#![allow(dead_code)]

//! A wrapper around [cfitsio].
//!
//! This wrapper attempts to add some safety to the [cfitsio] library, and allows `.fits` files to
//! be read from rust.
//!
//! The main entry point to the code is `FitsFile::open` which creates a new file, and
//! `FitsFile::create` which creates a new file.
//!
//! [cfitsio]: https://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html

pub mod raw;

extern crate libc;

use raw::*;
use libc::{c_int, c_long, c_char, c_void};
use std::ptr;
use std::ffi;
use std::result;

/// Error type
#[derive(Debug)]
pub struct FitsError {
    status: i32,
    message: String,
}

pub type Result<T> = result::Result<T, FitsError>;

/// Internal function to get the fits error description from a status code
fn status_to_string(status: c_int) -> Option<String> {
    match status {
        0 => None,
        status => {
            let mut buffer: Vec<c_char> = vec![0; 31];
            unsafe {
                ffgerr(status, buffer.as_mut_ptr());
            }
            let result_str = String::from_utf8(buffer.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect())
                .unwrap();
            Some(result_str)
        }
    }
}

/// General type defining what kind of HDU we're talking about
#[derive(Eq, PartialEq, Debug)]
pub enum HduType {
    ImageHDU,
    AsciiTableHDU,
    BinTableHDU,
}

/// Wrapper around a C `fitsfile` pointer.
///
/// This handles [opening][FitsFile::open], [creating][FitsFile::create] and automatically
/// closing (through the `Drop` trait) the file.
///
/// All subsequent file access is controled through this object.
///
/// [FitsFile::open]: #method.open
/// [FitsFile::create]: #method.create
pub struct FitsFile {
    fptr: *mut fitsfile,
    status: c_int,
    pub filename: String,
}

impl FitsFile {
    /// Open a fits file for reading
    ///
    /// * `filename` - Filename to pass to `cfitsio`. Can conform to the
    /// [Extended Filename Syntax][extended-filename-syntax].
    ///
    /// [extended-filename-syntax]:
    ///     https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/node82.html
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    ///     match FitsFile::open("testdata/full_example.fits") {
    ///         Ok(f) => { },
    ///         Err(e) => panic!("{:?}", e),
    ///     }
    /// # }
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
        }

        return match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: status_to_string(status).unwrap(),
                })
            }
        };

    }

    /// Create a new fits file
    ///
    /// An empty primary header is added so when the `drop` method is called, the file is valid.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate fitsio;
    /// # extern crate tempdir;
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let tdir = tempdir::TempDir::new("fitsio-").unwrap();
    /// # let tdir_path = tdir.path();
    /// # let filename = tdir_path.join("test.fits");
    /// # let filename = filename.to_str().unwrap();
    /// match FitsFile::create(filename) {
    ///     Ok(f) => println!("Fits file created ok"),
    ///     Err(e) => panic!("Error: {:?}", e),
    /// }
    /// # }
    /// ```
    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            ffinit(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   &mut status);
        }

        return match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: status_to_string(status).unwrap(),
                })
            }
        };
    }

    /// Function to check that the status code is ok.
    ///
    /// If the value of `self.status` is not 0 then exit the current process as an error has
    /// occurred.
    fn check(&self) {
        match self.status {
            0 => {}
            status => {
                panic!("Status code {} encountered, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }

    /// Returns the current HDU number, 0-indexed
    ///
    /// The FITS standard is 1-indexed (thanks Fortran), so this function
    /// converts the indexing to be 0-based so the primary HDU is at
    /// index 0.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// let f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// assert_eq!(f.current_hdu_number(), 0);
    /// ```
    pub fn current_hdu_number(&self) -> u32 {
        let mut hdu_num = 0;
        unsafe {
            ffghdn(self.fptr, &mut hdu_num);
        }
        self.check();
        assert!(hdu_num >= 1);
        (hdu_num - 1) as u32
    }

    /// Change the current HDU
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// assert_eq!(f.current_hdu_number(), 0);
    /// f.change_hdu(1);
    /// assert_eq!(f.current_hdu_number(), 1);
    /// # }
    /// ```
    pub fn change_hdu(&mut self, hdu_num: u32) {
        let mut _hdu_type = 0;
        unsafe {
            ffmahd(self.fptr,
                   (hdu_num + 1) as i32,
                   &mut _hdu_type,
                   &mut self.status);
        }
        self.check();
    }

    /// Get which type of HDU the current HDU is
    ///
    /// Results in one of the `HduType` options.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// // Primary HDUs are always image hdus
    /// assert_eq!(f.get_hdu_type(), HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu_type(&mut self) -> HduType {
        let mut hdu_type = 3;
        unsafe {
            ffghdt(self.fptr, &mut hdu_type, &mut self.status);
        }
        self.check();

        match hdu_type {
            0 => HduType::ImageHDU,
            1 => HduType::AsciiTableHDU,
            2 => HduType::BinTableHDU,
            _ => panic!("Unknown hdu type: {}", hdu_type),
        }
    }

    /// Return a `FitsHDU` object for the specified HDU
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// let primary_hdu = f.get_hdu(0);
    /// assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu(&mut self, index: usize) -> FitsHDU {
        self.change_hdu(index as u32);
        let hdu_type = self.get_hdu_type();

        let image_shape = if hdu_type == HduType::ImageHDU {
            let mut naxis = vec![0, 0];
            unsafe {
                ffgisz(self.fptr, 2, naxis.as_mut_ptr(), &mut self.status);
            }
            println!("{:?}", naxis);
            (naxis[0] as usize, naxis[1] as usize)
        } else {
            (0, 0)
        };

        FitsHDU {
            fitsfile: self,
            hdu_type: hdu_type,
            image_shape: image_shape,
        }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        unsafe {
            ffclos(self.fptr, &mut self.status);
        }
    }
}

/// Wrapper around a FITS HDU
///
/// This struct is the main interface around reading and writing the file contents.
pub struct FitsHDU<'a> {
    fitsfile: &'a FitsFile,
    pub hdu_type: HduType,
    image_shape: (usize, usize),
}

impl<'a> FitsHDU<'a> {
    /// Read a header key as a string
    ///
    /// The user is responsible for converting the value type from a string to whatever type the
    /// header key contains.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
    /// let mut primary_hdu = f.get_hdu(0);
    /// // Image is 2-dimensional
    /// let naxis = primary_hdu.get_key("NAXIS").parse::<i32>().unwrap();
    /// assert_eq!(naxis, 2);
    /// # }
    /// ```
    pub fn get_key(&mut self, key: &str) -> String {
        let fptr = &self.fitsfile.fptr;
        let mut value: Vec<c_char> = vec![0; MAX_VALUE_LENGTH];
        let keyname = ffi::CString::new(key).unwrap();
        let mut status = 0;

        unsafe {
            ffgkys(*fptr,
                   keyname.as_ptr(),
                   value.as_mut_ptr(),
                   ptr::null_mut(),
                   &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                return String::from_utf8(value).unwrap();
            }
            _ => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }

    fn read_all_i32(&mut self, buffer: &mut Vec<i32>) {
        let npix = self.image_shape.0 * self.image_shape.1;
        buffer.resize(npix, 0);
        let mut status = 0;

        unsafe {
            ffgpv(self.fitsfile.fptr,
                  31, // TINT
                  1,
                  npix as i64,
                  ptr::null_mut() as *mut c_void,
                  buffer.as_mut_ptr() as *mut c_void,
                  ptr::null_mut(),
                  &mut status);
        }
        match status {
            0 => {}
            status => panic!("Bad status value: {}", status),
        }
        self.fitsfile.check();
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use super::status_to_string;

    #[test]
    fn returning_error_messages() {
        assert_eq!(status_to_string(105).unwrap(),
                   "couldn't create the named file");
    }

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("testdata/full_example.fits") {
            Ok(f) => assert_eq!(f.status, 0),
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(f) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn filename_is_stored() {
        let f = FitsFile::open("testdata/full_example.fits").unwrap();
        assert_eq!(f.filename, "testdata/full_example.fits");
    }

    #[test]
    fn change_hdu() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
        f.change_hdu(1);
        assert_eq!(f.current_hdu_number(), 1u32);
    }

    #[test]
    fn getting_current_hdu_number() {
        let f = FitsFile::open("testdata/full_example.fits").unwrap();
        assert_eq!(f.current_hdu_number(), 0u32);
    }

    #[test]
    fn getting_hdu_object() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();

        // TODO: get rid of these scopes
        //
        // They're there because `get_hdu` mutably borrows the `self` object and
        // the result is still in scope. We need to expire the `FitsHDU` objects
        // and hence the scopes.
        {
            let primary_hdu = f.get_hdu(0);
            assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
        }

        {
            let table_hdu = f.get_hdu(1);
            assert_eq!(table_hdu.hdu_type, HduType::BinTableHDU);
        }
    }

    #[test]
    fn reading_in_image_data() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
        let mut primary_hdu = f.get_hdu(0);
        let mut data = Vec::new();
        primary_hdu.read_all_i32(&mut data);
        assert_eq!(data[0], 108);
        assert_eq!(data[1], 176);
    }

    #[test]
    fn get_image_dimensions() {
        let mut f = FitsFile::open("testdata/full_example.fits").unwrap();
        let primary_hdu = f.get_hdu(0);
        assert_eq!(primary_hdu.image_shape, (100, 100));
    }
}
<|endoftext|>


<commit_before>
extern crate crypto;
#[macro_use] extern crate hyper;
extern crate rustc_serialize;
extern crate time;

pub mod hook;
pub mod rep;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use hook::Hook;

use hyper::server::{Handler, Server, Request, Response};
use rep::{Payload, Ping};
use rustc_serialize::json::{self, DecodeResult};
use std::collections::HashMap;
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};

/// signature for request
/// see [this document](https://developer.github.com/webhooks/securing/) for more information
header! {(XHubSignature, "X-Hub-Signature") => [String]}

/// name of Github event
/// see [this document](https://developer.github.com/webhooks/#events) for available types
header! {(XGithubEvent, "X-Github-Event") => [String]}

/// unique id for each delivery
header! {(XGithubDelivery, "X-Github-Deliver") => [String]}

/// Raw, unparsed representation of an inbound github event
#[derive(Clone, Debug, Default)]
pub struct Event {
  pub name: String,
  pub payload: String
}

/// A hub is a handler for github event requests
struct Hub {
  secret: Option<String>,
  deliveries: Mutex<Sender<Event>>,
  hooks: Vec<Hook>
}

impl Hub {
  pub fn authenticate(secret: &String, payload: &String, signature: &[u8]) -> bool {
    let sbytes = secret.as_bytes();
    let pbytes = payload.as_bytes();
    let mut mac = Hmac::new(Sha1::new(), &sbytes);
    mac.input(&pbytes);
    mac.result().code().to_vec() == signature
  }
}

impl Handler for Hub {
  fn handle(&self, mut req: Request, res: Response) {
    let mut payload = String::new();
    if let Ok(_) = req.read_to_string(&mut payload) {
      if let Some(&XGithubEvent(ref event)) = req.headers.get::<XGithubEvent>() {
        println!("recv '{}' event", event);
        let deliver = || {
          let _ = self.deliveries.lock().unwrap().send(Event {
            name: event.clone(),
            payload: payload.clone()
          });
        };
        if let Some(ref secret) = self.secret {
           match req.headers.get::<XHubSignature>() {
              Some(sig) => {
                 if Hub::authenticate(&secret, &payload, &sig.as_bytes()) {
                   deliver()
                 } else {
                   println!("recv invalid signature for payload");
                 }
              },
                     _  => println!("recv unsigned request recieved")
           }
        } else {
          deliver()
        }
      }
    }
    let _ = res.send(b"ok");
    ()
  }
}

/// Filters filter inbound events, invoking interested hooks
struct Filter { hooks: Vec<Hook> }

impl Filter {

  /// filters hooks based on event name
  /// `*` will match any event
  pub fn filter(&self, ev: &Event, payload: &Payload) -> Vec<&Hook> {
    (*self.hooks).into_iter()
      .filter(|h| h.targets(&ev.name, payload))
      .collect::<Vec<&Hook>>()
  }

  /// recv's github events from rx and sends them
  /// to interested hooks.
  /// a thread will be spawned once for each hook
  /// before awaiting the reciept of events
  pub fn recv(&self, rx: Receiver<Event>) {
    let mut lookup     = HashMap::new();
    let mut deliveries = HashMap::new();
    for hook in (&self.hooks).iter() {
      lookup.insert((*hook).clone().name(), (*hook).clone());
    }
    for (name, hook) in lookup.into_iter() {
      let (tx, rx) = channel();
      deliveries.insert(name.clone(), tx);
      thread::spawn(move || {
        hook.recv(rx);
      });
    }
    while let Ok(ev) = rx.recv() {
      fn parse_payload(raw: &String) -> DecodeResult<Payload> {
        json::decode::<Payload>(&raw).or(
          json::decode::<Ping>(&raw).map(|p|p.hook)
        )
      }
      match parse_payload(&ev.payload) {
        Ok(payload) => {
          println!("rec {} event", ev.name);
          let hooks = self.filter(&ev, &payload);
          for h in hooks {
            let name = h.clone().name();
            if let Err(e) = deliveries.get(&name).unwrap().send(ev.clone()) {
              println!("{} delivery to {} failed: {}", ev.name, name, e.to_string())
            }
          }
        }, _ => println!("rec unparsable payload {:?}", ev.payload)
      }
    }
  }
}

/// A Service serves inbound requests for github events
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Service {
  pub secret: Option<String>,
  pub port: Option<u16>,
  pub hooks: Vec<Hook>
}

impl Service {

  /// return the configured port or 4567
  pub fn port(&self) -> u16 {
    self.port.unwrap_or(4567)
  }

  /// sets the current list of hooks in memory
  pub fn hooks(&mut self, hooks: Vec<Hook>) {
    self.hooks = hooks;
  }

  /// starts listening on the configured port
  pub fn run(self) {
    let (tx, rx) = channel();
    let hooks = self.hooks.clone();
    thread::spawn(move || {
      let filter = Filter { hooks: hooks };
      filter.recv(rx)
    });
    let addr = format!("0.0.0.0:{}", self.port());
    let srvc = Server::http(&addr[..]).unwrap()
      .handle(Hub {
         secret: self.secret,
         deliveries: Mutex::new(tx),
         hooks: self.hooks
      });
    println!("listening on {}", addr);
    srvc.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use rustc_serialize::json;
  use super::{Event, Filter, Service};
  use super::hook::Hook;
  use super::rep::Payload;

  #[test]
  fn test_filter() {
    let hooks = vec![
      Hook {
        events: vec![
          "a".to_owned(),
          "b".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec![
          "a".to_owned(),
          "c".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec!["*".to_owned()],
        ..Default::default()
      }
    ];
    let filter = Filter { hooks: hooks };

    assert_eq!(3, filter.filter(&Event {
      name: "a".to_owned(),
      ..Default::default()
    }, &Payload {
       ..Default::default()
    }).len());

    assert_eq!(2, filter.filter(&Event {
      name: "c".to_owned(),
      ..Default::default()
    }, &Payload {
      ..Default::default()
    }).len())
  }

  #[test]
  fn test_service_config() {
    match json::decode::<Service>(&r#"{
     "hooks": [{
       "cmd": "ls",
       "events": ["test"]
     }]
    }"#) {
      Ok(svc) => {
         assert_eq!(4567, svc.port());
         assert_eq!(1, svc.hooks.len());
      },
      Err(e) => panic!("failed to decode service {}", e)
    }
  }
}
<commit_msg>fix authentication<commit_after>
extern crate crypto;
#[macro_use] extern crate hyper;
extern crate rustc_serialize;
extern crate time;
use rustc_serialize::hex::ToHex;
pub mod hook;
pub mod rep;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use hook::Hook;

use hyper::server::{Handler, Server, Request, Response};
use rep::{Payload, Ping};
use rustc_serialize::json::{self, DecodeResult};
use std::collections::HashMap;
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};

/// signature for request
/// see [this document](https://developer.github.com/webhooks/securing/) for more information
header! {(XHubSignature, "X-Hub-Signature") => [String]}

/// name of Github event
/// see [this document](https://developer.github.com/webhooks/#events) for available types
header! {(XGithubEvent, "X-Github-Event") => [String]}

/// unique id for each delivery
header! {(XGithubDelivery, "X-Github-Deliver") => [String]}

/// Raw, unparsed representation of an inbound github event
#[derive(Clone, Debug, Default)]
pub struct Event {
  pub name: String,
  pub payload: String
}

/// A hub is a handler for github event requests
struct Hub {
  secret: Option<String>,
  deliveries: Mutex<Sender<Event>>,
  hooks: Vec<Hook>
}

impl Hub {
  pub fn authenticate(secret: &String, payload: &String, signature: &String) -> bool {
    let sbytes = secret.as_bytes();
    let pbytes = payload.as_bytes();
    let mut mac = Hmac::new(Sha1::new(), &sbytes);
    mac.input(&pbytes);
    mac.result().code().to_hex() == str::replace(signature, "sha1=", "")
  }
}

impl Handler for Hub {
  fn handle(&self, mut req: Request, res: Response) {
    let mut payload = String::new();
    if let Ok(_) = req.read_to_string(&mut payload) {
      if let Some(&XGithubEvent(ref event)) = req.headers.get::<XGithubEvent>() {
        println!("recv '{}' event", event);
        let deliver = || {
          let _ = self.deliveries.lock().unwrap().send(Event {
            name: event.clone(),
            payload: payload.clone()
          });
        };
        if let Some(ref secret) = self.secret {
           match req.headers.get::<XHubSignature>() {
             Some(sig) => {
                 println!("rec sig {}", sig);
                 if Hub::authenticate(&secret, &payload, &sig) {
                   deliver()
                 } else {
                   println!("recv invalid signature for payload");
                 }
              },
                     _  => println!("recv unsigned request recieved")
           }
        } else {
          deliver()
        }
      }
    }
    let _ = res.send(b"ok");
    ()
  }
}

/// Filters filter inbound events, invoking interested hooks
struct Filter { hooks: Vec<Hook> }

impl Filter {

  /// filters hooks based on event name
  /// `*` will match any event
  pub fn filter(&self, ev: &Event, payload: &Payload) -> Vec<&Hook> {
    (*self.hooks).into_iter()
      .filter(|h| h.targets(&ev.name, payload))
      .collect::<Vec<&Hook>>()
  }

  /// recv's github events from rx and sends them
  /// to interested hooks.
  /// a thread will be spawned once for each hook
  /// before awaiting the reciept of events
  pub fn recv(&self, rx: Receiver<Event>) {
    let mut lookup     = HashMap::new();
    let mut deliveries = HashMap::new();
    for hook in (&self.hooks).iter() {
      lookup.insert((*hook).clone().name(), (*hook).clone());
    }
    for (name, hook) in lookup.into_iter() {
      let (tx, rx) = channel();
      deliveries.insert(name.clone(), tx);
      thread::spawn(move || {
        hook.recv(rx);
      });
    }
    while let Ok(ev) = rx.recv() {
      fn parse_payload(raw: &String) -> DecodeResult<Payload> {
        json::decode::<Payload>(&raw).or(
          json::decode::<Ping>(&raw).map(|p|p.hook)
        )
      }
      match parse_payload(&ev.payload) {
        Ok(payload) => {
          println!("rec {} event", ev.name);
          let hooks = self.filter(&ev, &payload);
          for h in hooks {
            let name = h.clone().name();
            if let Err(e) = deliveries.get(&name).unwrap().send(ev.clone()) {
              println!("{} delivery to {} failed: {}", ev.name, name, e.to_string())
            }
          }
        }, _ => println!("rec unparsable payload {:?}", ev.payload)
      }
    }
  }
}

/// A Service serves inbound requests for github events
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Service {
  pub secret: Option<String>,
  pub port: Option<u16>,
  pub hooks: Vec<Hook>
}

impl Service {

  /// return the configured port or 4567
  pub fn port(&self) -> u16 {
    self.port.unwrap_or(4567)
  }

  /// sets the current list of hooks in memory
  pub fn hooks(&mut self, hooks: Vec<Hook>) {
    self.hooks = hooks;
  }

  /// starts listening on the configured port
  pub fn run(self) {
    let (tx, rx) = channel();
    let hooks = self.hooks.clone();
    thread::spawn(move || {
      let filter = Filter { hooks: hooks };
      filter.recv(rx)
    });
    let addr = format!("0.0.0.0:{}", self.port());
    let srvc = Server::http(&addr[..]).unwrap()
      .handle(Hub {
         secret: self.secret,
         deliveries: Mutex::new(tx),
         hooks: self.hooks
      });
    println!("listening on {}", addr);
    srvc.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use rustc_serialize::json;
  use super::{Event, Filter, Service};
  use super::hook::Hook;
  use super::rep::Payload;

  #[test]
  fn test_filter() {
    let hooks = vec![
      Hook {
        events: vec![
          "a".to_owned(),
          "b".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec![
          "a".to_owned(),
          "c".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec!["*".to_owned()],
        ..Default::default()
      }
    ];
    let filter = Filter { hooks: hooks };

    assert_eq!(3, filter.filter(&Event {
      name: "a".to_owned(),
      ..Default::default()
    }, &Payload {
       ..Default::default()
    }).len());

    assert_eq!(2, filter.filter(&Event {
      name: "c".to_owned(),
      ..Default::default()
    }, &Payload {
      ..Default::default()
    }).len())
  }

  #[test]
  fn test_service_config() {
    match json::decode::<Service>(&r#"{
     "hooks": [{
       "cmd": "ls",
       "events": ["test"]
     }]
    }"#) {
      Ok(svc) => {
         assert_eq!(4567, svc.port());
         assert_eq!(1, svc.hooks.len());
      },
      Err(e) => panic!("failed to decode service {}", e)
    }
  }
}
<|endoftext|>


<commit_before>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some introductory text here.
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! #![feature(core)]
//!
//! use std::fs;
//! use std::f32::consts::PI;
//! use std::iter::IntoIterator;
//! use std::num;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! // TODO: ensure that the type can be inferred.
//! let writer_res = hound::WavWriter::<fs::File>::create("sine.wav", spec);
//! let mut writer = writer_res.ok().unwrap();
//! for t in (0 .. 44100).map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude: i16 = num::Int::max_value();
//!     writer.write_sample((sample * amplitude as f32) as i16).ok().unwrap();
//! }
//! writer.finalize().ok().unwrap();
//! ```

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

/// Extends the functionality of `io::Write` with additional methods.
///
/// The methods may be used on any type that implements `io::Write`.
trait WriteExt: io::Write {
    /// Writes an unsigned 16-bit integer in little endian format.
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;

    /// Writes an unsigned 32-bit integer in little endian format.
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data section.
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self as u16)
        // TODO: take bits into account
    }
}

/// Generates a bitmask with `channels` ones in the least significant bits.
fn channel_mask(channels: u16) -> u32 {
    (0 .. channels).map(|c| 1 << c).fold(0, |a, c| a | c)
}

#[test]
fn verify_channel_mask()
{
    assert_eq!(channel_mask(0), 0);
    assert_eq!(channel_mask(1), 1);
    assert_eq!(channel_mask(2), 3);
    assert_eq!(channel_mask(3), 7);
    assert_eq!(channel_mask(4), 15);
}

/// Specifies properties of the audio data.
#[derive(Clone, Copy)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
pub struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// The (container) bytes per sample. This is the bit rate / 8 rounded up.
    bytes_per_sample: u32,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    ///
    /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
    /// buffering internally to avoid too many `write` calls to the underlying
    /// writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        WavWriter {
            spec: spec,
            bytes_per_sample: (spec.bits_per_sample as f32 / 8.0).ceil() as u32,
            wrote_header: false,
            writer: io::BufWriter::new(writer),
            data_bytes_written: 0,
            finalized: false
        }
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        // Useful links:
        // https://msdn.microsoft.com/en-us/library/ms713462.aspx
        // https://msdn.microsoft.com/en-us/library/ms713497.aspx

        let mut header = [0u8; 68];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.write_le_u32(0));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt ".as_bytes()));
            try!(buffer.write_le_u32(40)); // Size of the WAVE header chunk.

            // The following is based on the WAVEFORMATEXTENSIBLE struct as
            // documented on MSDN.

            // The field wFormatTag, value 1 means WAVE_FORMAT_PCM, but we use
            // the slightly more sophisticated WAVE_FORMAT_EXTENSIBLE.
            try!(buffer.write_le_u16(0xfffe));
            // The field nChannels.
            try!(buffer.write_le_u16(spec.channels));
            // The field nSamplesPerSec.
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * self.bytes_per_sample
                              * spec.channels as u32;
            // The field nAvgBytesPerSec;
            try!(buffer.write_le_u32(bytes_per_sec));
            // The field nBlockAlign. Block align * sample rate = bytes per sec.
            try!(buffer.write_le_u16((bytes_per_sec / spec.sample_rate) as u16));
            // The field wBitsPerSample. This is actually the size of the
            // container, so this is a multiple of 8.
            try!(buffer.write_le_u16(self.bytes_per_sample as u16 * 8));
            // The field cbSize, the number of remaining bytes in the struct.
            try!(buffer.write_le_u16(22));
            // The field wValidBitsPerSample, the real number of bits per sample.
            try!(buffer.write_le_u16(self.spec.bits_per_sample as u16));
            // The field dwChannelMask.
            // TODO: add the option to specify the channel mask. For now, use
            // the default assignment.
            try!(buffer.write_le_u32(channel_mask(self.spec.channels)));
            // The field SubFormat. We use KSDATAFORMAT_SUBTYPE_PCM. The
            // following GUIDS are defined:
            // - PCM:        00000001-0000-0010-8000-00aa00389b71
            // - IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71
            // The byte order of a GUID is native for the first three sections,
            // which is assumed to be little endian, and big endian for the
            // last 8-byte section (which does contain a hyphen, for reasons
            // unknown to me).
            try!(buffer.write_all(&[0x01, 0x00, 0x00, 0x00,
                                    0x00, 0x00, 0x10, 0x00,
                                    0x80, 0x00, 0x00, 0xaa,
                                    0x00, 0x38, 0x9b, 0x71]));

            // So far the "fmt " section, now comes the "data" section. We will
            // only write the header here, actual data are the samples. The
            // number of bytes that this will take is not known at this point.
            // The 0 will be overwritten later.
            try!(buffer.write_all("data".as_bytes()));
            try!(buffer.write_le_u32(0));
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    /// Writes a single sample for one channel.
    ///
    /// WAVE interleaves channel data, so the channel that this writes the
    /// sample to depends on previous writes.
    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
            self.wrote_header = true;
        }

        // TODO: do we need bits per sample? Is the padding at the obvious side?
        try!(sample.write(&mut self.writer, self.bytes_per_sample));
        self.data_bytes_written += self.bytes_per_sample;
        Ok(())
    }

    /// Performs finalization. After calling this, the writer should be destructed.
    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();

        // The header minus magic and 32-bit filesize is 60 bytes long.
        let file_size = self.data_bytes_written + 60;
        try!(writer.seek(io::SeekFrom::Start(4)));
        try!(writer.write_le_u32(file_size));
        try!(writer.seek(io::SeekFrom::Start(64)));
        try!(writer.write_le_u32(self.data_bytes_written));

        Ok(())
    }

    /// Writes the parts of the WAVE format that require knowing all samples.
    ///
    /// This method must be called after all samples have been written. If it
    /// is not called, the destructor will finalize the file, but any IO errors
    /// that occur in the process cannot be observed in that manner.
    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}

// TODO: Add benchmark for write speed.
<commit_msg>remove unused features and lint exceptions<commit_after>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some introductory text here.
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! #![feature(core)]
//!
//! use std::fs;
//! use std::f32::consts::PI;
//! use std::iter::IntoIterator;
//! use std::num;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! // TODO: ensure that the type can be inferred.
//! let writer_res = hound::WavWriter::<fs::File>::create("sine.wav", spec);
//! let mut writer = writer_res.ok().unwrap();
//! for t in (0 .. 44100).map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude: i16 = num::Int::max_value();
//!     writer.write_sample((sample * amplitude as f32) as i16).ok().unwrap();
//! }
//! writer.finalize().ok().unwrap();
//! ```

#![warn(missing_docs)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

/// Extends the functionality of `io::Write` with additional methods.
///
/// The methods may be used on any type that implements `io::Write`.
trait WriteExt: io::Write {
    /// Writes an unsigned 16-bit integer in little endian format.
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;

    /// Writes an unsigned 32-bit integer in little endian format.
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data section.
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self as u16)
        // TODO: take bits into account
    }
}

/// Generates a bitmask with `channels` ones in the least significant bits.
fn channel_mask(channels: u16) -> u32 {
    (0 .. channels).map(|c| 1 << c).fold(0, |a, c| a | c)
}

#[test]
fn verify_channel_mask()
{
    assert_eq!(channel_mask(0), 0);
    assert_eq!(channel_mask(1), 1);
    assert_eq!(channel_mask(2), 3);
    assert_eq!(channel_mask(3), 7);
    assert_eq!(channel_mask(4), 15);
}

/// Specifies properties of the audio data.
#[derive(Clone, Copy)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
pub struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// The (container) bytes per sample. This is the bit rate / 8 rounded up.
    bytes_per_sample: u32,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    ///
    /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
    /// buffering internally to avoid too many `write` calls to the underlying
    /// writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        WavWriter {
            spec: spec,
            bytes_per_sample: (spec.bits_per_sample as f32 / 8.0).ceil() as u32,
            wrote_header: false,
            writer: io::BufWriter::new(writer),
            data_bytes_written: 0,
            finalized: false
        }
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        // Useful links:
        // https://msdn.microsoft.com/en-us/library/ms713462.aspx
        // https://msdn.microsoft.com/en-us/library/ms713497.aspx

        let mut header = [0u8; 68];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.write_le_u32(0));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt ".as_bytes()));
            try!(buffer.write_le_u32(40)); // Size of the WAVE header chunk.

            // The following is based on the WAVEFORMATEXTENSIBLE struct as
            // documented on MSDN.

            // The field wFormatTag, value 1 means WAVE_FORMAT_PCM, but we use
            // the slightly more sophisticated WAVE_FORMAT_EXTENSIBLE.
            try!(buffer.write_le_u16(0xfffe));
            // The field nChannels.
            try!(buffer.write_le_u16(spec.channels));
            // The field nSamplesPerSec.
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * self.bytes_per_sample
                              * spec.channels as u32;
            // The field nAvgBytesPerSec;
            try!(buffer.write_le_u32(bytes_per_sec));
            // The field nBlockAlign. Block align * sample rate = bytes per sec.
            try!(buffer.write_le_u16((bytes_per_sec / spec.sample_rate) as u16));
            // The field wBitsPerSample. This is actually the size of the
            // container, so this is a multiple of 8.
            try!(buffer.write_le_u16(self.bytes_per_sample as u16 * 8));
            // The field cbSize, the number of remaining bytes in the struct.
            try!(buffer.write_le_u16(22));
            // The field wValidBitsPerSample, the real number of bits per sample.
            try!(buffer.write_le_u16(self.spec.bits_per_sample as u16));
            // The field dwChannelMask.
            // TODO: add the option to specify the channel mask. For now, use
            // the default assignment.
            try!(buffer.write_le_u32(channel_mask(self.spec.channels)));
            // The field SubFormat. We use KSDATAFORMAT_SUBTYPE_PCM. The
            // following GUIDS are defined:
            // - PCM:        00000001-0000-0010-8000-00aa00389b71
            // - IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71
            // The byte order of a GUID is native for the first three sections,
            // which is assumed to be little endian, and big endian for the
            // last 8-byte section (which does contain a hyphen, for reasons
            // unknown to me).
            try!(buffer.write_all(&[0x01, 0x00, 0x00, 0x00,
                                    0x00, 0x00, 0x10, 0x00,
                                    0x80, 0x00, 0x00, 0xaa,
                                    0x00, 0x38, 0x9b, 0x71]));

            // So far the "fmt " section, now comes the "data" section. We will
            // only write the header here, actual data are the samples. The
            // number of bytes that this will take is not known at this point.
            // The 0 will be overwritten later.
            try!(buffer.write_all("data".as_bytes()));
            try!(buffer.write_le_u32(0));
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    /// Writes a single sample for one channel.
    ///
    /// WAVE interleaves channel data, so the channel that this writes the
    /// sample to depends on previous writes.
    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
            self.wrote_header = true;
        }

        // TODO: do we need bits per sample? Is the padding at the obvious side?
        try!(sample.write(&mut self.writer, self.bytes_per_sample));
        self.data_bytes_written += self.bytes_per_sample;
        Ok(())
    }

    /// Performs finalization. After calling this, the writer should be destructed.
    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();

        // The header minus magic and 32-bit filesize is 60 bytes long.
        let file_size = self.data_bytes_written + 60;
        try!(writer.seek(io::SeekFrom::Start(4)));
        try!(writer.write_le_u32(file_size));
        try!(writer.seek(io::SeekFrom::Start(64)));
        try!(writer.write_le_u32(self.data_bytes_written));

        Ok(())
    }

    /// Writes the parts of the WAVE format that require knowing all samples.
    ///
    /// This method must be called after all samples have been written. If it
    /// is not called, the destructor will finalize the file, but any IO errors
    /// that occur in the process cannot be observed in that manner.
    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}

// TODO: Add benchmark for write speed.
<|endoftext|>