<commit_before>use std::io::Cursor;
use std::cmp::PartialEq;

use FromCursor;
use types::{CString, CStringList, CInet};

// Event types
const TOPOLOGY_CHANGE: &'static str = "TOPOLOGY_CHANGE";
const STATUS_CHANGE: &'static str = "STATUS_CHANGE";
const SCHEMA_CHANGE: &'static str = "SCHEMA_CHANGE";

// Topologe changes
const NEW_NODE: &'static str = "NEW_NODE";
const REMOVED_NODE: &'static str = "REMOVED_NODE";

// Status changes
const UP: &'static str = "UP";
const DOWN: &'static str = "DOWN";

// Schema changes
const CREATED: &'static str = "CREATED";
const UPDATED: &'static str = "UPDATED";
const DROPPED: &'static str = "DROPPED";

// Schema change targets
const KEYSPACE: &'static str = "KEYSPACE";
const TABLE: &'static str = "TABLE";
const TYPE: &'static str = "TYPE";
const FUNCTION: &'static str = "FUNCTION";
const AGGREGATE: &'static str = "AGGREGATE";

/// Simplified `ServerEvent` that does not contain details
/// about a concrete change. It may be useful for subscription
/// when you need only string representation of an event.
#[derive(Debug, PartialEq)]
pub enum SimpleServerEvent {
    TopologyChange,
    StatusChange,
    SchemaChange
}

impl SimpleServerEvent {
    pub fn as_string(&self) -> String {
        match self {
            &SimpleServerEvent::TopologyChange => String::from(TOPOLOGY_CHANGE),
            &SimpleServerEvent::StatusChange => String::from(STATUS_CHANGE),
            &SimpleServerEvent::SchemaChange => String::from(SCHEMA_CHANGE)
        }
    }
}

impl From<ServerEvent> for SimpleServerEvent {
    fn from(event: ServerEvent) -> SimpleServerEvent {
        match event {
            ServerEvent::TopologyChange(_) => SimpleServerEvent::TopologyChange,
            ServerEvent::StatusChange(_) => SimpleServerEvent::TopologyChange,
            ServerEvent::SchemaChange(_) => SimpleServerEvent::TopologyChange,
        }
    }
}

impl<'a> From<&'a ServerEvent> for SimpleServerEvent {
    fn from(event: &'a ServerEvent) -> SimpleServerEvent {
        match event {
            &ServerEvent::TopologyChange(_) => SimpleServerEvent::TopologyChange,
            &ServerEvent::StatusChange(_) => SimpleServerEvent::TopologyChange,
            &ServerEvent::SchemaChange(_) => SimpleServerEvent::TopologyChange,
        }
    }
}

impl PartialEq<ServerEvent> for SimpleServerEvent {
    fn eq(&self, full_event: &ServerEvent) -> bool {
        self == &SimpleServerEvent::from(full_event)
    }
}

/// Full server event that contains all details about a concreate change.
#[derive(Debug)]
pub enum ServerEvent {
    /// Events related to change in the cluster topology
    TopologyChange(TopologyChange),
    /// Events related to change of node status.
    StatusChange(StatusChange),
    /// Events related to schema change.
    SchemaChange(SchemaChange)
}

impl PartialEq<SimpleServerEvent> for ServerEvent {
    fn eq(&self, event: &SimpleServerEvent) -> bool {
        &SimpleServerEvent::from(self) == event
    }
}

impl FromCursor for ServerEvent {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> ServerEvent {
        let event_type = CString::from_cursor(&mut cursor);
        match event_type.as_str() {
            TOPOLOGY_CHANGE => ServerEvent::TopologyChange(
                TopologyChange::from_cursor(&mut cursor)
            ),
            STATUS_CHANGE => ServerEvent::StatusChange(
                StatusChange::from_cursor(&mut cursor)
            ),
            SCHEMA_CHANGE => ServerEvent::SchemaChange(
                SchemaChange::from_cursor(&mut cursor)
            ),
            _ => unreachable!()
        }
    }
}

/// Events related to change in the cluster topology
#[derive(Debug)]
pub struct TopologyChange {
    pub change_type: TopologyChangeType,
    pub addr: CInet
}

impl FromCursor for TopologyChange {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> TopologyChange {
        let change_type = TopologyChangeType::from_cursor(&mut cursor);
        let addr = CInet::from_cursor(&mut cursor);

        TopologyChange {
            change_type: change_type,
            addr: addr
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum TopologyChangeType {
    NewNode,
    RemovedNode
}

impl FromCursor for TopologyChangeType {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> TopologyChangeType {
        match CString::from_cursor(&mut cursor).as_str() {
            NEW_NODE => TopologyChangeType::NewNode,
            REMOVED_NODE => TopologyChangeType::RemovedNode,
            _ => unreachable!()
        }
    }
}

/// Events related to change of node status.
#[derive(Debug)]
pub struct StatusChange {
    pub change_type: StatusChangeType,
    pub addr: CInet
}

impl FromCursor for StatusChange {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> StatusChange {
        let change_type = StatusChangeType::from_cursor(&mut cursor);
        let addr = CInet::from_cursor(&mut cursor);

        StatusChange {
            change_type: change_type,
            addr: addr
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum StatusChangeType {
    Up,
    Down
}

impl FromCursor for StatusChangeType {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> StatusChangeType {
        match CString::from_cursor(&mut cursor).as_str() {
            UP => StatusChangeType::Up,
            DOWN => StatusChangeType::Down,
            _ => unreachable!()
        }
    }
}

/// Events related to schema change.
#[derive(Debug, PartialEq)]
pub struct SchemaChange {
    pub change_type: ChangeType,
    pub target: Target,
    pub options: ChangeSchemeOptions
}

impl FromCursor for SchemaChange {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> SchemaChange {
        let change_type = ChangeType::from_cursor(&mut cursor);
        let target = Target::from_cursor(&mut cursor);
        let options = ChangeSchemeOptions::from_cursor_and_target(&mut cursor, &target);

        SchemaChange {
            change_type: change_type,
            target: target,
            options: options
        }
    }
}

/// Represents type of changes.
#[derive(Debug, PartialEq)]
pub enum ChangeType {
    Created,
    Updated,
    Dropped
}

impl FromCursor for ChangeType {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeType {
        match CString::from_cursor(&mut cursor).as_str() {
            CREATED => ChangeType::Created,
            UPDATED => ChangeType::Updated,
            DROPPED => ChangeType::Dropped,
            _ => unreachable!()
        }
    }
}

/// Refers to a target of changes were made.
#[derive(Debug, PartialEq)]
pub enum Target {
    Keyspace,
    Table,
    Type,
    Function,
    Aggregate
}

impl FromCursor for Target {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> Target {
        match CString::from_cursor(&mut cursor).as_str() {
            KEYSPACE => Target::Keyspace,
            TABLE => Target::Table,
            TYPE => Target::Type,
            FUNCTION => Target::Function,
            AGGREGATE => Target::Aggregate,
            _ => unreachable!()
        }
    }
}

/// Option that contains an information about changes were made.
#[derive(Debug, PartialEq)]
pub enum ChangeSchemeOptions {
    /// Changes related to keyspaces. Contains keyspace name.
    Keyspace(String),
    /// Changes related to tables. Contains keyspace and table names.
    Table((String, String)),
    /// Changes related to functions and aggregations. Contains:
    /// * keyspace containing the user defined function / aggregate
    /// * the function/aggregate name
    /// * list of strings, one string for each argument type (as CQL type)
    Function((String, String, Vec<String>))
}

impl ChangeSchemeOptions {
    fn from_cursor_and_target(mut cursor: &mut Cursor<Vec<u8>>, target: &Target)
        -> ChangeSchemeOptions {
        match target {
            &Target::Keyspace => ChangeSchemeOptions::from_cursor_keyspace(&mut cursor),
            &Target::Table | &Target::Type => ChangeSchemeOptions::from_cursor_table(&mut cursor),
            &Target::Function | &Target::Aggregate => ChangeSchemeOptions::from_cursor_function(&mut cursor)
        }
    }

    fn from_cursor_keyspace(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeSchemeOptions {
         ChangeSchemeOptions::Keyspace(CString::from_cursor(&mut cursor).into_plain())
    }

    fn from_cursor_table(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeSchemeOptions {
        let keyspace = CString::from_cursor(&mut cursor).into_plain();
        let name = CString::from_cursor(&mut cursor).into_plain();
        ChangeSchemeOptions::Table((keyspace, name))
    }

    fn from_cursor_function(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeSchemeOptions {
        let keyspace = CString::from_cursor(&mut cursor).into_plain();
        let name = CString::from_cursor(&mut cursor).into_plain();
        let types = CStringList::from_cursor(&mut cursor).into_plain();
        ChangeSchemeOptions::Function((keyspace, name, types))
    }
}

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

    #[test]
    fn as_string() {
        assert_eq!(SimpleServerEvent::TopologyChange.as_string(), "TOPOLOGY_CHANGE".to_string());
        assert_eq!(SimpleServerEvent::StatusChange.as_string(), "STATUS_CHANGE".to_string());
        assert_eq!(SimpleServerEvent::SchemaChange.as_string(), "SCHEMA_CHANGE".to_string());
    }
}

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

    #[test]
    fn from_cursor() {
        let mut new_node: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 8, 78, 69, 87, 95, 78, 79, 68, 69]);
        assert_eq!(TopologyChangeType::from_cursor(&mut new_node),
            TopologyChangeType::NewNode);

        let mut removed_node: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 12, 82, 69, 77, 79, 86, 69, 68, 95, 78, 79, 68, 69]);
        assert_eq!(TopologyChangeType::from_cursor(&mut removed_node),
            TopologyChangeType::RemovedNode);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = TopologyChangeType::from_cursor(&mut wrong);
    }
}

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

    #[test]
    fn from_cursor() {
        let mut up: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 2, 85, 80]);
        assert_eq!(StatusChangeType::from_cursor(&mut up),
            StatusChangeType::Up);

