<commit_before>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website https://serde.rs/ for additional documentation and
//! usage examples.
//!
//! ### Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's code
//! generation to automatically derive implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform roughly the same speed as a handwritten serializer
//! for the specific selection of data structure and data format.
//!
//! ### Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON](https://github.com/serde-rs/json), the ubiquitous JavaScript Object
//!   Notation used by many HTTP APIs.
//! - [Bincode](https://github.com/TyOverby/bincode), a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR](https://github.com/pyfisch/cbor), a Concise Binary Object
//!   Representation designed for small message size without the need for
//!   version negotiation.
//! - [YAML](https://github.com/dtolnay/serde-yaml), a popular human-friendly
//!   configuration language that ain't markup language.
//! - [MessagePack](https://github.com/3Hren/msgpack-rust), an efficient binary
//!   format that resembles a compact JSON.
//! - [TOML](https://github.com/alexcrichton/toml-rs), a minimal configuration
//!   format used by [Cargo](http://doc.crates.io/manifest.html).
//! - [Pickle](https://github.com/birkenfeld/serde-pickle), a format common in
//!   the Python world.
//! - [Hjson](https://github.com/laktak/hjson-rust), a variant of JSON designed
//!   to be readable and writable by humans.
//! - [BSON](https://github.com/zonyitoo/bson-rs), the data storage and network
//!   transfer format used by MongoDB.
//! - [URL](https://github.com/nox/serde_urlencoded), the x-www-form-urlencoded
//!   format.
//! - [XML](https://github.com/serde-rs/xml), the flexible machine-friendly W3C
//!   standard. *(deserialization only)*
//! - [Envy](https://github.com/softprops/envy), a way to deserialize
//!   environment variables into Rust structs. *(deserialization only)*
//! - [Redis](https://github.com/OneSignal/serde-redis), deserialize values from
//!   Redis when using [redis-rs](https://crates.io/crates/redis).
//!   *(deserialization only)*

#![doc(html_root_url = "https://docs.rs/serde/0.9.13")]

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unstable", feature(nonzero, specialization, zero_one))]
#![cfg_attr(all(feature = "std", feature = "unstable"), feature(into_boxed_c_str))]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "collections", feature(collections))]
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist, type_complexity, doc_markdown))]
#![deny(missing_docs, unused_imports)]

#[cfg(feature = "collections")]
extern crate collections;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(all(feature = "unstable", feature = "std"))]
extern crate core;

/// A facade around all the types we need from the `std`, `core`, `alloc`, and
/// `collections` crates. This avoids elaborate import wrangling having to
/// happen in every module.
mod lib {
    mod core {
        #[cfg(feature = "std")]
        pub use std::*;
        #[cfg(not(feature = "std"))]
        pub use core::*;
    }

    pub use self::core::{cmp, iter, mem, ops, str};
    pub use self::core::{i8, i16, i32, i64, isize};
    pub use self::core::{u8, u16, u32, u64, usize};
    pub use self::core::{f32, f64};

    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::borrow::{Cow, ToOwned};

    #[cfg(feature = "std")]
    pub use std::string::String;
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::string::{String, ToString};

    #[cfg(feature = "std")]
    pub use std::vec::Vec;
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::vec::Vec;

    #[cfg(feature = "std")]
    pub use std::boxed::Box;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::Rc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::Rc;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::Arc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::arc::Arc;

    #[cfg(feature = "std")]
    pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net, path};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CString, CStr, OsString, OsStr};
    #[cfg(feature = "std")]
    pub use std::hash::{Hash, BuildHasher};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::time::Duration;

    #[cfg(feature = "unstable")]
    pub use core::nonzero::{NonZero, Zeroable};
    #[cfg(feature = "unstable")]
    #[allow(deprecated)] // required for impl Deserialize for NonZero<T>
    pub use core::num::Zero;
}

#[doc(inline)]
pub use ser::{Serialize, Serializer};
#[doc(inline)]
pub use de::{Deserialize, Deserializer};

#[macro_use]
mod macros;

pub mod de;
pub mod ser;

// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;

// Helpers used by generated code and doc tests. Not public API.
#[doc(hidden)]
pub mod private;

// Re-export #[derive(Serialize, Deserialize)].
//
// This is a workaround for https://github.com/rust-lang/cargo/issues/1286.
// Without this re-export, crates that put Serde derives behind a cfg_attr would
// need to use some silly feature name that depends on both serde and
// serde_derive.
//
//     [features]
//     serde-impls = ["serde", "serde_derive"]
//
//     [dependencies]
//     serde = { version = "1.0", optional = true }
//     serde_derive = { version = "1.0", optional = true }
//
//     # Used like this:
//     # #[cfg(feature = "serde-impls")]
//     # #[macro_use]
//     # extern crate serde_derive;
//     #
//     # #[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The re-exported derives allow crates to use "serde" as the name of their
// Serde feature which is more intuitive.
//
//     [dependencies]
//     serde = { version = "1.0", optional = true, features = ["derive"] }
//
//     # Used like this:
//     # #[cfg(feature = "serde")]
//     # #[macro_use]
//     # extern crate serde;
//     #
//     # #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<commit_msg>Touch up the top-level documentation<commit_after>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website [https://serde.rs/] for additional documentation and
//! usage examples.
//!
//! [https://serde.rs/]: https://serde.rs/
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a popular human-friendly configuration language that ain't markup
//!   language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [URL], the x-www-form-urlencoded format.
//! - [XML], the flexible machine-friendly W3C standard.
//!   *(deserialization only)*
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Redis], deserialize values from Redis when using [redis-rs].
//!   *(deserialization only)*
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/TyOverby/bincode
//! [CBOR]: https://github.com/pyfisch/cbor
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [Hjson]: https://github.com/laktak/hjson-rust
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [URL]: https://github.com/nox/serde_urlencoded
//! [XML]:https://github.com/RReverser/serde-xml-rs
//! [Envy]: https://github.com/softprops/envy
//! [Redis]: https://github.com/OneSignal/serde-redis
//! [Cargo]: http://doc.crates.io/manifest.html
//! [redis-rs]: https://crates.io/crates/redis

#![doc(html_root_url = "https://docs.rs/serde/0.9.13")]

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unstable", feature(nonzero, specialization, zero_one))]
#![cfg_attr(all(feature = "std", feature = "unstable"), feature(into_boxed_c_str))]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "collections", feature(collections))]
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist, type_complexity, doc_markdown))]
#![deny(missing_docs, unused_imports)]

#[cfg(feature = "collections")]
extern crate collections;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(all(feature = "unstable", feature = "std"))]
extern crate core;

/// A facade around all the types we need from the `std`, `core`, `alloc`, and
/// `collections` crates. This avoids elaborate import wrangling having to
/// happen in every module.
mod lib {
    mod core {
        #[cfg(feature = "std")]
        pub use std::*;
        #[cfg(not(feature = "std"))]
        pub use core::*;
    }

    pub use self::core::{cmp, iter, mem, ops, str};
    pub use self::core::{i8, i16, i32, i64, isize};
    pub use self::core::{u8, u16, u32, u64, usize};
    pub use self::core::{f32, f64};

    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::borrow::{Cow, ToOwned};

    #[cfg(feature = "std")]
    pub use std::string::String;
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::string::{String, ToString};

    #[cfg(feature = "std")]
    pub use std::vec::Vec;
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::vec::Vec;

    #[cfg(feature = "std")]
    pub use std::boxed::Box;
    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::Rc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::Rc;

    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::Arc;
    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::arc::Arc;

    #[cfg(feature = "std")]
    pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
    #[cfg(all(feature = "collections", not(feature = "std")))]
    pub use collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net, path};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CString, CStr, OsString, OsStr};
    #[cfg(feature = "std")]
    pub use std::hash::{Hash, BuildHasher};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::time::Duration;

    #[cfg(feature = "unstable")]
    pub use core::nonzero::{NonZero, Zeroable};
    #[cfg(feature = "unstable")]
    #[allow(deprecated)] // required for impl Deserialize for NonZero<T>
    pub use core::num::Zero;
}

#[doc(inline)]
pub use ser::{Serialize, Serializer};
#[doc(inline)]
pub use de::{Deserialize, Deserializer};

#[macro_use]
mod macros;

pub mod de;
pub mod ser;

// Generated code uses these to support no_std. Not public API.
#[doc(hidden)]
pub mod export;

// Helpers used by generated code and doc tests. Not public API.
#[doc(hidden)]
pub mod private;