        let mut down: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 4, 68, 79, 87, 78]);
        assert_eq!(StatusChangeType::from_cursor(&mut down),
            StatusChangeType::Down);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = StatusChangeType::from_cursor(&mut wrong);
    }
}

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

    #[test]
    fn from_cursor() {
        let mut created: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 7, 67, 82, 69, 65, 84, 69, 68]);
        assert_eq!(ChangeType::from_cursor(&mut created),
            ChangeType::Created);

        let mut updated: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 7, 85, 80, 68, 65, 84, 69, 68]);
        assert_eq!(ChangeType::from_cursor(&mut updated),
            ChangeType::Updated);

        let mut dropped: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 7, 68, 82, 79, 80, 80, 69, 68]);
        assert_eq!(ChangeType::from_cursor(&mut dropped),
            ChangeType::Dropped);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = ChangeType::from_cursor(&mut wrong);
    }
}
<commit_msg>Create frame/events 2<commit_after>use std::io::Cursor;
use std::cmp::PartialEq;

use FromCursor;
use types::{CString, CStringList, CInet};

// Event types
const TOPOLOGY_CHANGE: &'static str = "TOPOLOGY_CHANGE";
const STATUS_CHANGE: &'static str = "STATUS_CHANGE";
const SCHEMA_CHANGE: &'static str = "SCHEMA_CHANGE";

// Topologe changes
const NEW_NODE: &'static str = "NEW_NODE";
const REMOVED_NODE: &'static str = "REMOVED_NODE";

// Status changes
const UP: &'static str = "UP";
const DOWN: &'static str = "DOWN";

// Schema changes
const CREATED: &'static str = "CREATED";
const UPDATED: &'static str = "UPDATED";
const DROPPED: &'static str = "DROPPED";

// Schema change targets
const KEYSPACE: &'static str = "KEYSPACE";
const TABLE: &'static str = "TABLE";
const TYPE: &'static str = "TYPE";
const FUNCTION: &'static str = "FUNCTION";
const AGGREGATE: &'static str = "AGGREGATE";

/// Simplified `ServerEvent` that does not contain details
/// about a concrete change. It may be useful for subscription
/// when you need only string representation of an event.
#[derive(Debug, PartialEq)]
pub enum SimpleServerEvent {
    TopologyChange,
    StatusChange,
    SchemaChange
}

impl SimpleServerEvent {
    pub fn as_string(&self) -> String {
        match self {
            &SimpleServerEvent::TopologyChange => String::from(TOPOLOGY_CHANGE),
            &SimpleServerEvent::StatusChange => String::from(STATUS_CHANGE),
            &SimpleServerEvent::SchemaChange => String::from(SCHEMA_CHANGE)
        }
    }
}

impl From<ServerEvent> for SimpleServerEvent {
    fn from(event: ServerEvent) -> SimpleServerEvent {
        match event {
            ServerEvent::TopologyChange(_) => SimpleServerEvent::TopologyChange,
            ServerEvent::StatusChange(_) => SimpleServerEvent::TopologyChange,
            ServerEvent::SchemaChange(_) => SimpleServerEvent::TopologyChange,
        }
    }
}

impl<'a> From<&'a ServerEvent> for SimpleServerEvent {
    fn from(event: &'a ServerEvent) -> SimpleServerEvent {
        match event {
            &ServerEvent::TopologyChange(_) => SimpleServerEvent::TopologyChange,
            &ServerEvent::StatusChange(_) => SimpleServerEvent::TopologyChange,
            &ServerEvent::SchemaChange(_) => SimpleServerEvent::TopologyChange,
        }
    }
}

impl PartialEq<ServerEvent> for SimpleServerEvent {
    fn eq(&self, full_event: &ServerEvent) -> bool {
        self == &SimpleServerEvent::from(full_event)
    }
}

/// Full server event that contains all details about a concreate change.
#[derive(Debug)]
pub enum ServerEvent {
    /// Events related to change in the cluster topology
    TopologyChange(TopologyChange),
    /// Events related to change of node status.
    StatusChange(StatusChange),
    /// Events related to schema change.
    SchemaChange(SchemaChange)
}

impl PartialEq<SimpleServerEvent> for ServerEvent {
    fn eq(&self, event: &SimpleServerEvent) -> bool {
        &SimpleServerEvent::from(self) == event
    }
}

impl FromCursor for ServerEvent {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> ServerEvent {
        let event_type = CString::from_cursor(&mut cursor);
        match event_type.as_str() {
            TOPOLOGY_CHANGE => ServerEvent::TopologyChange(
                TopologyChange::from_cursor(&mut cursor)
            ),
            STATUS_CHANGE => ServerEvent::StatusChange(
                StatusChange::from_cursor(&mut cursor)
            ),
            SCHEMA_CHANGE => ServerEvent::SchemaChange(
                SchemaChange::from_cursor(&mut cursor)
            ),
            _ => unreachable!()
        }
    }
}

/// Events related to change in the cluster topology
#[derive(Debug)]
pub struct TopologyChange {
    pub change_type: TopologyChangeType,
    pub addr: CInet
}

impl FromCursor for TopologyChange {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> TopologyChange {
        let change_type = TopologyChangeType::from_cursor(&mut cursor);
        let addr = CInet::from_cursor(&mut cursor);

        TopologyChange {
            change_type: change_type,
            addr: addr
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum TopologyChangeType {
    NewNode,
    RemovedNode
}

impl FromCursor for TopologyChangeType {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> TopologyChangeType {
        match CString::from_cursor(&mut cursor).as_str() {
            NEW_NODE => TopologyChangeType::NewNode,
            REMOVED_NODE => TopologyChangeType::RemovedNode,
            _ => unreachable!()
        }
    }
}

/// Events related to change of node status.
#[derive(Debug)]
pub struct StatusChange {
    pub change_type: StatusChangeType,
    pub addr: CInet
}

impl FromCursor for StatusChange {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> StatusChange {
        let change_type = StatusChangeType::from_cursor(&mut cursor);
        let addr = CInet::from_cursor(&mut cursor);

        StatusChange {
            change_type: change_type,
            addr: addr
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum StatusChangeType {
    Up,
    Down
}

impl FromCursor for StatusChangeType {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> StatusChangeType {
        match CString::from_cursor(&mut cursor).as_str() {
            UP => StatusChangeType::Up,
            DOWN => StatusChangeType::Down,
            _ => unreachable!()
        }
    }
}

/// Events related to schema change.
#[derive(Debug, PartialEq)]
pub struct SchemaChange {
    pub change_type: ChangeType,
    pub target: Target,
    pub options: ChangeSchemeOptions
}

impl FromCursor for SchemaChange {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> SchemaChange {
        let change_type = ChangeType::from_cursor(&mut cursor);
        let target = Target::from_cursor(&mut cursor);
        let options = ChangeSchemeOptions::from_cursor_and_target(&mut cursor, &target);

        SchemaChange {
            change_type: change_type,
            target: target,
            options: options
        }
    }
}

/// Represents type of changes.
#[derive(Debug, PartialEq)]
pub enum ChangeType {
    Created,
    Updated,
    Dropped
}

impl FromCursor for ChangeType {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeType {
        match CString::from_cursor(&mut cursor).as_str() {
            CREATED => ChangeType::Created,
            UPDATED => ChangeType::Updated,
            DROPPED => ChangeType::Dropped,
            _ => unreachable!()
        }
    }
}

/// Refers to a target of changes were made.
#[derive(Debug, PartialEq)]
pub enum Target {
    Keyspace,
    Table,
    Type,
    Function,
    Aggregate
}

impl FromCursor for Target {
    fn from_cursor(mut cursor: &mut Cursor<Vec<u8>>) -> Target {
        match CString::from_cursor(&mut cursor).as_str() {
            KEYSPACE => Target::Keyspace,
            TABLE => Target::Table,
            TYPE => Target::Type,
            FUNCTION => Target::Function,
            AGGREGATE => Target::Aggregate,
            _ => unreachable!()
        }
    }
}

/// Option that contains an information about changes were made.
#[derive(Debug, PartialEq)]
pub enum ChangeSchemeOptions {
    /// Changes related to keyspaces. Contains keyspace name.
    Keyspace(String),
    /// Changes related to tables. Contains keyspace and table names.
    Table((String, String)),
    /// Changes related to functions and aggregations. Contains:
    /// * keyspace containing the user defined function / aggregate
    /// * the function/aggregate name
    /// * list of strings, one string for each argument type (as CQL type)
    Function((String, String, Vec<String>))
}

impl ChangeSchemeOptions {
    fn from_cursor_and_target(mut cursor: &mut Cursor<Vec<u8>>, target: &Target)
        -> ChangeSchemeOptions {
        match target {
            &Target::Keyspace => ChangeSchemeOptions::from_cursor_keyspace(&mut cursor),
            &Target::Table | &Target::Type => ChangeSchemeOptions::from_cursor_table(&mut cursor),
            &Target::Function | &Target::Aggregate => ChangeSchemeOptions::from_cursor_function(&mut cursor)
        }
    }

    fn from_cursor_keyspace(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeSchemeOptions {
         ChangeSchemeOptions::Keyspace(CString::from_cursor(&mut cursor).into_plain())
    }

    fn from_cursor_table(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeSchemeOptions {
        let keyspace = CString::from_cursor(&mut cursor).into_plain();
        let name = CString::from_cursor(&mut cursor).into_plain();
        ChangeSchemeOptions::Table((keyspace, name))
    }

    fn from_cursor_function(mut cursor: &mut Cursor<Vec<u8>>) -> ChangeSchemeOptions {
        let keyspace = CString::from_cursor(&mut cursor).into_plain();
        let name = CString::from_cursor(&mut cursor).into_plain();
        let types = CStringList::from_cursor(&mut cursor).into_plain();
        ChangeSchemeOptions::Function((keyspace, name, types))
    }
}

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

    #[test]
    fn as_string() {
        assert_eq!(SimpleServerEvent::TopologyChange.as_string(), "TOPOLOGY_CHANGE".to_string());
        assert_eq!(SimpleServerEvent::StatusChange.as_string(), "STATUS_CHANGE".to_string());
        assert_eq!(SimpleServerEvent::SchemaChange.as_string(), "SCHEMA_CHANGE".to_string());
    }
}

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

    #[test]
    fn from_cursor() {
        let mut new_node: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 8, 78, 69, 87, 95, 78, 79, 68, 69]);
        assert_eq!(TopologyChangeType::from_cursor(&mut new_node),
            TopologyChangeType::NewNode);

        let mut removed_node: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 12, 82, 69, 77, 79, 86, 69, 68, 95, 78, 79, 68, 69]);
        assert_eq!(TopologyChangeType::from_cursor(&mut removed_node),
            TopologyChangeType::RemovedNode);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = TopologyChangeType::from_cursor(&mut wrong);
    }
}

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