// Re-export #[derive(Serialize, Deserialize)].
//
// This is a workaround for https://github.com/rust-lang/cargo/issues/1286.
// Without this re-export, crates that put Serde derives behind a cfg_attr would
// need to use some silly feature name that depends on both serde and
// serde_derive.
//
//     [features]
//     serde-impls = ["serde", "serde_derive"]
//
//     [dependencies]
//     serde = { version = "1.0", optional = true }
//     serde_derive = { version = "1.0", optional = true }
//
//     # Used like this:
//     # #[cfg(feature = "serde-impls")]
//     # #[macro_use]
//     # extern crate serde_derive;
//     #
//     # #[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The re-exported derives allow crates to use "serde" as the name of their
// Serde feature which is more intuitive.
//
//     [dependencies]
//     serde = { version = "1.0", optional = true, features = ["derive"] }
//
//     # Used like this:
//     # #[cfg(feature = "serde")]
//     # #[macro_use]
//     # extern crate serde;
//     #
//     # #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
//     # struct S { /* ... */ }
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<|endoftext|>


<commit_before>
pub struct StatusFlags {
    pub carry: bool,
    pub zero: bool,
    pub interrupt_disabled: bool,
    pub decimal: bool,
    pub breakpoint: bool,
    pub unused: bool,
    pub overflow: bool,
    pub sign: bool,
}

impl Default for StatusFlags {
    fn default() -> StatusFlags {
        StatusFlags {
            carry: false,
            zero: false,
            interrupt_disabled: true,
            decimal: false,
            breakpoint: false,
            unused: false,
            overflow: false,
            sign: false,
        }
    }
}<commit_msg>Add to_u8 and from<u8> for StatusFlags<commit_after>
pub struct StatusFlags {
    pub carry: bool,
    pub zero: bool,
    pub interrupt_disabled: bool,
    pub decimal: bool,
    pub breakpoint: bool,
    pub unused: bool,
    pub overflow: bool,
    pub sign: bool,
}

impl StatusFlags {
    pub fn to_u8(&self) -> u8 {
        let carry = if self.carry { 0x01 } else { 0 };
        let zero = if self.zero { 0x02 } else { 0 };
        let interrupt_disabled = if self.interrupt_disabled { 0x04 } else { 0 };
        let decimal = if self.decimal { 0x08 } else { 0 };
        let breakpoint = if self.breakpoint { 0x10 } else { 0 };
        let overflow = if self.overflow { 0x40 } else { 0 };
        let sign = if self.sign { 0x80 } else { 0 };

        carry | zero | interrupt_disabled | decimal | breakpoint | overflow | sign
    }
}

impl From<u8> for StatusFlags {
    fn from(byte: u8) -> StatusFlags {
        StatusFlags {
            carry: byte & 0x01 == 0x01,
            zero: byte & 0x02 == 0x02,
            interrupt_disabled: byte & 0x04 == 0x04,
            decimal: byte & 0x08 == 0x08,
            breakpoint: byte & 0x10 == 0x10,
            unused: false,
            overflow: byte & 0x40 == 0x40,
            sign: byte & 0x80 == 0x80,
        }
    }
}

impl Default for StatusFlags {
    fn default() -> StatusFlags {
        StatusFlags {
            carry: false,
            zero: false,
            interrupt_disabled: true,
            decimal: false,
            breakpoint: false,
            unused: false,
            overflow: false,
            sign: false,
        }
    }
}

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

    #[test]
    fn default_is_four() {
        let f = StatusFlags::default();

        assert_eq!(0x04, f.to_u8());
    }

    #[test]
    fn can_convert_to_u8() {
        let mut f = StatusFlags::default();

        f.carry = true;

        assert_eq!(0x05, f.to_u8());
    }

    #[test]
    fn can_convert_to_and_from() {
        let f = StatusFlags {
            carry: true,
            decimal: true,
            sign: true,
            overflow: true,
            interrupt_disabled: false,
            ..Default::default()
        };

        let byte = f.to_u8();
        let result: StatusFlags = byte.into();

        assert_eq!(true, result.carry);
        assert_eq!(true, result.decimal);
        assert_eq!(true, result.sign);
        assert_eq!(true, result.overflow);

        assert_eq!(false, result.interrupt_disabled);
        assert_eq!(false, result.zero);
        assert_eq!(false, result.breakpoint);
        assert_eq!(false, result.unused);
    }
}<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::process::Child;

/// This structure is needed to manage worker pools for groups.
/// It's a newtype pattern around a nested BTreeMap, which implements some convenience functions.
///
/// The datastructure contains these types of data:
/// BTreeMap<group, BTreeMap<group_worker_id, (task_id, Subprocess handle)>
pub struct Children(pub BTreeMap<String, BTreeMap<usize, (usize, Child)>>);

impl Children {
    /// Returns whether there are any active tasks across all groups.
    pub fn has_active_tasks(&self) -> bool {
        self.0.iter().any(|(_, pool)| !pool.is_empty())
    }

    /// A convenience function to check whether there's child with a given task_id.
    /// We have to do a nested linear search, as these datastructure aren't indexed via task_ids.
    pub fn has_child(&self, task_id: usize) -> bool {
        for (_, pool) in self.0.iter() {
            for (_, (child_task_id, _)) in pool.iter() {
                if child_task_id == &task_id {
                    return true;
                }
            }
        }

        false
    }

    /// A convenience function to get a child by its respective task_id.
    /// We have to do a nested linear search, as these datastructure aren't indexed via task_ids.
    pub fn get_child(&self, task_id: usize) -> Option<&Child> {
        for (_, pool) in self.0.iter() {
            for (_, (child_task_id, child)) in pool.iter() {
                if child_task_id == &task_id {
                    return Some(child);
                }
            }
        }

        None
    }

    /// A convenience function to get a child by its respective task_id.
    /// We have to do a nested linear search, as these datastructure aren't indexed via task_ids.
    pub fn get_child_mut(&mut self, task_id: usize) -> Option<&mut Child> {
        for (_, pool) in self.0.iter_mut() {
            for (_, (child_task_id, child)) in pool.iter_mut() {
                if child_task_id == &task_id {
                    return Some(child);
                }
            }
        }

        None
    }

    /// A convenience function to get a list with all task_ids of all children.
    pub fn all_task_ids(&self) -> Vec<usize> {
        let mut task_ids = Vec::new();
        for (_, pool) in self.0.iter() {
            for (_, (task_id, _)) in pool.iter() {
                task_ids.push(*task_id)
            }
        }

        task_ids
    }

    /// Returns the next free worker slot for a given group.
    /// This function doesn't take Pueue's configuration into account, it simply returns the next
    /// free integer key, starting from 0.
    ///
    /// This function should only be called when spawning a new process.
    /// At this point, we're sure that the worker pool for the given group already exists, hence
    /// the expect call.
    pub fn get_next_group_worker(&self, group: &str) -> usize {
        let pool = self
            .0
            .get(group)
            .expect("The worker pool should be initialized when getting the next worker id.");

        // This does a simple linear scan over the worker keys of the process group.
        // Keys in a BTreeMap are ordered, which is why we can start at 0 and check for each entry,
        // if it is the same as our current id.
        //
        // E.g. If all slots to the last are full, we should walk through all keys and increment by
        // one each time.
        // If the second slot is free, we increment once, break the loop in the second iteration
        // and return the new id.
        let mut next_worker_id = 0;
        for worker_id in pool.keys() {
            if worker_id != &next_worker_id {
                break;
            }
            next_worker_id += 1;
        }

        next_worker_id
    }

    /// Inserts a new children into the worker pool of the given group.
    ///
    /// This function should only be called when spawning a new process.
    /// At this point, we're sure that the worker pool for the given group already exists, hence
    /// the expect call.
    pub fn add_child(&mut self, group: &str, worker_id: usize, task_id: usize, child: Child) {
        let pool = self
            .0
            .get_mut(group)
            .expect("The worker pool should be initialized when inserting a new child.");

        pool.insert(worker_id, (task_id, child));
    }
}
<commit_msg>refactor: Simplify child search logic<commit_after>use std::collections::BTreeMap;
use std::process::Child;

/// This structure is needed to manage worker pools for groups.
/// It's a newtype pattern around a nested BTreeMap, which implements some convenience functions.
///
/// The datastructure contains these types of data:
/// BTreeMap<group, BTreeMap<group_worker_id, (task_id, Subprocess handle)>
pub struct Children(pub BTreeMap<String, BTreeMap<usize, (usize, Child)>>);

impl Children {
    /// Returns whether there are any active tasks across all groups.
    pub fn has_active_tasks(&self) -> bool {
        self.0.iter().any(|(_, pool)| !pool.is_empty())
    }

    /// A convenience function to check whether there's child with a given task_id.
    /// We have to do a nested linear search, as these datastructure aren't indexed via task_ids.
    pub fn has_child(&self, task_id: usize) -> bool {
        for pool in self.0.values() {
            for (child_task_id, _) in pool.values() {
                if child_task_id == &task_id {
                    return true;
                }
            }
        }

        false
    }

    /// A convenience function to get a child by its respective task_id.
    /// We have to do a nested linear search over all children of all pools,
    /// beceause these datastructure aren't indexed via task_ids.
    pub fn get_child(&self, task_id: usize) -> Option<&Child> {
        for pool in self.0.values() {
            for (child_task_id, child) in pool.values() {
                if child_task_id == &task_id {
                    return Some(child);
                }
            }
        }

        None
    }

    /// A convenience function to get a mutable child by its respective task_id.
    /// We have to do a nested linear search over all children of all pools,
    /// beceause these datastructure aren't indexed via task_ids.
    pub fn get_child_mut(&mut self, task_id: usize) -> Option<&mut Child> {
        for pool in self.0.values_mut() {
            for (child_task_id, child) in pool.values_mut() {
                if child_task_id == &task_id {
                    return Some(child);
                }
            }
        }

        None
    }

    /// A convenience function to get a list with all task_ids of all children.
    pub fn all_task_ids(&self) -> Vec<usize> {
        let mut task_ids = Vec::new();
        for pool in self.0.values() {
            for (task_id, _) in pool.values() {
                task_ids.push(*task_id)
            }
        }

        task_ids
    }

    /// Returns the next free worker slot for a given group.
    /// This function doesn't take Pueue's configuration into account, it simply returns the next
    /// free integer key, starting from 0.
    ///
    /// This function should only be called when spawning a new process.
    /// At this point, we're sure that the worker pool for the given group already exists, hence
    /// the expect call.
    pub fn get_next_group_worker(&self, group: &str) -> usize {
        let pool = self
            .0
            .get(group)
            .expect("The worker pool should be initialized when getting the next worker id.");

        // This does a simple linear scan over the worker keys of the process group.
        // Keys in a BTreeMap are ordered, which is why we can start at 0 and check for each entry,
        // if it is the same as our current id.
        //
        // E.g. If all slots to the last are full, we should walk through all keys and increment by
        // one each time.
        // If the second slot is free, we increment once, break the loop in the second iteration
        // and return the new id.
        let mut next_worker_id = 0;
        for worker_id in pool.keys() {
            if worker_id != &next_worker_id {
                break;
            }
            next_worker_id += 1;
        }

        next_worker_id
    }

    /// Inserts a new children into the worker pool of the given group.
    ///
    /// This function should only be called when spawning a new process.
    /// At this point, we're sure that the worker pool for the given group already exists, hence
    /// the expect call.
    pub fn add_child(&mut self, group: &str, worker_id: usize, task_id: usize, child: Child) {
        let pool = self
            .0
            .get_mut(group)
            .expect("The worker pool should be initialized when inserting a new child.");

        pool.insert(worker_id, (task_id, child));
    }
}
<|endoftext|>


<commit_before>//! An example of how to play with various graphics modes settings,
//! resize windows, etc.
//!
//! Prints instructions to the console.

extern crate ggez;
extern crate clap;
use clap::{Arg, App};
use ggez::*;
use ggez::graphics::{DrawMode, Point2};
use ggez::event::{Keycode, Mod};

use std::env;
use std::path;

enum WindowToggle {
    NONE,
    FORWARD,
    REVERSE,
}

struct WindowSettings {
    window_size_toggle: WindowToggle,
    toggle_fullscreen: bool,
    is_fullscreen: bool,
    num_of_resolutions: usize,
    resolution_index: usize,
    resize_projection: bool,
}

struct MainState {
    angle: f32, // in radians
    zoom: f32,
    image: graphics::Image,
    window_settings: WindowSettings,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let mut s = MainState {
            angle: 0.0,
            zoom: 1.0,
            image: graphics::Image::new(ctx, "/tile.png")?,
            window_settings: WindowSettings {
                toggle_fullscreen: false,
                window_size_toggle: WindowToggle::NONE,
                is_fullscreen: false,
                resolution_index: 0,
                num_of_resolutions: 0,
                resize_projection: false,
            },
        };

        let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
        s.window_settings.num_of_resolutions = resolutions.len();

        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        const DESIRED_FPS: u32 = 60;
        while timer::check_update_time(ctx, DESIRED_FPS) {
            self.angle += 0.01;

            if self.window_settings.toggle_fullscreen {
                ggez::graphics::set_fullscreen(ctx, self.window_settings.is_fullscreen)?;
                self.window_settings.toggle_fullscreen = false;
            }

            match self.window_settings.window_size_toggle {
                WindowToggle::FORWARD | WindowToggle::REVERSE => {
                    let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
                    let (width, height) = resolutions[self.window_settings.resolution_index];

                    ggez::graphics::set_resolution(ctx, width, height)?;

                    self.window_settings.window_size_toggle = WindowToggle::NONE;
                }
                _ => {}
            }
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::BLACK);
        graphics::clear(ctx);
        let rotation = timer::get_ticks(ctx) % 1000;
        graphics::set_color(ctx, graphics::WHITE)?;
        let circle = graphics::Mesh::new_circle(ctx,
                                                DrawMode::Line(3.0),
                                                Point2::new(0.0, 0.0),
                                                100.0,
                                                4.0)?;
        graphics::draw(ctx, &self.image, Point2::new(400.0, 300.0), 0.0)?;
        graphics::draw(ctx, &circle, Point2::new(400.0, 300.0), rotation as f32)?;

        // Let's draw a grid so we can see where the window bounds are.
        const COUNT: i32 = 10;
        for x in -COUNT..COUNT {
            for y in -COUNT..COUNT {
                const SPACING: i32 = 100;
                let fx = (x * SPACING) as f32;
                let fy = (y * SPACING) as f32;
                // println!("POS: {},{}", fx, fy);
                let r = (x as f32) / (COUNT as f32);
                let b = (y as f32) / (COUNT as f32);
                // println!("R: {}", r);
                let color = graphics::Color::new(r, 0.0, b, 1.0);
                graphics::set_color(ctx, color)?;
                graphics::rectangle(ctx, graphics::DrawMode::Fill, graphics::Rect::new(fx, fy, 5.0, 5.0))?
            }
        }
        graphics::present(ctx);
        Ok(())
    }

    fn key_up_event(&mut self, ctx: &mut Context, keycode: Keycode, _keymod: Mod, repeat: bool) {
        if !repeat {
            match keycode {
                Keycode::F => {
                    self.window_settings.toggle_fullscreen = true;
                    self.window_settings.is_fullscreen = !self.window_settings.is_fullscreen;
                }
                Keycode::H => {
                    self.window_settings.window_size_toggle = WindowToggle::FORWARD;
                    self.window_settings.resolution_index += 1;
                    self.window_settings.resolution_index %=
                        self.window_settings.num_of_resolutions;
                }
                Keycode::G => {
                    if self.window_settings.resolution_index > 0 {
                        self.window_settings.window_size_toggle = WindowToggle::REVERSE;
                        self.window_settings.resolution_index -= 1;
                        self.window_settings.resolution_index %=
                            self.window_settings.num_of_resolutions;
                    }
                },
                Keycode::Up => {
                    self.zoom += 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();

                },
                Keycode::Down => {
                    self.zoom -= 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();
                },
                Keycode::Space => {
                    self.window_settings.resize_projection = !self.window_settings.resize_projection;
                    println!("Resizing the projection on window resize is now: {}", self.window_settings.resize_projection);
                }
                _ => {}
            }
        }
    }

    fn resize_event(&mut self, ctx: &mut Context, width: u32, height: u32) {
        println!("Resized screen to {}, {}", width, height);
        if self.window_settings.resize_projection {
            let new_rect = graphics::Rect::new(0.0,
                                            0.0,
                                            width as f32 * self.zoom,
                                            height as f32 * self.zoom);
            graphics::set_screen_coordinates(ctx, new_rect).unwrap();
        }
    }
}

fn print_help() {
    println!("GRAPHICS SETTING EXAMPLE:");
    println!("    F: toggle fullscreen");
    println!("    H/G: Increase/decrease window sizes");
    println!("    Up/Down: Zoom in/out");
    println!("    Spacebar: Toggle whether or not to resize the projection when the window is resized");
    println!("    ");
    println!("    To see command-line options, run with `cargo run --example graphics_settings -- --help`");
    println!("    ");
}