    #[test]
    fn from_cursor() {
        let mut up: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 2, 85, 80]);
        assert_eq!(StatusChangeType::from_cursor(&mut up),
            StatusChangeType::Up);

        let mut down: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 4, 68, 79, 87, 78]);
        assert_eq!(StatusChangeType::from_cursor(&mut down),
            StatusChangeType::Down);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = StatusChangeType::from_cursor(&mut wrong);
    }
}

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

    #[test]
    fn from_cursor() {
        let mut created: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 7, 67, 82, 69, 65, 84, 69, 68]);
        assert_eq!(ChangeType::from_cursor(&mut created),
            ChangeType::Created);

        let mut updated: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 7, 85, 80, 68, 65, 84, 69, 68]);
        assert_eq!(ChangeType::from_cursor(&mut updated),
            ChangeType::Updated);

        let mut dropped: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 7, 68, 82, 79, 80, 80, 69, 68]);
        assert_eq!(ChangeType::from_cursor(&mut dropped),
            ChangeType::Dropped);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = ChangeType::from_cursor(&mut wrong);
    }
}

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

    #[test]
    fn from_cursor() {
        let mut keyspace: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 8, 75, 69, 89, 83, 80, 65, 67, 69]);
        assert_eq!(Target::from_cursor(&mut keyspace),
            Target::Keyspace);

        let mut table: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 5, 84, 65, 66, 76, 69]);
        assert_eq!(Target::from_cursor(&mut table),
            Target::Table);

        let mut _type: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 4, 84, 89, 80, 69]);
        assert_eq!(Target::from_cursor(&mut _type),
            Target::Type);

        let mut function: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 8, 70, 85, 78, 67, 84, 73, 79, 78]);
        assert_eq!(Target::from_cursor(&mut function),
            Target::Function);

        let mut aggregate: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 9, 65, 71, 71, 82, 69, 71, 65, 84, 69]);
        assert_eq!(Target::from_cursor(&mut aggregate),
            Target::Aggregate);
    }

    #[test]
    #[should_panic]
    fn from_cursor_wrong() {
        let mut wrong: Cursor<Vec<u8>> =
            Cursor::new(vec![0, 1, 78]);
        let _ = Target::from_cursor(&mut wrong);
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate serde;
extern crate regex;
extern crate docopt;
extern crate rustc_serialize;
extern crate env_logger;
extern crate ansi_term;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[macro_use]
extern crate sonicd;
extern crate rpassword;
extern crate pbr;

mod util {
    #[cfg(feature = "serde_macros")]
    include!("util.rs.in");

    #[cfg(not(feature = "serde_macros"))]
    include!(concat!(env!("OUT_DIR"), "/util.rs"));
}

use std::path::PathBuf;
use std::process;
use std::io::{Write, stderr, stdout};
use std::cell::RefCell;

use docopt::Docopt;
use pbr::ProgressBar;
use sonicd::SonicMessage;
use rpassword::read_password;

#[cfg_attr(rustfmt, rustfmt_skip)]
const USAGE: &'static str = "
.
                           d8b
                           Y8P

.d8888b   .d88b.  88888b.  888  .d8888b
88K      d88\"\"88b 888 \"88b 888 d88P\"
\"Y8888b. 888  888 888  888 888 888
     X88 Y88..88P 888  888 888 Y88b.
 88888P'  \"Y88P\"  888  888 888  \"Y8888P

Usage:
  sonic <source> [-d <foo=bar>...] [options] -e <query>
  sonic <source> [-d <foo=bar>...] [options] -f <file>
  sonic login [options]
  sonic -h | --help
  sonic -v | --version

Options:
  -e, --execute         Run command literal
  -f, --file            Run command from file
  -c <config>           Use a different configuration file (default: $HOME/.sonicrc)
  -d <foo=bar>          Replace variable in query in the form of `${foo}` with value `var`
  -r, --rows-only       Skip printing column names
  -S, --silent          Skip printing query progress bar
  -V, --verbose         Enable debug logging
  -h, --help            Print this message
  -v, --version         Print version
";

static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static COMMIT: Option<&'static str> = option_env!("SONIC_COMMIT");

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_file: String,
    arg_query: String,
    flag_silent: bool,
    flag_rows_only: bool,
    flag_d: Vec<String>,
    flag_file: bool,
    flag_c: String,
    flag_verbose: bool,
    arg_source: String,
    cmd_login: bool,
    flag_execute: bool,
    flag_version: bool,
    flag_help: bool,
}

error_chain! {
    types {
        Error, ErrorKind, ChainErr, Result;
    }

    links {
        sonicd::Error, sonicd::ErrorKind, SonicdError;
    }

    foreign_links {
        ::std::io::Error, IoError, "I/O operation failed";
        ::serde_json::Error, Json, "JSON serialization/deserialization error";
        ::std::sync::mpsc::RecvError, RecvError, "Channel receive error";
    }

    errors {
        InvalidFormat(co: String, msg: String) {
            description("invalid format error")
                display("invalid format {}: {}", co, msg)
        }
    }
}

fn hide<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = false;
    pb.show_speed = false;
    pb.show_percent = false;
    pb.show_counter = false;
    pb.show_time_left = false;
    pb.show_tick = false;
    pb.show_message = false;
}

fn show<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = true;
    pb.show_speed = false;
    pb.show_percent = true;
    pb.show_counter = true;
    pb.show_time_left = true;
    pb.show_tick = true;
    pb.show_message = true;
}