pub fn main() {
    let matches = App::new("ggez graphics settings example")
        .arg(Arg::with_name("msaa")
                 .short("m")
                 .value_name("N")
                 .help("Number of MSAA samples to do (powers of 2 from 1 to 16)")
                 .takes_value(true))
        .get_matches();

    let msaa: u32 = matches
        .value_of("msaa")
        .unwrap_or("1")
        .parse()
        .expect("Option msaa needs to be a number!");
    let mut c = conf::Conf::new();
    c.window_setup.samples =
        conf::NumSamples::from_u32(msaa).expect("Option msaa needs to be 1, 2, 4, 8 or 16!");
    c.window_setup.resizable = true;

    let ctx = &mut Context::load_from_conf("graphics_settings", "ggez", c).unwrap();

    // We add the CARGO_MANIFEST_DIR/resources do the filesystems paths so
    // we we look in the cargo project for files.
    if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        ctx.filesystem.mount(&path, true);
        println!("Adding path {:?}", path);
    } else {
        println!("not building with cargo?");
    }

    print_help();
    let state = &mut MainState::new(ctx).unwrap();
    event::run(ctx, state).unwrap();
}
<commit_msg>Improved graphics settings example a little<commit_after>//! An example of how to play with various graphics modes settings,
//! resize windows, etc.
//!
//! Prints instructions to the console.

extern crate ggez;
extern crate clap;
use clap::{Arg, App};
use ggez::*;
use ggez::graphics::{DrawMode, Point2};
use ggez::event::{Keycode, Mod};

use std::env;
use std::path;

enum WindowToggle {
    NONE,
    FORWARD,
    REVERSE,
}

struct WindowSettings {
    window_size_toggle: bool,
    toggle_fullscreen: bool,
    is_fullscreen: bool,
    num_of_resolutions: usize,
    resolution_index: usize,
    resize_projection: bool,
}

struct MainState {
    angle: f32, // in radians
    zoom: f32,
    image: graphics::Image,
    window_settings: WindowSettings,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let mut s = MainState {
            angle: 0.0,
            zoom: 1.0,
            image: graphics::Image::new(ctx, "/tile.png")?,
            window_settings: WindowSettings {
                toggle_fullscreen: false,
                window_size_toggle: false,
                is_fullscreen: false,
                resolution_index: 0,
                num_of_resolutions: 0,
                resize_projection: false,
            },
        };

        let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
        s.window_settings.num_of_resolutions = resolutions.len();

        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        const DESIRED_FPS: u32 = 60;
        while timer::check_update_time(ctx, DESIRED_FPS) {
            self.angle += 0.01;

            if self.window_settings.toggle_fullscreen {
                ggez::graphics::set_fullscreen(ctx, self.window_settings.is_fullscreen)?;
                self.window_settings.toggle_fullscreen = false;
            }

            if self.window_settings.window_size_toggle {
                    let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
                    let (width, height) = resolutions[self.window_settings.resolution_index];

                    ggez::graphics::set_resolution(ctx, width, height)?;

                    self.window_settings.window_size_toggle = false;
            }
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::BLACK);
        graphics::clear(ctx);
        let rotation = timer::get_ticks(ctx) % 1000;
        graphics::set_color(ctx, graphics::WHITE)?;
        let circle = graphics::Mesh::new_circle(ctx,
                                                DrawMode::Line(3.0),
                                                Point2::new(0.0, 0.0),
                                                100.0,
                                                4.0)?;
        graphics::draw(ctx, &self.image, Point2::new(400.0, 300.0), 0.0)?;
        graphics::draw(ctx, &circle, Point2::new(400.0, 300.0), rotation as f32)?;

        // Let's draw a grid so we can see where the window bounds are.
        const COUNT: i32 = 10;
        for x in -COUNT..COUNT {
            for y in -COUNT..COUNT {
                const SPACING: i32 = 100;
                let fx = (x * SPACING) as f32;
                let fy = (y * SPACING) as f32;
                // println!("POS: {},{}", fx, fy);
                let r = (x as f32) / (COUNT as f32);
                let b = (y as f32) / (COUNT as f32);
                // println!("R: {}", r);
                let color = graphics::Color::new(r, 0.0, b, 1.0);
                graphics::set_color(ctx, color)?;
                graphics::rectangle(ctx, graphics::DrawMode::Fill, graphics::Rect::new(fx, fy, 5.0, 5.0))?
            }
        }
        graphics::present(ctx);
        Ok(())
    }

    fn mouse_button_down_event(&mut self, _ctx: &mut Context, _btn: event::MouseButton, x: i32, y: i32) {
        println!("Button clicked at: {} {}", x, y);
    }

    fn key_up_event(&mut self, ctx: &mut Context, keycode: Keycode, _keymod: Mod, repeat: bool) {
        if !repeat {
            match keycode {
                Keycode::F => {
                    self.window_settings.toggle_fullscreen = true;
                    self.window_settings.is_fullscreen = !self.window_settings.is_fullscreen;
                }
                Keycode::H => {
                    self.window_settings.window_size_toggle = true;
                    self.window_settings.resolution_index += 1;
                    self.window_settings.resolution_index %=
                        self.window_settings.num_of_resolutions;
                }
                Keycode::G => {
                    if self.window_settings.resolution_index > 0 {
                        self.window_settings.window_size_toggle = true;
                        self.window_settings.resolution_index -= 1;
                        self.window_settings.resolution_index %=
                            self.window_settings.num_of_resolutions;
                    }
                },
                Keycode::Up => {
                    self.zoom += 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();

                },
                Keycode::Down => {
                    self.zoom -= 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();
                },
                Keycode::Space => {
                    self.window_settings.resize_projection = !self.window_settings.resize_projection;
                    println!("Resizing the projection on window resize is now: {}", self.window_settings.resize_projection);
                }
                _ => {}
            }
        }
    }

    fn resize_event(&mut self, ctx: &mut Context, width: u32, height: u32) {
        println!("Resized screen to {}, {}", width, height);
        if self.window_settings.resize_projection {
            let new_rect = graphics::Rect::new(0.0,
                                            0.0,
                                            width as f32 * self.zoom,
                                            height as f32 * self.zoom);
            graphics::set_screen_coordinates(ctx, new_rect).unwrap();
        }
    }
}

fn print_help() {
    println!("GRAPHICS SETTING EXAMPLE:");
    println!("    F: toggle fullscreen");
    println!("    G/H: Increase/decrease window sizes");
    println!("    Up/Down: Zoom in/out");
    println!("    Spacebar: Toggle whether or not to resize the projection when the window is resized");
    println!("    ");
    println!("    To see command-line options, run with `cargo run --example graphics_settings -- --help`");
    println!("    ");
}

pub fn main() {
    let matches = App::new("ggez graphics settings example")
        .arg(Arg::with_name("msaa")
                 .short("m")
                 .value_name("N")
                 .help("Number of MSAA samples to do (powers of 2 from 1 to 16)")
                 .takes_value(true))
        .get_matches();

    let msaa: u32 = matches
        .value_of("msaa")
        .unwrap_or("1")
        .parse()
        .expect("Option msaa needs to be a number!");
    let mut c = conf::Conf::new();
    c.window_mode.fullscreen_type = conf::FullscreenType::True;
    c.window_setup.samples =
        conf::NumSamples::from_u32(msaa).expect("Option msaa needs to be 1, 2, 4, 8 or 16!");
    c.window_setup.resizable = true;
    println!("{:?}", c);

    let ctx = &mut Context::load_from_conf("graphics_settings", "ggez", c).unwrap();

    // We add the CARGO_MANIFEST_DIR/resources do the filesystems paths so
    // we we look in the cargo project for files.
    if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        ctx.filesystem.mount(&path, true);
        println!("Adding path {:?}", path);
    } else {
        println!("not building with cargo?");
    }

    print_help();
    let state = &mut MainState::new(ctx).unwrap();
    event::run(ctx, state).unwrap();
}
<|endoftext|>


<commit_before>fn main() {
    // In general, the `{}` will be automatically replaced with any
    // arguments. These will be stringified.
    println!("{} days", 31);

    // Without a suffix, 31 becomes an i32. You can change what type 31 is,
    // with a suffix.

    // There are various optional patterns this works with. Positional
    // arguments can be used.
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // As can named arguments.
    println!("{subject} {verb} {predicate}",
             predicate="over the lazy dog",
             subject="the quick brown fox",
             verb="jumps");

    // Special formatting can be specified after a `:`.
    println!("{} of {:b} people know binary, the other half don't", 1, 2);

    // You can right-align text with a specified width. This will output
    // "     1". 5 white spaces and a "1".
    println!("{number:>width$}", number=1, width=6);

    // You can pad numbers with extra zeroes. This will output "000001".
    println!("{number:>0width$}", number=1, width=6);

    // It will even check to make sure the correct number of arguments are
    // used.
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ Add the missing argument: "James"

    // Create a structure which contains an `i32`. Name it `Structure`.
    struct Structure(i32);

    // However, custom types such as this structure require more complicated
    // handling. This will not work.
    println!("This struct `{}` won't print...", Structure(3));
    // FIXME ^ Comment out this line.
}
<commit_msg>More accurate grammar terms in example<commit_after>fn main() {
    // In general, the `{}` will be automatically replaced with any
    // arguments. These will be stringified.
    println!("{} days", 31);

    // Without a suffix, 31 becomes an i32. You can change what type 31 is,
    // with a suffix.

    // There are various optional patterns this works with. Positional
    // arguments can be used.
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // As can named arguments.
    println!("{subject} {verb} {object}",
             object="the lazy dog",
             subject="the quick brown fox",
             verb="jumps over");

    // Special formatting can be specified after a `:`.
    println!("{} of {:b} people know binary, the other half don't", 1, 2);

    // You can right-align text with a specified width. This will output
    // "     1". 5 white spaces and a "1".
    println!("{number:>width$}", number=1, width=6);

    // You can pad numbers with extra zeroes. This will output "000001".
    println!("{number:>0width$}", number=1, width=6);

    // It will even check to make sure the correct number of arguments are
    // used.
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ Add the missing argument: "James"

    // Create a structure which contains an `i32`. Name it `Structure`.
    struct Structure(i32);

    // However, custom types such as this structure require more complicated
    // handling. This will not work.
    println!("This struct `{}` won't print...", Structure(3));
    // FIXME ^ Comment out this line.
}
<|endoftext|>


<commit_before>/// A data table consisting of varying column types and headers.
pub struct DataTable {
	pub data_cols: Vec<DataCols<f64>>,
}

impl DataTable {

	pub fn empty() -> DataTable {
		DataTable {
			data_cols: Vec::new(),
		}
	}

}

/// DataType enum
///
/// Not sure how this should be used.
enum DataType {
	Reals,
	Categorical,
}

/// A data column with a consistent data type.
pub struct DataCols<T> {
	data_type : DataType,
	pub data: Vec<T>,
	// If categorical - some kind of set for each category

}

impl<T> DataCols<T> {
	pub fn empty() -> DataCols<T> {
		DataCols {
			data_type: DataType::Reals,
			data: Vec::<T>::new(),
		}
	}
}<commit_msg>Basic data counting.<commit_after>/// A data table consisting of varying column types and headers.
pub struct DataTable {
	pub data_cols: Vec<DataCols<f64>>,
}

impl DataTable {

	pub fn empty() -> DataTable {
		DataTable {
			data_cols: Vec::new(),
		}
	}

	pub fn cols(&self) -> usize {
		self.data_cols.len()
	}

}

/// DataType enum
///
/// Not sure how this should be used.
enum DataType {
	Reals,
	Categorical,
}

/// A data column with a consistent data type.
pub struct DataCols<T> {
	data_type : DataType,
	pub data: Vec<T>,
	// If categorical - some kind of set for each category

}

impl<T> DataCols<T> {
	pub fn empty() -> DataCols<T> {
		DataCols {
			data_type: DataType::Reals,
			data: Vec::<T>::new(),
		}
	}

	pub fn len(&self) -> usize {
		self.data.len()
	}
}<|endoftext|>


<commit_before>pub trait Property {
    fn inherits_automatically() -> bool;
}