fn exec(host: &str, port: &u16, query: SonicMessage, rows_only: bool, silent: bool) -> Result<()> {

    let out = RefCell::new(stdout());
    let mut buf: Vec<SonicMessage> = Vec::new();
    let mut pb = ProgressBar::on(stderr(), 0);
    pb.format("╢░░_╟");
    pb.tick_format("▀▐▄▌");
    show(&mut pb);

    let (tx, rx) = ::std::sync::mpsc::channel();

    try!(sonicd::stream((host, *port), query, tx));

    let draw = |b: &mut Vec<SonicMessage>| {
        let len = b.len();
        for msg in b.drain(..len) {
            let cols = match msg {
                SonicMessage::OutputChunk(data) => {
                    data.iter().fold(String::new(), |acc, val| format!("{}{:?}\t", acc, val))
                }
                SonicMessage::TypeMetadata(data) => {
                    data.iter().fold(String::new(), |acc, col| format!("{}{:?}\t", acc, col.0))
                }
                _ => panic!("not possible!"),
            };
            let row = format!("{}\n", cols.trim_right());
            let mut bout = out.borrow_mut();
            bout.write_all(row.as_bytes()).unwrap();
            bout.flush().unwrap();
        }
    };

    let res: Result<()>;

    loop {
        match try!(rx.recv()) {
            Ok(msg @ SonicMessage::TypeMetadata(_)) => {
                if !rows_only {
                    buf.push(msg);
                }
            }
            Ok(msg @ SonicMessage::OutputChunk(_)) => {
                buf.push(msg);
                if !silent && !pb.is_finish {
                    // tick format breaks suffix length
                    // so we need to disable it before finishing bar
                    hide(&mut pb);
                    pb.tick();
                    pb.finish();
                }
                draw(&mut buf);
            }
            Ok(SonicMessage::QueryProgress { status, progress, total, .. }) => {
                if !silent && !pb.is_finish {

                    pb.message(&format!("{:?} ", status));
                    debug!("{:?}: {:?}/{:?}", status, progress, total);

                    if let Some(total) = total {
                        pb.total = total as u64;
                    }

                    if progress >= 1.0 {
                        pb.add(progress as u64);
                    } else {
                        pb.tick();
                    };
                }
            }
            Ok(SonicMessage::Done(None)) => {
                res = Ok(());
                break;
            }
            Ok(SonicMessage::Done(Some(e))) => {
                res = Err(e.into());
                break;
            }
            Err(e) => {
                res = Err(e.into());
                break;
            }
            Ok(a) => debug!("ignoring msg {:?}", a),
        }
    }

    draw(&mut buf);

    res
}

pub fn login(host: &str, tcp_port: &u16) -> Result<()> {

    let user = option_env!("USER").unwrap_or_else(|| "unknown user");

    try!(stdout().write(b"Enter key: "));
    try!(stdout().flush());

    let key = try!(read_password());

    let (tx, rx) = ::std::sync::mpsc::channel();

    let cmd = SonicMessage::Authenticate {
        key: key,
        user: user.to_owned(),
        trace_id: None,
    };

    try!(sonicd::stream((host, *tcp_port), cmd, tx));

    let token: String;

    loop {
        match try!(rx.recv()) {
            Ok(SonicMessage::OutputChunk(data)) => {
                token = try!(util::parse_token(data));
                break;
            }
            Ok(_) => {},
            Err(e) => {
                return Err(e.into())
            }
        };
    }

    let path = util::get_config_path();
    let config = try!(util::read_config(&path));

    let new_config = util::ClientConfig { auth: Some(token), ..config };

    try!(util::write_config(&new_config, &path));

    println!("OK");
    Ok(())
}

fn _main(args: Args) -> Result<()> {

    let Args { arg_file,
               arg_query,
               flag_silent,
               flag_rows_only,
               flag_d,
               flag_file,
               flag_c,
               arg_source,
               cmd_login,
               flag_execute,
               flag_version,
               .. } = args;

    let util::ClientConfig { sonicd, tcp_port, sources, auth } = if flag_c != "" {
        debug!("sourcing passed config in path '{:?}'", &flag_c);
        try!(util::read_config(&PathBuf::from(flag_c)))
    } else {
        debug!("sourcing default config in path '$HOME/.sonicrc'");
        try!(util::get_default_config())
    };

    if flag_file {

        let query_str = try!(util::read_file_contents(&PathBuf::from(&arg_file)));
        let split = try!(util::split_key_value(&flag_d));
        let injected = try!(util::inject_vars(&query_str, &split));
        let query = try!(util::build(arg_source, sources, auth, injected));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if flag_execute {

        let query = try!(util::build(arg_source, sources, auth, arg_query));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if cmd_login {

        login(&sonicd, &tcp_port)

    } else if flag_version {

        println!("Sonic CLI version {} ({})",
                 VERSION,
                 COMMIT.unwrap_or_else(|| "dev"));

        Ok(())

    } else {

        panic!("unexpected args");

    }
}

fn main() {

    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let verbose: bool = args.flag_verbose;

    if verbose {
        let mut builder = env_logger::LogBuilder::new();
        builder.parse("debug");
        builder.init().unwrap();
    } else {
        env_logger::init().unwrap();
    }

    debug!("parsed args {:?}", args);

    match _main(args) {
        Ok(_) => {}
        Err(e) => {
            util::report_error(&e, verbose);
            process::exit(1)
        }
    }
}
<commit_msg>cli: changed auth user from compile time to run time<commit_after>extern crate serde_json;
extern crate serde;
extern crate regex;
extern crate docopt;
extern crate rustc_serialize;
extern crate env_logger;
extern crate ansi_term;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[macro_use]
extern crate sonicd;
extern crate rpassword;
extern crate pbr;

mod util {
    #[cfg(feature = "serde_macros")]
    include!("util.rs.in");

    #[cfg(not(feature = "serde_macros"))]
    include!(concat!(env!("OUT_DIR"), "/util.rs"));
}

use std::path::PathBuf;
use std::process;
use std::io::{Write, stderr, stdout};
use std::cell::RefCell;

use docopt::Docopt;
use pbr::ProgressBar;
use sonicd::SonicMessage;
use rpassword::read_password;

#[cfg_attr(rustfmt, rustfmt_skip)]
const USAGE: &'static str = "
.
                           d8b
                           Y8P

.d8888b   .d88b.  88888b.  888  .d8888b
88K      d88\"\"88b 888 \"88b 888 d88P\"
\"Y8888b. 888  888 888  888 888 888
     X88 Y88..88P 888  888 888 Y88b.
 88888P'  \"Y88P\"  888  888 888  \"Y8888P

Usage:
  sonic <source> [-d <foo=bar>...] [options] -e <query>
  sonic <source> [-d <foo=bar>...] [options] -f <file>
  sonic login [options]
  sonic -h | --help
  sonic --version

Options:
  -e, --execute         Run command literal
  -f, --file            Run command from file
  -c <config>           Use a different configuration file (default: $HOME/.sonicrc)
  -d <foo=bar>          Replace variable in query in the form of `${foo}` with value `var`
  -r, --rows-only       Skip printing column names
  -S, --silent          Skip printing query progress bar
  -v, --verbose         Enable debug logging
  -h, --help            Print this message
  --version             Print version
";

static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static COMMIT: Option<&'static str> = option_env!("SONIC_COMMIT");

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_file: String,
    arg_query: String,
    flag_silent: bool,
    flag_rows_only: bool,
    flag_d: Vec<String>,
    flag_file: bool,
    flag_c: String,
    flag_verbose: bool,
    arg_source: String,
    cmd_login: bool,
    flag_execute: bool,
    flag_version: bool,
    flag_help: bool,
}

error_chain! {
    types {
        Error, ErrorKind, ChainErr, Result;
    }

    links {
        sonicd::Error, sonicd::ErrorKind, SonicdError;
    }

    foreign_links {
        ::std::io::Error, IoError, "I/O operation failed";
        ::serde_json::Error, Json, "JSON serialization/deserialization error";
        ::std::sync::mpsc::RecvError, RecvError, "Channel receive error";
    }

    errors {
        InvalidFormat(co: String, msg: String) {
            description("invalid format error")
                display("invalid format {}: {}", co, msg)
        }
    }
}

fn hide<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = false;
    pb.show_speed = false;
    pb.show_percent = false;
    pb.show_counter = false;
    pb.show_time_left = false;
    pb.show_tick = false;
    pb.show_message = false;
}

fn show<T: Write>(pb: &mut ProgressBar<T>) {
    pb.show_bar = true;
    pb.show_speed = false;
    pb.show_percent = true;
    pb.show_counter = true;
    pb.show_time_left = true;
    pb.show_tick = true;
    pb.show_message = true;
}

fn exec(host: &str, port: &u16, query: SonicMessage, rows_only: bool, silent: bool) -> Result<()> {

    let out = RefCell::new(stdout());
    let mut buf: Vec<SonicMessage> = Vec::new();
    let mut pb = ProgressBar::on(stderr(), 0);
    pb.format("╢░░_╟");
    pb.tick_format("▀▐▄▌");
    show(&mut pb);

    let (tx, rx) = ::std::sync::mpsc::channel();

    try!(sonicd::stream((host, *port), query, tx));

    let draw = |b: &mut Vec<SonicMessage>| {
        let len = b.len();
        for msg in b.drain(..len) {
            let cols = match msg {
                SonicMessage::OutputChunk(data) => {
                    data.iter().fold(String::new(), |acc, val| format!("{}{:?}\t", acc, val))
                }
                SonicMessage::TypeMetadata(data) => {
                    data.iter().fold(String::new(), |acc, col| format!("{}{:?}\t", acc, col.0))
                }
                _ => panic!("not possible!"),
            };
            let row = format!("{}\n", cols.trim_right());
            let mut bout = out.borrow_mut();
            bout.write_all(row.as_bytes()).unwrap();
            bout.flush().unwrap();
        }
    };

    let res: Result<()>;

    loop {
        match try!(rx.recv()) {
            Ok(msg @ SonicMessage::TypeMetadata(_)) => {
                if !rows_only {
                    buf.push(msg);
                }
            }
            Ok(msg @ SonicMessage::OutputChunk(_)) => {
                buf.push(msg);
                if !silent && !pb.is_finish {
                    // tick format breaks suffix length
                    // so we need to disable it before finishing bar
                    hide(&mut pb);
                    pb.tick();
                    pb.finish();
                }
                draw(&mut buf);
            }
            Ok(SonicMessage::QueryProgress { status, progress, total, .. }) => {
                if !silent && !pb.is_finish {

                    pb.message(&format!("{:?} ", status));
                    debug!("{:?}: {:?}/{:?}", status, progress, total);

                    if let Some(total) = total {
                        pb.total = total as u64;
                    }

                    if progress >= 1.0 {
                        pb.add(progress as u64);
                    } else {
                        pb.tick();
                    };
                }
            }
            Ok(SonicMessage::Done(None)) => {
                res = Ok(());
                break;
            }
            Ok(SonicMessage::Done(Some(e))) => {
                res = Err(e.into());
                break;
            }
            Err(e) => {
                res = Err(e.into());
                break;
            }
            Ok(a) => debug!("ignoring msg {:?}", a),
        }
    }

    draw(&mut buf);

    res
}