/// Generates a property definition that simply parses strings to enum variants
///
/// This can be used for properties with simple symbol-based values.
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```
/// make_ident_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, where
/// `type Data = ()` and `type Err = AttributeError`.
#[macro_export]
macro_rules! make_ident_property {
    ($name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[repr(C)]
        #[derive(Debug, Copy, Clone, PartialEq)]
        pub enum $name {
            $($variant),+
        }

        impl Default for $name {
            fn default() -> $name {
                $name::$default
            }
        }

        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }

        impl ::parsers::Parse for $name {
            type Data = ();
            type Err = ::error::AttributeError;

            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
                match s.trim() {
                    $($str_prop => Ok($name::$variant),)+

                    _ => Err(::error::AttributeError::from(::parsers::ParseError::new("invalid value"))),
                }
            }
        }
    };
}

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

    use parsers::Parse;

    #[test]
    fn check_generated_property() {
        make_ident_property! {
            Foo,
            default: Def,
            inherits_automatically: true,

            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property>::inherits_automatically(), true);

        assert!(<Foo as Parse>::parse("blargh", ()).is_err());
        assert_eq!(<Foo as Parse>::parse("bar", ()), Ok(Foo::Bar));
    }
}
<commit_msg>macro: remove the repr C<commit_after>pub trait Property {
    fn inherits_automatically() -> bool;
}

/// Generates a property definition that simply parses strings to enum variants
///
/// This can be used for properties with simple symbol-based values.
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```
/// make_ident_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, where
/// `type Data = ()` and `type Err = AttributeError`.
#[macro_export]
macro_rules! make_ident_property {
    ($name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        pub enum $name {
            $($variant),+
        }

        impl Default for $name {
            fn default() -> $name {
                $name::$default
            }
        }

        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }

        impl ::parsers::Parse for $name {
            type Data = ();
            type Err = ::error::AttributeError;

            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
                match s.trim() {
                    $($str_prop => Ok($name::$variant),)+

                    _ => Err(::error::AttributeError::from(::parsers::ParseError::new("invalid value"))),
                }
            }
        }
    };
}

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

    use parsers::Parse;

    #[test]
    fn check_generated_property() {
        make_ident_property! {
            Foo,
            default: Def,
            inherits_automatically: true,

            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property>::inherits_automatically(), true);

        assert!(<Foo as Parse>::parse("blargh", ()).is_err());
        assert_eq!(<Foo as Parse>::parse("bar", ()), Ok(Foo::Bar));
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use regex::Regex;
use std::ascii::AsciiExt;
use std::cmp;

#[deriving(Show, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub static LOG_LEVEL_NAMES: [&'static str, ..4] = ["ERROR", "WARN", "INFO",
                                               "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    level.parse::<u32>().or_else(|| {
        let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
        pos.map(|p| p as u32 + 1)
    }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<Regex>) {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return (dirs, None);
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match parse_log_level(part0) {
                    Some(num) => (num, None),
                    None => (::MAX_LOG_LEVEL, Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
            (Some(part0), Some(part1), None) => {
                match parse_log_level(part1) {
                    Some(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    let filter = filter.map_or(None, |filter| {
        match Regex::new(filter) {
            Ok(re) => Some(re),
            Err(e) => {
                println!("warning: invalid regex filter - {}", e);
                None
            }
        }
    });

    return (dirs, filter);
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::WARN);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let (dirs, filter) = parse_logging_spec("warn,crate2=4");
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_string()));
        assert_eq!(dirs[1].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_valid_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
    }

    #[test]
    fn parse_logging_spec_invalid_crate_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
    }

    #[test]
    fn parse_logging_spec_empty_with_filter() {
        let (dirs, filter) = parse_logging_spec("crate1/a*c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate1".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
    }
}
<commit_msg>Array syntax fallout<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use regex::Regex;
use std::ascii::AsciiExt;
use std::cmp;

#[deriving(Show, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub static LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
                                               "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    level.parse::<u32>().or_else(|| {
        let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
        pos.map(|p| p as u32 + 1)
    }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<Regex>) {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return (dirs, None);
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match parse_log_level(part0) {
                    Some(num) => (num, None),
                    None => (::MAX_LOG_LEVEL, Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
            (Some(part0), Some(part1), None) => {
                match parse_log_level(part1) {
                    Some(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    let filter = filter.map_or(None, |filter| {
        match Regex::new(filter) {
            Ok(re) => Some(re),
            Err(e) => {
                println!("warning: invalid regex filter - {}", e);
                None
            }
        }
    });

    return (dirs, filter);
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::WARN);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let (dirs, filter) = parse_logging_spec("warn,crate2=4");
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_string()));
        assert_eq!(dirs[1].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_valid_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
    }

    #[test]
    fn parse_logging_spec_invalid_crate_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
    }

    #[test]
    fn parse_logging_spec_empty_with_filter() {
        let (dirs, filter) = parse_logging_spec("crate1/a*c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate1".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
    }
}
<|endoftext|>


<commit_before>use crypto;
use crypto::mac::Mac;
use crypto::digest::Digest;
use zeroconf::DNSService;
use tiny_http::{Method, Response, ResponseBox, Server};
use num::BigUint;
use url;
use rand;
use rustc_serialize::base64::{self, ToBase64, FromBase64};

use session::Session;
use diffie_hellman::{DH_GENERATOR, DH_PRIME};
use util;

pub struct DiscoveryManager {
    session: Session,
    private_key: BigUint,
    public_key: BigUint
}

fn not_found() -> ResponseBox {
    Response::from_string("Not found").with_status_code(404).boxed()
}

impl DiscoveryManager {
    pub fn new(session: Session) -> DiscoveryManager {
        let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
        let private_key = BigUint::from_bytes_be(&key_data);
        let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);

        DiscoveryManager {
            session: session,
            private_key: private_key,
            public_key: public_key,
        }
    }

    fn get_info(&self) -> ResponseBox {
        let public_key = self.public_key.to_bytes_be().to_base64(base64::STANDARD);
        Response::from_string(json!({
            "status": 101,
            "statusString": "ERROR-OK",
            "spotifyError": 0,
            "version": "2.1.0",
            "deviceID": (self.session.0.data.read().unwrap().device_id),
            "remoteName": (self.session.0.config.device_name),
            "activeUser": "",
            "publicKey": (public_key),
            "deviceType": "UNKNOWN",
            "libraryVersion": "0.1.0",
            "accountReq": "PREMIUM",
            "brandDisplayName": "librespot",
            "modelDisplayName": "librespot",
        }).to_string()).boxed()
    }

    fn add_user(&self, params: &[(String, String)]) -> ResponseBox {
        let &(_, ref username) = params.iter().find(|& &(ref key, _)| key == "userName").unwrap();
        let &(_, ref encrypted_blob) = params.iter().find(|& &(ref key, _)| key == "blob").unwrap();
        let &(_, ref client_key) = params.iter().find(|& &(ref key, _)| key == "clientKey").unwrap();

        let encrypted_blob = encrypted_blob.from_base64().unwrap();

        let client_key = client_key.from_base64().unwrap();
        let client_key = BigUint::from_bytes_be(&client_key);

        let shared_key = util::powm(&client_key, &self.private_key, &DH_PRIME);

        let iv = &encrypted_blob[0..16];
        let encrypted = &encrypted_blob[16..encrypted_blob.len()-20];
        let cksum = &encrypted_blob[encrypted_blob.len()-20..encrypted_blob.len()];

        let base_key = {
            let mut data = [0u8; 20];
            let mut h = crypto::sha1::Sha1::new();
            h.input(&shared_key.to_bytes_be());
            h.result(&mut data);
            data[..16].to_owned()
        };

        let checksum_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input("checksum".as_bytes());
            h.result().code().to_owned()
        };

        let encryption_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input("encryption".as_bytes());
            h.result().code().to_owned()
        };

        let mac = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &checksum_key);
            h.input(encrypted);
            h.result().code().to_owned()
        };

        assert_eq!(mac.as_slice(), cksum);

        let decrypted = {
            let mut data = vec![0u8; encrypted.len()];
            let mut cipher = crypto::aes::ctr(crypto::aes::KeySize::KeySize128, &encryption_key, &iv);
            cipher.process(&encrypted, &mut data);
            String::from_utf8(data).unwrap()
        };

        self.session.login_blob(username.to_owned(), &decrypted).unwrap();

        Response::from_string(json!({
            "status": 101,
            "spotifyError": 0,
            "statusString": "ERROR-OK"
        }).to_string()).boxed()
    }

    pub fn run(&mut self) {
        let server = Server::http("0.0.0.0:8000").unwrap();
        let svc = DNSService::register(Some(&self.session.0.config.device_name),
                                       "_spotify-connect._tcp",
                                       None,
                                       None,
                                       8000,
                                       &["VERSION=1.0", "CPath=/"]
                                       ).unwrap();

        for mut request in server.incoming_requests() {
            let (_, query, _) = url::parse_path(request.url()).unwrap();
            let mut params = query.map(|q| url::form_urlencoded::parse(q.as_bytes())).unwrap_or(Vec::new());

            if *request.method() == Method::Post {
                let mut body = Vec::new();
                request.as_reader().read_to_end(&mut body).unwrap();
                let form = url::form_urlencoded::parse(&body);
                params.extend(form);
            }

            println!("{:?}", params);

            let &(_, ref action) = params.iter().find(|& &(ref key, _)| key == "action").unwrap();
            match action.as_ref() {
                "getInfo" => request.respond(self.get_info()).unwrap(),
                "addUser" => {
                    request.respond(self.add_user(&params)).unwrap();
                    break;
                }
                _ => request.respond(not_found()).unwrap(),
            };
        }

        drop(svc);
    }
}

<commit_msg>discovery: Truncate the AES key to 128<commit_after>use crypto;
use crypto::mac::Mac;
use crypto::digest::Digest;
use zeroconf::DNSService;
use tiny_http::{Method, Response, ResponseBox, Server};
use num::BigUint;
use url;
use rand;
use rustc_serialize::base64::{self, ToBase64, FromBase64};

use session::Session;
use diffie_hellman::{DH_GENERATOR, DH_PRIME};
use util;

pub struct DiscoveryManager {
    session: Session,
    private_key: BigUint,
    public_key: BigUint
}

fn not_found() -> ResponseBox {
    Response::from_string("Not found").with_status_code(404).boxed()
}

impl DiscoveryManager {
    pub fn new(session: Session) -> DiscoveryManager {
        let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
        let private_key = BigUint::from_bytes_be(&key_data);
        let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);

        DiscoveryManager {
            session: session,
            private_key: private_key,
            public_key: public_key,
        }
    }

    fn get_info(&self) -> ResponseBox {
        let public_key = self.public_key.to_bytes_be().to_base64(base64::STANDARD);
        Response::from_string(json!({
            "status": 101,
            "statusString": "ERROR-OK",
            "spotifyError": 0,
            "version": "2.1.0",
            "deviceID": (self.session.0.data.read().unwrap().device_id),
            "remoteName": (self.session.0.config.device_name),
            "activeUser": "",
            "publicKey": (public_key),
            "deviceType": "UNKNOWN",
            "libraryVersion": "0.1.0",
            "accountReq": "PREMIUM",
            "brandDisplayName": "librespot",
            "modelDisplayName": "librespot",
        }).to_string()).boxed()
    }

    fn add_user(&self, params: &[(String, String)]) -> ResponseBox {
        let &(_, ref username) = params.iter().find(|& &(ref key, _)| key == "userName").unwrap();
        let &(_, ref encrypted_blob) = params.iter().find(|& &(ref key, _)| key == "blob").unwrap();
        let &(_, ref client_key) = params.iter().find(|& &(ref key, _)| key == "clientKey").unwrap();

        let encrypted_blob = encrypted_blob.from_base64().unwrap();

        let client_key = client_key.from_base64().unwrap();
        let client_key = BigUint::from_bytes_be(&client_key);

        let shared_key = util::powm(&client_key, &self.private_key, &DH_PRIME);

        let iv = &encrypted_blob[0..16];
        let encrypted = &encrypted_blob[16..encrypted_blob.len()-20];
        let cksum = &encrypted_blob[encrypted_blob.len()-20..encrypted_blob.len()];

        let base_key = {
            let mut data = [0u8; 20];
            let mut h = crypto::sha1::Sha1::new();
            h.input(&shared_key.to_bytes_be());
            h.result(&mut data);
            data[..16].to_owned()
        };

        let checksum_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input("checksum".as_bytes());
            h.result().code().to_owned()
        };

        let encryption_key = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &base_key);
            h.input("encryption".as_bytes());
            h.result().code().to_owned()
        };

        let mac = {
            let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &checksum_key);
            h.input(encrypted);
            h.result().code().to_owned()
        };

        assert_eq!(mac.as_slice(), cksum);

        let decrypted = {
            let mut data = vec![0u8; encrypted.len()];
            let mut cipher = crypto::aes::ctr(crypto::aes::KeySize::KeySize128, &encryption_key[0..16], &iv);
            cipher.process(&encrypted, &mut data);
            String::from_utf8(data).unwrap()
        };

        self.session.login_blob(username.to_owned(), &decrypted).unwrap();

        Response::from_string(json!({
            "status": 101,
            "spotifyError": 0,
            "statusString": "ERROR-OK"
        }).to_string()).boxed()
    }

    pub fn run(&mut self) {
        let server = Server::http("0.0.0.0:8000").unwrap();
        let svc = DNSService::register(Some(&self.session.0.config.device_name),
                                       "_spotify-connect._tcp",
                                       None,
                                       None,
                                       8000,
                                       &["VERSION=1.0", "CPath=/"]
                                       ).unwrap();

        for mut request in server.incoming_requests() {
            let (_, query, _) = url::parse_path(request.url()).unwrap();
            let mut params = query.map(|q| url::form_urlencoded::parse(q.as_bytes())).unwrap_or(Vec::new());

            if *request.method() == Method::Post {
                let mut body = Vec::new();
                request.as_reader().read_to_end(&mut body).unwrap();
                let form = url::form_urlencoded::parse(&body);
                params.extend(form);
            }

            println!("{:?}", params);

            let &(_, ref action) = params.iter().find(|& &(ref key, _)| key == "action").unwrap();
            match action.as_ref() {
                "getInfo" => request.respond(self.get_info()).unwrap(),
                "addUser" => {
                    request.respond(self.add_user(&params)).unwrap();
                    break;
                }
                _ => request.respond(not_found()).unwrap(),
            };
        }

        drop(svc);
    }
}

<|endoftext|>


<commit_before>//! Types for compile-time endianity.

use byteorder;
use parser::{Error, Result};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, Index, Range, RangeFrom, RangeTo};

/// A trait describing the endianity of some buffer.
///
/// All interesting methods are from the `byteorder` crate's `ByteOrder`
/// trait. All methods are static. You shouldn't instantiate concrete objects
/// that implement this trait, it is just used as compile-time phantom data.
pub trait Endianity
    : byteorder::ByteOrder + Debug + Default + Clone + Copy + PartialEq + Eq {
}

/// Little endian byte order.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LittleEndian {}

impl Default for LittleEndian {
    fn default() -> LittleEndian {
        unreachable!()
    }
}

impl byteorder::ByteOrder for LittleEndian {
    fn read_u16(buf: &[u8]) -> u16 {
        byteorder::LittleEndian::read_u16(buf)
    }
    fn read_u32(buf: &[u8]) -> u32 {
        byteorder::LittleEndian::read_u32(buf)
    }
    fn read_u64(buf: &[u8]) -> u64 {
        byteorder::LittleEndian::read_u64(buf)
    }
    fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
        byteorder::LittleEndian::read_uint(buf, nbytes)
    }
    fn write_u16(buf: &mut [u8], n: u16) {
        byteorder::LittleEndian::write_u16(buf, n)
    }
    fn write_u32(buf: &mut [u8], n: u32) {
        byteorder::LittleEndian::write_u32(buf, n)
    }
    fn write_u64(buf: &mut [u8], n: u64) {
        byteorder::LittleEndian::write_u64(buf, n)
    }
    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
        byteorder::LittleEndian::write_uint(buf, n, nbytes)
    }
}

impl Endianity for LittleEndian {}

/// Big endian byte order.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BigEndian {}

impl Default for BigEndian {
    fn default() -> BigEndian {
        unreachable!()
    }
}

impl byteorder::ByteOrder for BigEndian {
    fn read_u16(buf: &[u8]) -> u16 {
        byteorder::BigEndian::read_u16(buf)
    }
    fn read_u32(buf: &[u8]) -> u32 {
        byteorder::BigEndian::read_u32(buf)
    }
    fn read_u64(buf: &[u8]) -> u64 {
        byteorder::BigEndian::read_u64(buf)
    }
    fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
        byteorder::BigEndian::read_uint(buf, nbytes)
    }
    fn write_u16(buf: &mut [u8], n: u16) {
        byteorder::BigEndian::write_u16(buf, n)
    }
    fn write_u32(buf: &mut [u8], n: u32) {
        byteorder::BigEndian::write_u32(buf, n)
    }
    fn write_u64(buf: &mut [u8], n: u64) {
        byteorder::BigEndian::write_u64(buf, n)
    }
    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
        byteorder::BigEndian::write_uint(buf, n, nbytes)
    }
}

impl Endianity for BigEndian {}

/// The native endianity for the target platform.
#[cfg(target_endian = "little")]
pub type NativeEndian = LittleEndian;
#[cfg(target_endian = "big")]
pub type NativeEndian = BigEndian;

/// A `&[u8]` slice with compile-time endianity metadata.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EndianBuf<'input, Endian>(pub &'input [u8], pub PhantomData<Endian>)
    where Endian: Endianity;

impl<'input, Endian> EndianBuf<'input, Endian>
    where Endian: Endianity
{
    /// Construct a new `EndianBuf` with the given buffer.
    pub fn new(buf: &'input [u8]) -> EndianBuf<'input, Endian> {
        EndianBuf(buf, PhantomData)
    }

    /// Split the buffer in two at the given index, resulting in the tuple where
    /// the first item has range [0, idx), and the second has range
    /// [idx, len). Panics if the index is out of bounds.
    #[inline]
    pub fn split_at(&self, idx: usize) -> (EndianBuf<'input, Endian>, EndianBuf<'input, Endian>) {
        (self.range_to(..idx), self.range_from(idx..))
    }

    /// The same as `split_at`, but returns a `Result` rather than panicking
    /// when the index is out of bounds.
    #[inline]
    pub fn try_split_at(&self,
                        idx: usize)
                        -> Result<(EndianBuf<'input, Endian>, EndianBuf<'input, Endian>)> {
        if idx > self.len() {
            Err(Error::BadLength)
        } else {
            Ok(self.split_at(idx))
        }
    }
}

/// # Range Methods
///
/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't
/// implement `Index<Range<usize>>` to return a new `EndianBuf` the way we would
/// like to. Instead, we abandon fancy indexing operators and have these plain
/// old methods.
impl<'input, Endian> EndianBuf<'input, Endian>
    where Endian: Endianity
{
    /// Take the given `start..end` range of the underlying buffer and return a
    /// new `EndianBuf`.
    ///
    /// ```
    /// use gimli::{EndianBuf, LittleEndian};
    ///
    /// let buf = [0x01, 0x02, 0x03, 0x04];
    /// let endian_buf = EndianBuf::<LittleEndian>::new(&buf);
    /// assert_eq!(endian_buf.range(1..3),
    ///            EndianBuf::new(&buf[1..3]));
    /// ```
    pub fn range(&self, idx: Range<usize>) -> EndianBuf<'input, Endian> {
        EndianBuf(&self.0[idx], self.1)
    }

    /// Take the given `start..` range of the underlying buffer and return a new
    /// `EndianBuf`.
    ///
    /// ```
    /// use gimli::{EndianBuf, LittleEndian};
    ///
    /// let buf = [0x01, 0x02, 0x03, 0x04];
    /// let endian_buf = EndianBuf::<LittleEndian>::new(&buf);
    /// assert_eq!(endian_buf.range_from(2..),
    ///            EndianBuf::new(&buf[2..]));
    /// ```
    pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianBuf<'input, Endian> {
        EndianBuf(&self.0[idx], self.1)
    }

    /// Take the given `..end` range of the underlying buffer and return a new
    /// `EndianBuf`.
    ///
    /// ```
    /// use gimli::{EndianBuf, LittleEndian};
    ///
    /// let buf = [0x01, 0x02, 0x03, 0x04];
    /// let endian_buf = EndianBuf::<LittleEndian>::new(&buf);
    /// assert_eq!(endian_buf.range_to(..3),
    ///            EndianBuf::new(&buf[..3]));
    /// ```
    pub fn range_to(&self, idx: RangeTo<usize>) -> EndianBuf<'input, Endian> {
        EndianBuf(&self.0[idx], self.1)
    }
}

impl<'input, Endian> Index<usize> for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    type Output = u8;
    fn index(&self, idx: usize) -> &Self::Output {
        &self.0[idx]
    }
}

impl<'input, Endian> Index<RangeFrom<usize>> for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    type Output = [u8];
    fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
        &self.0[idx]
    }
}

impl<'input, Endian> Deref for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        self.0
    }
}

impl<'input, Endian> Into<&'input [u8]> for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    fn into(self) -> &'input [u8] {
        self.0
    }
}

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

    #[test]
    fn test_endian_buf_split_at() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        assert_eq!(eb.split_at(3),
                   (EndianBuf::new(&buf[..3]), EndianBuf::new(&buf[3..])));
    }

    #[test]
    #[should_panic]
    fn test_endian_buf_split_at_out_of_bounds() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        eb.split_at(30);
    }

    #[test]
    fn test_endian_buf_try_split_at() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        assert_eq!(eb.try_split_at(3),
                   Ok((EndianBuf::new(&buf[..3]), EndianBuf::new(&buf[3..]))));
    }

    #[test]
    fn test_endian_buf_try_split_at_out_of_bounds() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        assert_eq!(Err(Error::BadLength), eb.try_split_at(30));
    }
}
<commit_msg>Add Endianity::is_big_endian()<commit_after>//! Types for compile-time endianity.