pub fn login(host: &str, tcp_port: &u16) -> Result<()> {

    let user = std::env::var("USER")
        .unwrap_or("unknown".to_owned());

    try!(stdout().write(b"Enter key: "));
    try!(stdout().flush());

    let key = try!(read_password());

    let (tx, rx) = ::std::sync::mpsc::channel();

    let cmd = SonicMessage::Authenticate {
        key: key,
        user: user.to_owned(),
        trace_id: None,
    };

    try!(sonicd::stream((host, *tcp_port), cmd, tx));

    let token: String;

    loop {
        match try!(rx.recv()) {
            Ok(SonicMessage::OutputChunk(data)) => {
                token = try!(util::parse_token(data));
                break;
            }
            Ok(_) => {},
            Err(e) => {
                return Err(e.into())
            }
        };
    }

    debug!("generated token for user {:?}: {:?}", &user, &token);

    let path = util::get_config_path();
    let config = try!(util::read_config(&path));

    let new_config = util::ClientConfig { auth: Some(token), ..config };

    try!(util::write_config(&new_config, &path));

    println!("OK");
    Ok(())
}

fn _main(args: Args) -> Result<()> {

    let Args { arg_file,
               arg_query,
               flag_silent,
               flag_rows_only,
               flag_d,
               flag_file,
               flag_c,
               arg_source,
               cmd_login,
               flag_execute,
               flag_version,
               .. } = args;

    let util::ClientConfig { sonicd, tcp_port, sources, auth } = if flag_c != "" {
        debug!("sourcing passed config in path '{:?}'", &flag_c);
        try!(util::read_config(&PathBuf::from(flag_c)))
    } else {
        debug!("sourcing default config in path '$HOME/.sonicrc'");
        try!(util::get_default_config())
    };

    if flag_file {

        let query_str = try!(util::read_file_contents(&PathBuf::from(&arg_file)));
        let split = try!(util::split_key_value(&flag_d));
        let injected = try!(util::inject_vars(&query_str, &split));
        let query = try!(util::build(arg_source, sources, auth, injected));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if flag_execute {

        let query = try!(util::build(arg_source, sources, auth, arg_query));

        exec(&sonicd, &tcp_port, query, flag_rows_only, flag_silent)

    } else if cmd_login {

        login(&sonicd, &tcp_port)

    } else if flag_version {

        println!("Sonic CLI version {} ({})",
                 VERSION,
                 COMMIT.unwrap_or_else(|| "dev"));

        Ok(())

    } else {

        panic!("unexpected args");

    }
}

fn main() {

    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let verbose: bool = args.flag_verbose;

    if verbose {
        let mut builder = env_logger::LogBuilder::new();
        builder.parse("debug");
        builder.init().unwrap();
    } else {
        env_logger::init().unwrap();
    }

    debug!("parsed args {:?}", args);

    match _main(args) {
        Ok(_) => {}
        Err(e) => {
            util::report_error(&e, verbose);
            process::exit(1)
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
mod basic_test;
#[ cfg( any( feature = "derive_clone_dyn" ) ) ]
mod clone_dyn_test;
<commit_msg>Fix tests of module `derive_tools`, test with valid features<commit_after>use super::*;
mod basic_test;
#[ cfg( any( feature = "derive_clone_dyn_use_std", feature = "derive_clone_dyn_use_alloc" ) ) ]
mod clone_dyn_test;
<|endoftext|>


<commit_before>fraptor ICON "misc/icons/Factor.ico"

<commit_msg>vm: change id of windows app icon resource to more standard "APPICON"<commit_after>APPICON ICON "misc/icons/Factor.ico"

<|endoftext|>


<commit_before>//! Random number generation

export rng, seed, seeded_rng, weighted, extensions;
export xorshift, seeded_xorshift;

enum rctx {}

#[abi = "cdecl"]
extern mod rustrt {
    fn rand_seed() -> ~[u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: ~[u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/// A random number generator
iface rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl extensions for rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * Return an int randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * Return a uint randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * Return a char randomly chosen from chars, failing if chars is empty
     */
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// Return a bool with a 1 in n chance of true
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    /**
     * Return a random string of the specified length composed of A-Z,a-z,0-9
     */
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    /// Return a random byte string of the specified length
    fn gen_bytes(len: uint) -> ~[u8] {
        do vec::from_fn(len) |_i| {
            self.gen_u8()
        }
    }

    /// Choose an item randomly, failing if values is empty
    fn choose<T:copy>(values: ~[T]) -> T {
        self.choose_option(values).get()
    }

    /// Choose some(item) randomly, returning none if values is empty
    fn choose_option<T:copy>(values: ~[T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    /**
     * Choose an item respecting the relative weights, failing if the sum of
     * the weights is 0
     */
    fn choose_weighted<T: copy>(v : ~[weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    /**
     * Choose some(item) respecting the relative weights, returning none if
     * the sum of the weights is 0
     */
    fn choose_weighted_option<T:copy>(v: ~[weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each |item| {
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    /**
     * Return a vec containing copies of the items, in order, where
     * the weight of the item determines how many copies there are
     */
    fn weighted_vec<T:copy>(v: ~[weighted<T>]) -> ~[T] {
        let mut r = ~[];
        for v.each |item| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: ~[T]) -> ~[T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    /// Shuffle a mutable vec in place
    fn shuffle_mut<T>(&&values: ~[mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

class rand_res {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

/**
 * Create a random number generator using the specified seed. A generator
 * constructed with a given seed will generate the same sequence of values as
 * all other generators constructed with the same seed. The seed may be any
 * length.
 */
fn seeded_rng(seed: ~[u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

type xorshift_state = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl of rng for xorshift_state {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        #error("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose(~[1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option(~[]) == none::<int>;
        assert r.choose_option(~[1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
               some(42);
        assert r.choose_weighted_option(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option(~[]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.weighted_vec(~[]) == empty;
        assert r.weighted_vec(~[
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == ~[2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.shuffle(~[]) == empty;
        assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Move string append to libraries. Closes #2710.<commit_after>//! Random number generation

export rng, seed, seeded_rng, weighted, extensions;
export xorshift, seeded_xorshift;

enum rctx {}

#[abi = "cdecl"]
extern mod rustrt {
    fn rand_seed() -> ~[u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: ~[u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/// A random number generator
iface rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl extensions for rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * Return an int randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * Return a uint randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * Return a char randomly chosen from chars, failing if chars is empty
     */
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// Return a bool with a 1 in n chance of true
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    /**
     * Return a random string of the specified length composed of A-Z,a-z,0-9
     */
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                       abcdefghijklmnopqrstuvwxyz\
                       0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    /// Return a random byte string of the specified length
    fn gen_bytes(len: uint) -> ~[u8] {
        do vec::from_fn(len) |_i| {
            self.gen_u8()
        }
    }

    /// Choose an item randomly, failing if values is empty
    fn choose<T:copy>(values: ~[T]) -> T {
        self.choose_option(values).get()
    }

    /// Choose some(item) randomly, returning none if values is empty
    fn choose_option<T:copy>(values: ~[T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    /**
     * Choose an item respecting the relative weights, failing if the sum of
     * the weights is 0
     */
    fn choose_weighted<T: copy>(v : ~[weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    /**
     * Choose some(item) respecting the relative weights, returning none if
     * the sum of the weights is 0
     */
    fn choose_weighted_option<T:copy>(v: ~[weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each |item| {
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    /**
     * Return a vec containing copies of the items, in order, where
     * the weight of the item determines how many copies there are
     */
    fn weighted_vec<T:copy>(v: ~[weighted<T>]) -> ~[T] {
        let mut r = ~[];
        for v.each |item| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: ~[T]) -> ~[T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    /// Shuffle a mutable vec in place
    fn shuffle_mut<T>(&&values: ~[mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

class rand_res {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

/**
 * Create a random number generator using the specified seed. A generator
 * constructed with a given seed will generate the same sequence of values as
 * all other generators constructed with the same seed. The seed may be any
 * length.
 */
fn seeded_rng(seed: ~[u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

type xorshift_state = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl of rng for xorshift_state {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        #error("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose(~[1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option(~[]) == none::<int>;
        assert r.choose_option(~[1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
               some(42);
        assert r.choose_weighted_option(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option(~[]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.weighted_vec(~[]) == empty;
        assert r.weighted_vec(~[
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == ~[2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.shuffle(~[]) == empty;
        assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>#[doc = "Random number generation"];

export rng;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_new() -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;

    #[doc = "Return the next random float"]
    fn next_float() -> float;

    #[doc = "Return a random string composed of A-Z, a-z, 0-9."]
    fn gen_str(len: uint) -> str;

    #[doc = "Return a random byte string."]
    fn gen_bytes(len: uint) -> [u8];
}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

#[doc = "Create a random number generator"]
fn rng() -> rng {
    impl of rng for @rand_res {
        fn next() -> u32 { ret rustrt::rand_next(**self); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**self) as float;
          let u2 = rustrt::rand_next(**self) as float;
          let u3 = rustrt::rand_next(**self) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let mut s = "";
            let mut i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**self) as uint %
                    str::len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let mut v = [];
            let mut i = 0u;
            while i < len {
                let n = rustrt::rand_next(**self) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    @rand_res(rustrt::rand_new()) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {
        let r1: rand::rng = rand::rng();
        log(debug, r1.next());
        log(debug, r1.next());
        {
            let r2 = rand::rng();
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r2.next());
        }
        log(debug, r1.next());
        log(debug, r1.next());
    }

    #[test]
    fn genstr() {
        let r: rand::rng = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert(str::len(r.gen_str(10u)) == 10u);
        assert(str::len(r.gen_str(16u)) == 16u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>separate the rand::rng gen_* methods out into an iface-less-impl so that the gen_* methods can be reused with different rng implementations (for https://github.com/mozilla/rust/issues/2379)<commit_after>#[doc = "Random number generation"];

export rng, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_new() -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random float"]
    fn gen_float() -> float {
          let u1 = self.next() as float;
          let u2 = self.next() as float;
          let u3 = self.next() as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random string composed of A-Z, a-z, 0-9."]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            let n = self.next() as uint % charset.len();
            s = s + str::from_char(str::char_at(charset, n));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string."]
    fn gen_bytes(len: uint) -> [u8] {
        let mut v = [];
        let mut i = 0u;
        while i < len {
            let n = self.next() as uint;
            v += [(n % (u8::max_value as uint)) as u8];
            i += 1u;
        }
        v
    }
}

#[doc = "Create a random number generator"]
fn rng() -> rng {
    resource rand_res(c: *rctx) { rustrt::rand_free(c); }

    impl of rng for @rand_res {
        fn next() -> u32 { ret rustrt::rand_next(**self); }
    }

    @rand_res(rustrt::rand_new()) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {
        let r1 = rand::rng();
        log(debug, r1.next());
        log(debug, r1.next());
        {
            let r2 = rand::rng();
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r2.next());
        }
        log(debug, r1.next());
        log(debug, r1.next());
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before><commit_msg>length.rs: Be more explicit about what we match for default units<commit_after><|endoftext|>


<commit_before>pub fn configure(_: &mut WindowManager, _: &WindowSystem, config: &mut Config) {
    let modm = MOD1MASK;

    config.border_color = 0x7e9014;
    config.focus_border_color = 0xafc81c;
    //config.focus_border_color = 0xaf0000;
    config.terminal = (String::from_str("xfce4-terminal"), String::from_str(""));

    // Register key handlers
    config.add_key_handler(String::from_str("q"), modm | SHIFTMASK,
            box |&: m, w, c| restart(m, w, c));
    config.add_key_handler(String::from_str("Return"), modm | SHIFTMASK,
            box |&: m, w, c| start_terminal(m, w, c));
    config.add_key_handler(String::from_str("p"), modm,
            box |&: m, w, c| start_launcher(m, w, c));

    config.add_key_handler(String::from_str("j"), modm,
            box |&: m: WindowManager, w: &WindowSystem, c: &Config| {
                m.windows(w, c, |x| x.focus_down())
            });

    config.add_key_handler(String::from_str("k"), modm,
            box |&: m: WindowManager, w: &WindowSystem, c: &Config| {
                m.windows(w, c, |x| x.focus_up())
            });

    for i in range(1u, 10) {
        config.add_key_handler(i.to_string(), modm,
            box move |&: m, w, c| switch_to_workspace(m, w, c, i - 1));

        config.add_key_handler(i.to_string(), modm | SHIFTMASK,
            box move |&: m, w, c| move_window_to_workspace(m, w, c, i - 1));
    }
}
<commit_msg>corrected direction of mod+(j,k) and tested that this finally closes Kintaro/wtftw#6<commit_after>pub fn configure(_: &mut WindowManager, _: &WindowSystem, config: &mut Config) {
    let modm = MOD1MASK;

    config.border_color = 0x7e9014;
    config.focus_border_color = 0xafc81c;
    //config.focus_border_color = 0xaf0000;
    config.terminal = (String::from_str("xfce4-terminal"), String::from_str(""));

    // Register key handlers
    config.add_key_handler(String::from_str("q"), modm | SHIFTMASK,
            box |&: m, w, c| restart(m, w, c));
    config.add_key_handler(String::from_str("Return"), modm | SHIFTMASK,
            box |&: m, w, c| start_terminal(m, w, c));
    config.add_key_handler(String::from_str("p"), modm,
            box |&: m, w, c| start_launcher(m, w, c));

    config.add_key_handler(String::from_str("k"), modm,
            box |&: m: WindowManager, w: &WindowSystem, c: &Config| {
                m.windows(w, c, |x| x.focus_down())
            });

    config.add_key_handler(String::from_str("j"), modm,
            box |&: m: WindowManager, w: &WindowSystem, c: &Config| {
                m.windows(w, c, |x| x.focus_up())
            });

    for i in range(1u, 10) {
        config.add_key_handler(i.to_string(), modm,
            box move |&: m, w, c| switch_to_workspace(m, w, c, i - 1));

        config.add_key_handler(i.to_string(), modm | SHIFTMASK,
            box move |&: m, w, c| move_window_to_workspace(m, w, c, i - 1));
    }
}
<|endoftext|>


<commit_before>use std::{iter,str};
use std::fmt::Debug;

pub type Key = Vec<u8>;
pub type KeyValue<K,V> = (K,V);

const BRANCH_FACTOR: usize = 4;

#[derive(Debug,PartialEq)]
pub struct TrieNode<V> {
  partial_key: Key,
  key_value:   Option<KeyValue<Key,V>>,
  children:    Vec<TrieNode<V>>,
}

#[derive(Debug,PartialEq)]
pub enum InsertResult {
  Ok,
  Existing,
  Failed
}

#[derive(Debug,PartialEq)]
pub enum RemoveResult {
  Ok,
  NotFound,
}

impl<V:Clone+Debug> TrieNode<V> {
  pub fn new(partial: &[u8], key: Key, value: V) -> TrieNode<V> {
    TrieNode {
      partial_key:    Vec::from(partial),
      key_value:      Some((key, value)),
      children:       vec!(),
    }
  }

  pub fn root() -> TrieNode<V> {
    TrieNode {
      partial_key:    vec!(),
      key_value:      None,
      children:       vec!(),
    }
  }

  pub fn split(&mut self, index:usize) {
    let key_value = self.key_value.take();
    let children  = self.children.drain(..).collect();

    let child = TrieNode {
      partial_key: (&self.partial_key[index..]).to_vec(),
      key_value:   key_value,
      children:    children,
    };

    self.children.push(child);
    self.partial_key = (&self.partial_key[..index]).to_vec();
  }

  pub fn insert(&mut self, key: Key, value: V) -> InsertResult {
    let res = self.insert_recursive(&key, &key, &value);
    assert_ne!(res, InsertResult::Failed);
    res
  }

  pub fn insert_recursive(&mut self, partial_key: &[u8], key: &Key, value: &V) -> InsertResult {
    assert_ne!(partial_key, &b""[..]);

    let pos = partial_key.iter().zip(self.partial_key.iter()).position(|(&a,&b)| a != b);

    match pos {
      Some(0) => InsertResult::Failed,
      Some(index) => {
        self.split(index);
        let new_child = TrieNode {
          partial_key: (&partial_key[index..]).to_vec(),
          key_value:   Some((key.clone(), value.clone())),
          children:    vec!(),
        };

        self.children.push(new_child);
        InsertResult::Ok
      },
      None    => {
        // we consumed the whole local partial key
        if partial_key.len() > self.partial_key.len() {
          for child in self.children.iter_mut() {
            match child.insert_recursive(&partial_key[self.partial_key.len()..], key, value) {
              InsertResult::Ok       => return InsertResult::Ok,
              InsertResult::Existing => return InsertResult::Existing,
              _ => {}
            }
          }

          // we could not insert in children
          let new_child = TrieNode {
            partial_key: (&partial_key[self.partial_key.len()..]).to_vec(),
            key_value:   Some((key.clone(), value.clone())),
            children:    vec!(),
          };

          self.children.push(new_child);
          InsertResult::Ok
        } else {
          // the partial key is the same as ours
          if self.key_value.is_some() {
            InsertResult::Existing
          } else {
            self.key_value = Some((key.clone(), value.clone()));
            InsertResult::Ok
          }
        }
      }
    }
  }

  pub fn remove(&mut self, key: &Key) -> RemoveResult {
    self.remove_recursive(key)
  }

  pub fn remove_recursive(&mut self, partial_key: &[u8]) -> RemoveResult {
    assert_ne!(partial_key, &b""[..]);
    let mut found_child:Option<usize> = None;

    // checking directly the children
    for (index, child) in self.children.iter_mut().enumerate() {

      let pos = partial_key.iter().zip(child.partial_key.iter()).position(|(&a,&b)| a != b);
      match pos {
        Some(i) => continue,
        None    => {
          if partial_key.len() > child.partial_key.len()  {
            let i = child.partial_key.len();
            return child.remove_recursive(&partial_key[i..]);
          } else if partial_key.len() == child.partial_key.len() {
            found_child = Some(index);
            break;
          } else {
            continue
          }
        }
      };
    }

    if let Some(index ) = found_child {
      self.children.remove(index);
      if self.key_value.is_some() {
        return RemoveResult::Ok;
      } else {
        //merging with the child
        if self.children.len() == 1 {
          let mut ch     = self.children.remove(0);
          self.key_value = ch.key_value.take();
          self.children  = ch.children;
          self.partial_key.extend(ch.partial_key);
        }
        // not handling the case of empty children vec
        // this case should only happen if it is the root node
        // otherwise, when we get to one last node and there is
        // no key_value, it is merged with the child node
        return RemoveResult::Ok
      }
    } else {
      RemoveResult::NotFound
    }
  }

  pub fn lookup(&self, partial_key: &[u8]) -> Option<&KeyValue<Key,V>> {
    assert_ne!(partial_key, &b""[..]);

    if partial_key.starts_with(&self.partial_key) {
      if partial_key.len() == self.partial_key.len() {
        return self.key_value.as_ref();
      } else {
        for child in self.children.iter() {
          let res = child.lookup(&partial_key[self.partial_key.len()..]);
          if res.is_some() {
            return res
          }
        }
        None
      }
    } else {
      None
    }
  }

  // specific version that will handle wildcard domains
  pub fn domain_lookup(&self, key: Key) -> Option<KeyValue<Key,V>> {
    None
  }

  pub fn print(&self) {
    self.print_recursive(0)
  }

  pub fn print_recursive(&self, indent:u8) {
    let raw_prefix:Vec<u8> = iter::repeat(' ' as u8).take(indent as usize).collect();
    let prefix = str::from_utf8(&raw_prefix).unwrap();

    if let Some((ref key, ref value)) = self.key_value {
    println!("{}{}: ({},{:?})", prefix, str::from_utf8(&self.partial_key).unwrap(),
      str::from_utf8(&key).unwrap(), value);
    } else {
    println!("{}{}: None", prefix, str::from_utf8(&self.partial_key).unwrap());
    }
    for child in self.children.iter() {
      child.print_recursive(indent+1);
    }
  }
}

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

  #[test]
  fn insert() {
    let mut root: TrieNode<u8> = TrieNode::root();
    root.print();

    assert_eq!(root.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    root.print();
    assert_eq!(root.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);
    root.print();
    assert_eq!(root.insert(Vec::from(&b"abgh"[..]), 3), InsertResult::Ok);
    root.print();

    assert_eq!(root.lookup(&b"abce"[..]), Some(&((&b"abce"[..]).to_vec(), 2)));
    //assert!(false);
  }

  #[test]
  fn remove() {
    let mut root: TrieNode<u8> = TrieNode::root();

    assert_eq!(root.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(root.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);
    assert_eq!(root.insert(Vec::from(&b"abgh"[..]), 3), InsertResult::Ok);

    let mut root2: TrieNode<u8> = TrieNode::root();

    assert_eq!(root2.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(root2.insert(Vec::from(&b"abgh"[..]), 3), InsertResult::Ok);

    println!("before remove");
    root.print();
    assert_eq!(root.remove(&Vec::from(&b"abce"[..])), RemoveResult::Ok);
    println!("after remove");
    root.print();
    println!("expected");
    root2.print();
    assert_eq!(root, root2);

    assert_eq!(root.remove(&Vec::from(&b"abgh"[..])), RemoveResult::Ok);
    println!("after remove");
    root.print();
    println!("expected");
    let mut root3: TrieNode<u8> = TrieNode::root();
    assert_eq!(root3.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    root3.print();
    assert_eq!(root, root3);

    assert!(false);
  }
}
<commit_msg>Handle domain lookup in the tree<commit_after>use std::{iter,str};
use std::fmt::Debug;

pub type Key = Vec<u8>;
pub type KeyValue<K,V> = (K,V);

const BRANCH_FACTOR: usize = 4;

#[derive(Debug,PartialEq)]
pub struct TrieNode<V> {
  partial_key: Key,
  key_value:   Option<KeyValue<Key,V>>,
  children:    Vec<TrieNode<V>>,
}

#[derive(Debug,PartialEq)]
pub enum InsertResult {
  Ok,
  Existing,
  Failed
}

#[derive(Debug,PartialEq)]
pub enum RemoveResult {
  Ok,
  NotFound,
}

impl<V:Clone+Debug> TrieNode<V> {
  pub fn new(partial: &[u8], key: Key, value: V) -> TrieNode<V> {
    TrieNode {
      partial_key:    Vec::from(partial),
      key_value:      Some((key, value)),
      children:       vec!(),
    }
  }

  pub fn root() -> TrieNode<V> {
    TrieNode {
      partial_key:    vec!(),
      key_value:      None,
      children:       vec!(),
    }
  }

  pub fn split(&mut self, index:usize) {
    let key_value = self.key_value.take();
    let children  = self.children.drain(..).collect();

    let child = TrieNode {
      partial_key: (&self.partial_key[index..]).to_vec(),
      key_value:   key_value,
      children:    children,
    };

    self.children.push(child);
    self.partial_key = (&self.partial_key[..index]).to_vec();
  }

  pub fn insert(&mut self, key: Key, value: V) -> InsertResult {
    let res = self.insert_recursive(&key, &key, &value);
    assert_ne!(res, InsertResult::Failed);
    res
  }

  pub fn insert_recursive(&mut self, partial_key: &[u8], key: &Key, value: &V) -> InsertResult {
    assert_ne!(partial_key, &b""[..]);

    let pos = partial_key.iter().zip(self.partial_key.iter()).position(|(&a,&b)| a != b);

    match pos {
      Some(0) => InsertResult::Failed,
      Some(index) => {
        self.split(index);
        let new_child = TrieNode {
          partial_key: (&partial_key[index..]).to_vec(),
          key_value:   Some((key.clone(), value.clone())),
          children:    vec!(),
        };

        self.children.push(new_child);
        InsertResult::Ok
      },
      None    => {
        // we consumed the whole local partial key
        if partial_key.len() > self.partial_key.len() {
          for child in self.children.iter_mut() {
            match child.insert_recursive(&partial_key[self.partial_key.len()..], key, value) {
              InsertResult::Ok       => return InsertResult::Ok,
              InsertResult::Existing => return InsertResult::Existing,
              _ => {}
            }
          }

          // we could not insert in children
          let new_child = TrieNode {
            partial_key: (&partial_key[self.partial_key.len()..]).to_vec(),
            key_value:   Some((key.clone(), value.clone())),
            children:    vec!(),
          };

          self.children.push(new_child);
          InsertResult::Ok
        } else if partial_key.len() == self.partial_key.len() {
          // the partial key is the same as ours
          if self.key_value.is_some() {
            InsertResult::Existing
          } else {
            self.key_value = Some((key.clone(), value.clone()));
            InsertResult::Ok
          }
        } else {
          // self.partial_key is larger
          self.split(partial_key.len());
          let new_child = TrieNode {
            partial_key: (self.partial_key[partial_key.len()..]).to_vec(),
            key_value:   self.key_value.take(),
            children:    vec!(),
          };

          self.children.push(new_child);
          self.partial_key = partial_key.to_vec();
          self.key_value = Some((key.clone(), value.clone()));
          InsertResult::Ok
        }
      }
    }
  }

  pub fn remove(&mut self, key: &Key) -> RemoveResult {
    self.remove_recursive(key)
  }

  pub fn remove_recursive(&mut self, partial_key: &[u8]) -> RemoveResult {
    assert_ne!(partial_key, &b""[..]);
    let mut found_child:Option<usize> = None;

    // checking directly the children
    for (index, child) in self.children.iter_mut().enumerate() {

      let pos = partial_key.iter().zip(child.partial_key.iter()).position(|(&a,&b)| a != b);
      match pos {
        Some(i) => continue,
        None    => {
          if partial_key.len() > child.partial_key.len()  {
            let i = child.partial_key.len();
            return child.remove_recursive(&partial_key[i..]);
          } else if partial_key.len() == child.partial_key.len() {
            found_child = Some(index);
            break;
          } else {
            continue
          }
        }
      };
    }

    if let Some(index) = found_child {
      if self.children[index].children.len() > 0 && self.children[index].key_value.is_some() {
        self.children[index].key_value = None;
        return RemoveResult::Ok;
      } else {
        self.children.remove(index);
        if self.key_value.is_some() {
          return RemoveResult::Ok;
        } else {
          //merging with the child
          if self.children.len() == 1 {
            let mut ch     = self.children.remove(0);
            self.key_value = ch.key_value.take();
            self.children  = ch.children;
            self.partial_key.extend(ch.partial_key);
          }
          // not handling the case of empty children vec
          // this case should only happen if it is the root node
          // otherwise, when we get to one last node and there is
          // no key_value, it is merged with the child node
          return RemoveResult::Ok
        }
      }
    } else {
      RemoveResult::NotFound
    }
  }

  pub fn lookup(&self, partial_key: &[u8]) -> Option<&KeyValue<Key,V>> {
    assert_ne!(partial_key, &b""[..]);

    if partial_key.starts_with(&self.partial_key) {
      if partial_key.len() == self.partial_key.len() {
        return self.key_value.as_ref();
      } else {
        for child in self.children.iter() {
          let res = child.lookup(&partial_key[self.partial_key.len()..]);
          if res.is_some() {
            return res
          }
        }
        None
      }
    } else {
      None
    }
  }

  // specific version that will handle wildcard domains
  pub fn domain_insert(&mut self, key: Key, value: V) -> InsertResult {
    let mut partial_key = key.clone();
    partial_key.reverse();
    self.insert_recursive(&partial_key, &key, &value)
  }

  // specific version that will handle wildcard domains
  pub fn domain_remove(&mut self, key: &Key) -> RemoveResult {
    let mut partial_key = key.clone();
    partial_key.reverse();
    self.remove_recursive(&partial_key)
  }

  // specific version that will handle wildcard domains
  pub fn domain_lookup(&self, key: &[u8]) -> Option<&KeyValue<Key,V>> {
    let mut partial_key = key.to_vec();
    partial_key.reverse();
    self.domain_lookup_recursive(&partial_key)
  }

  // specific version that will handle wildcard domains
  pub fn domain_lookup_recursive(&self, partial_key: &[u8]) -> Option<&KeyValue<Key,V>> {
    assert_ne!(partial_key, &b""[..]);
    let pos = partial_key.iter().zip(self.partial_key.iter()).position(|(&a,&b)| a != b);

    match pos {
      Some(0) => return None,
      Some(i) => {
        // check for wildcard
        if i+1 == self.partial_key.len() && self.partial_key[i] == '*' as u8 {
          let c = '.' as u8;
          if (&partial_key[i..]).contains(&c) {
            None
          } else {
            self.key_value.as_ref()
          }
        } else {
          None
        }
      },
      None    => {
        if partial_key.len() > self.partial_key.len() {
          for child in self.children.iter() {
            let res = child.domain_lookup_recursive(&partial_key[self.partial_key.len()..]);
            if res.is_some() {
              return res
            }
          }
          None
        } else if partial_key.len() == self.partial_key.len() {
          self.key_value.as_ref()
        } else {
          None
        }

      }
    }
  }

  pub fn print(&self) {
    self.print_recursive(0)
  }

  pub fn print_recursive(&self, indent:u8) {
    let raw_prefix:Vec<u8> = iter::repeat(' ' as u8).take(2*indent as usize).collect();
    let prefix = str::from_utf8(&raw_prefix).unwrap();

    if let Some((ref key, ref value)) = self.key_value {
    println!("{}{}: ({},{:?})", prefix, str::from_utf8(&self.partial_key).unwrap(),
      str::from_utf8(&key).unwrap(), value);
    } else {
    println!("{}{}: None", prefix, str::from_utf8(&self.partial_key).unwrap());
    }
    for child in self.children.iter() {
      child.print_recursive(indent+1);
    }
  }
}

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

  #[test]
  fn insert() {
    let mut root: TrieNode<u8> = TrieNode::root();
    root.print();

    assert_eq!(root.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    root.print();
    assert_eq!(root.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);
    root.print();
    assert_eq!(root.insert(Vec::from(&b"abgh"[..]), 3), InsertResult::Ok);
    root.print();

    assert_eq!(root.lookup(&b"abce"[..]), Some(&((&b"abce"[..]).to_vec(), 2)));
    //assert!(false);
  }

  #[test]
  fn remove() {
    let mut root: TrieNode<u8> = TrieNode::root();

    assert_eq!(root.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(root.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);
    assert_eq!(root.insert(Vec::from(&b"abgh"[..]), 3), InsertResult::Ok);

    let mut root2: TrieNode<u8> = TrieNode::root();

    assert_eq!(root2.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(root2.insert(Vec::from(&b"abgh"[..]), 3), InsertResult::Ok);

    println!("before remove");
    root.print();
    assert_eq!(root.remove(&Vec::from(&b"abce"[..])), RemoveResult::Ok);
    println!("after remove");
    root.print();
    println!("expected");
    root2.print();
    assert_eq!(root, root2);

    assert_eq!(root.remove(&Vec::from(&b"abgh"[..])), RemoveResult::Ok);
    println!("after remove");
    root.print();
    println!("expected");
    let mut root3: TrieNode<u8> = TrieNode::root();
    assert_eq!(root3.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    root3.print();
    assert_eq!(root, root3);
  }

  #[test]
  fn add_child_to_leaf() {
    let mut root: TrieNode<u8> = TrieNode::root();

    assert_eq!(root.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(root.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);
    assert_eq!(root.insert(Vec::from(&b"abc"[..]), 3), InsertResult::Ok);

    root.print();

    let mut root2: TrieNode<u8> = TrieNode::root();

    assert_eq!(root2.insert(Vec::from(&b"abc"[..]), 3), InsertResult::Ok);
    assert_eq!(root2.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(root2.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);

    root2.print();
    assert_eq!(root2.remove(&Vec::from(&b"abc"[..])), RemoveResult::Ok);

    let mut expected: TrieNode<u8> = TrieNode::root();

    assert_eq!(expected.insert(Vec::from(&b"abcd"[..]), 1), InsertResult::Ok);
    assert_eq!(expected.insert(Vec::from(&b"abce"[..]), 2), InsertResult::Ok);

    println!("after remove");
    root2.print();
    println!("expected");
    expected.print();
    assert_eq!(root2, expected);

  }

  #[test]
  fn domains() {
    let mut root: TrieNode<u8> = TrieNode::root();

    assert_eq!(root.domain_insert(Vec::from(&b"www.example.com"[..]), 1), InsertResult::Ok);
    root.print();
    assert_eq!(root.domain_insert(Vec::from(&b"test.example.com"[..]), 2), InsertResult::Ok);
    root.print();
    assert_eq!(root.domain_insert(Vec::from(&b"*.alldomains.org"[..]), 3), InsertResult::Ok);
    root.print();
    assert_eq!(root.domain_insert(Vec::from(&b"alldomains.org"[..]), 4), InsertResult::Ok);
    root.print();
    assert_eq!(root.domain_insert(Vec::from(&b"hello.com"[..]), 5), InsertResult::Ok);
    root.print();

    assert_eq!(root.domain_lookup(&b"example.com"[..]), None);
    assert_eq!(root.domain_lookup(&b"blah.test.example.com"[..]), None);
    assert_eq!(root.domain_lookup(&b"www.example.com"[..]), Some(&((&b"www.example.com"[..]).to_vec(), 1)));
    assert_eq!(root.domain_lookup(&b"alldomains.org"[..]), Some(&((&b"alldomains.org"[..]).to_vec(), 4)));
    assert_eq!(root.domain_lookup(&b"test.alldomains.org"[..]), Some(&((&b"*.alldomains.org"[..]).to_vec(), 3)));
    assert_eq!(root.domain_lookup(&b"hello.alldomains.org"[..]), Some(&((&b"*.alldomains.org"[..]).to_vec(), 3)));
    assert_eq!(root.domain_lookup(&b"blah.test.alldomains.org"[..]), None);

    assert_eq!(root.domain_remove(&Vec::from(&b"alldomains.org"[..])), RemoveResult::Ok);
    println!("after remove");
    root.print();
    assert_eq!(root.domain_lookup(&b"alldomains.org"[..]), None);
    assert_eq!(root.domain_lookup(&b"test.alldomains.org"[..]), Some(&((&b"*.alldomains.org"[..]).to_vec(), 3)));
    assert_eq!(root.domain_lookup(&b"hello.alldomains.org"[..]), Some(&((&b"*.alldomains.org"[..]).to_vec(), 3)));
    assert_eq!(root.domain_lookup(&b"blah.test.alldomains.org"[..]), None);
  }
}
<|endoftext|>