use byteorder;
use parser::{Error, Result};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, Index, Range, RangeFrom, RangeTo};

/// A trait describing the endianity of some buffer.
///
/// All interesting methods are from the `byteorder` crate's `ByteOrder`
/// trait. All methods are static. You shouldn't instantiate concrete objects
/// that implement this trait, it is just used as compile-time phantom data.
pub trait Endianity
    : byteorder::ByteOrder + Debug + Default + Clone + Copy + PartialEq + Eq {
    /// Return true for big endian byte order.
    fn is_big_endian() -> bool;

    /// Return true for little endian byte order.
    fn is_little_endian() -> bool {
        !Self::is_big_endian()
    }
}

/// Little endian byte order.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LittleEndian {}

impl Default for LittleEndian {
    fn default() -> LittleEndian {
        unreachable!()
    }
}

impl byteorder::ByteOrder for LittleEndian {
    fn read_u16(buf: &[u8]) -> u16 {
        byteorder::LittleEndian::read_u16(buf)
    }
    fn read_u32(buf: &[u8]) -> u32 {
        byteorder::LittleEndian::read_u32(buf)
    }
    fn read_u64(buf: &[u8]) -> u64 {
        byteorder::LittleEndian::read_u64(buf)
    }
    fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
        byteorder::LittleEndian::read_uint(buf, nbytes)
    }
    fn write_u16(buf: &mut [u8], n: u16) {
        byteorder::LittleEndian::write_u16(buf, n)
    }
    fn write_u32(buf: &mut [u8], n: u32) {
        byteorder::LittleEndian::write_u32(buf, n)
    }
    fn write_u64(buf: &mut [u8], n: u64) {
        byteorder::LittleEndian::write_u64(buf, n)
    }
    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
        byteorder::LittleEndian::write_uint(buf, n, nbytes)
    }
}

impl Endianity for LittleEndian {
    fn is_big_endian() -> bool {
        false
    }
}

/// Big endian byte order.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BigEndian {}

impl Default for BigEndian {
    fn default() -> BigEndian {
        unreachable!()
    }
}

impl byteorder::ByteOrder for BigEndian {
    fn read_u16(buf: &[u8]) -> u16 {
        byteorder::BigEndian::read_u16(buf)
    }
    fn read_u32(buf: &[u8]) -> u32 {
        byteorder::BigEndian::read_u32(buf)
    }
    fn read_u64(buf: &[u8]) -> u64 {
        byteorder::BigEndian::read_u64(buf)
    }
    fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
        byteorder::BigEndian::read_uint(buf, nbytes)
    }
    fn write_u16(buf: &mut [u8], n: u16) {
        byteorder::BigEndian::write_u16(buf, n)
    }
    fn write_u32(buf: &mut [u8], n: u32) {
        byteorder::BigEndian::write_u32(buf, n)
    }
    fn write_u64(buf: &mut [u8], n: u64) {
        byteorder::BigEndian::write_u64(buf, n)
    }
    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
        byteorder::BigEndian::write_uint(buf, n, nbytes)
    }
}

impl Endianity for BigEndian {
    fn is_big_endian() -> bool {
        true
    }
}

/// The native endianity for the target platform.
#[cfg(target_endian = "little")]
pub type NativeEndian = LittleEndian;
#[cfg(target_endian = "big")]
pub type NativeEndian = BigEndian;

/// A `&[u8]` slice with compile-time endianity metadata.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EndianBuf<'input, Endian>(pub &'input [u8], pub PhantomData<Endian>)
    where Endian: Endianity;

impl<'input, Endian> EndianBuf<'input, Endian>
    where Endian: Endianity
{
    /// Construct a new `EndianBuf` with the given buffer.
    pub fn new(buf: &'input [u8]) -> EndianBuf<'input, Endian> {
        EndianBuf(buf, PhantomData)
    }

    /// Split the buffer in two at the given index, resulting in the tuple where
    /// the first item has range [0, idx), and the second has range
    /// [idx, len). Panics if the index is out of bounds.
    #[inline]
    pub fn split_at(&self, idx: usize) -> (EndianBuf<'input, Endian>, EndianBuf<'input, Endian>) {
        (self.range_to(..idx), self.range_from(idx..))
    }

    /// The same as `split_at`, but returns a `Result` rather than panicking
    /// when the index is out of bounds.
    #[inline]
    pub fn try_split_at(&self,
                        idx: usize)
                        -> Result<(EndianBuf<'input, Endian>, EndianBuf<'input, Endian>)> {
        if idx > self.len() {
            Err(Error::BadLength)
        } else {
            Ok(self.split_at(idx))
        }
    }
}

/// # Range Methods
///
/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't
/// implement `Index<Range<usize>>` to return a new `EndianBuf` the way we would
/// like to. Instead, we abandon fancy indexing operators and have these plain
/// old methods.
impl<'input, Endian> EndianBuf<'input, Endian>
    where Endian: Endianity
{
    /// Take the given `start..end` range of the underlying buffer and return a
    /// new `EndianBuf`.
    ///
    /// ```
    /// use gimli::{EndianBuf, LittleEndian};
    ///
    /// let buf = [0x01, 0x02, 0x03, 0x04];
    /// let endian_buf = EndianBuf::<LittleEndian>::new(&buf);
    /// assert_eq!(endian_buf.range(1..3),
    ///            EndianBuf::new(&buf[1..3]));
    /// ```
    pub fn range(&self, idx: Range<usize>) -> EndianBuf<'input, Endian> {
        EndianBuf(&self.0[idx], self.1)
    }

    /// Take the given `start..` range of the underlying buffer and return a new
    /// `EndianBuf`.
    ///
    /// ```
    /// use gimli::{EndianBuf, LittleEndian};
    ///
    /// let buf = [0x01, 0x02, 0x03, 0x04];
    /// let endian_buf = EndianBuf::<LittleEndian>::new(&buf);
    /// assert_eq!(endian_buf.range_from(2..),
    ///            EndianBuf::new(&buf[2..]));
    /// ```
    pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianBuf<'input, Endian> {
        EndianBuf(&self.0[idx], self.1)
    }

    /// Take the given `..end` range of the underlying buffer and return a new
    /// `EndianBuf`.
    ///
    /// ```
    /// use gimli::{EndianBuf, LittleEndian};
    ///
    /// let buf = [0x01, 0x02, 0x03, 0x04];
    /// let endian_buf = EndianBuf::<LittleEndian>::new(&buf);
    /// assert_eq!(endian_buf.range_to(..3),
    ///            EndianBuf::new(&buf[..3]));
    /// ```
    pub fn range_to(&self, idx: RangeTo<usize>) -> EndianBuf<'input, Endian> {
        EndianBuf(&self.0[idx], self.1)
    }
}

impl<'input, Endian> Index<usize> for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    type Output = u8;
    fn index(&self, idx: usize) -> &Self::Output {
        &self.0[idx]
    }
}

impl<'input, Endian> Index<RangeFrom<usize>> for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    type Output = [u8];
    fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
        &self.0[idx]
    }
}

impl<'input, Endian> Deref for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        self.0
    }
}

impl<'input, Endian> Into<&'input [u8]> for EndianBuf<'input, Endian>
    where Endian: Endianity
{
    fn into(self) -> &'input [u8] {
        self.0
    }
}

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

    #[test]
    fn test_endian_buf_split_at() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        assert_eq!(eb.split_at(3),
                   (EndianBuf::new(&buf[..3]), EndianBuf::new(&buf[3..])));
    }

    #[test]
    #[should_panic]
    fn test_endian_buf_split_at_out_of_bounds() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        eb.split_at(30);
    }

    #[test]
    fn test_endian_buf_try_split_at() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        assert_eq!(eb.try_split_at(3),
                   Ok((EndianBuf::new(&buf[..3]), EndianBuf::new(&buf[3..]))));
    }

    #[test]
    fn test_endian_buf_try_split_at_out_of_bounds() {
        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
        let eb = EndianBuf::<NativeEndian>::new(&buf);
        assert_eq!(Err(Error::BadLength), eb.try_split_at(30));
    }
}
<|endoftext|>