<commit_before>use std::time::{Duration, UNIX_EPOCH};

use assign::assign;
use matches::assert_matches;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events::{
    key::verification::VerificationMethod, room::message::KeyVerificationRequestEventContent,
};
use ruma_events::{
    room::{
        message::{
            AudioMessageEventContent, CustomEventContent, MessageEvent, MessageEventContent,
            MessageType, Relation, TextMessageEventContent,
        },
        relationships::InReplyTo,
    },
    Unsigned,
};
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::DeviceIdBox;
use ruma_identifiers::{event_id, mxc_uri, room_id, user_id};
use ruma_serde::Raw;
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

macro_rules! json_object {
    ( $($key:expr => $value:expr),* $(,)? ) => {
        {
            let mut _map = serde_json::Map::<String, serde_json::Value>::new();
            $(
                let _ = _map.insert($key, $value);
            )*
            _map
        }
    };
}

#[test]
fn serialization() {
    let ev = MessageEvent {
        content: MessageEventContent::new(MessageType::Audio(AudioMessageEventContent {
            body: "test".into(),
            info: None,
            url: Some(mxc_uri!("mxc://example.org/ffed755USFFxlgbQYZGtryd")),
            file: None,
        })),
        event_id: event_id!("$143273582443PhrSn:example.org"),
        origin_server_ts: UNIX_EPOCH + Duration::from_millis(10_000),
        room_id: room_id!("!testroomid:example.org"),
        sender: user_id!("@user:example.org"),
        unsigned: Unsigned::default(),
    };

    assert_eq!(
        to_json_value(ev).unwrap(),
        json!({
            "type": "m.room.message",
            "event_id": "$143273582443PhrSn:example.org",
            "origin_server_ts": 10_000,
            "room_id": "!testroomid:example.org",
            "sender": "@user:example.org",
            "content": {
                "body": "test",
                "msgtype": "m.audio",
                "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd",
            }
        })
    );
}

#[test]
fn content_serialization() {
    let message_event_content =
        MessageEventContent::new(MessageType::Audio(AudioMessageEventContent {
            body: "test".into(),
            info: None,
            url: Some(mxc_uri!("mxc://example.org/ffed755USFFxlgbQYZGtryd")),
            file: None,
        }));

    assert_eq!(
        to_json_value(&message_event_content).unwrap(),
        json!({
            "body": "test",
            "msgtype": "m.audio",
            "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
        })
    );
}

#[test]
fn custom_content_serialization() {
    let json_data = json_object! {
        "custom_field".into() => json!("baba"),
        "another_one".into() => json!("abab"),
    };
    let custom_event_content = MessageType::_Custom(CustomEventContent {
        msgtype: "my_custom_msgtype".into(),
        data: json_data,
    });

    assert_eq!(
        to_json_value(&custom_event_content).unwrap(),
        json!({
            "msgtype": "my_custom_msgtype",
            "custom_field": "baba",
            "another_one": "abab",
        })
    );
}

#[test]
fn custom_content_deserialization() {
    let json_data = json!({
        "msgtype": "my_custom_msgtype",
        "custom_field": "baba",
        "another_one": "abab",
    });

    let expected_json_data = json_object! {
        "custom_field".into() => json!("baba"),
        "another_one".into() => json!("abab"),
    };

    assert_matches!(
        from_json_value::<Raw<MessageType>>(json_data)
            .unwrap()
            .deserialize()
            .unwrap(),
        MessageType::_Custom(CustomEventContent {
            msgtype,
            data
        }) if msgtype == "my_custom_msgtype"
            && data == expected_json_data
    );
}

#[test]
fn formatted_body_serialization() {
    let message_event_content =
        MessageEventContent::text_html("Hello, World!", "Hello, World!");

    assert_eq!(
        to_json_value(&message_event_content).unwrap(),
        json!({
            "body": "Hello, World!",
            "msgtype": "m.text",
            "format": "org.matrix.custom.html",
            "formatted_body": "Hello, World!",
        })
    );
}

#[test]
fn plain_text_content_serialization() {
    let message_event_content =
        MessageEventContent::text_plain("> <@test:example.com> test\n\ntest reply");

    assert_eq!(
        to_json_value(&message_event_content).unwrap(),
        json!({
            "body": "> <@test:example.com> test\n\ntest reply",
            "msgtype": "m.text"
        })
    );
}

#[test]
fn relates_to_content_serialization() {
    let message_event_content =
        assign!(MessageEventContent::text_plain("> <@test:example.com> test\n\ntest reply"), {
            relates_to: Some(Relation::Reply {
                in_reply_to: InReplyTo { event_id: event_id!("$15827405538098VGFWH:example.com") },
            }),
        });

    let json_data = json!({
        "body": "> <@test:example.com> test\n\ntest reply",
        "msgtype": "m.text",
        "m.relates_to": {
            "m.in_reply_to": {
                "event_id": "$15827405538098VGFWH:example.com"
            }
        }
    });

    assert_eq!(to_json_value(&message_event_content).unwrap(), json_data);
}

#[test]
#[cfg(not(feature = "unstable-pre-spec"))]
fn edit_deserialization_061() {
    let json_data = json!({
        "body": "s/foo/bar",
        "msgtype": "m.text",
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": event_id!("$1598361704261elfgc:localhost"),
        },
        "m.new_content": {
            "body": "bar",
        },
    });

    assert_matches!(
        from_json_value::<MessageEventContent>(json_data).unwrap(),
        MessageEventContent {
            msgtype: MessageType::Text(TextMessageEventContent {
                body,
                formatted: None,
                ..
            }),
            relates_to: Some(Relation::Custom(_)),
            ..
        } if body == "s/foo/bar"
    );
}

#[test]
#[cfg(feature = "unstable-pre-spec")]
fn edit_deserialization_future() {
    use ruma_events::room::relationships::Replacement;

    let ev_id = event_id!("$1598361704261elfgc:localhost");
    let json_data = json!({
        "body": "s/foo/bar",
        "msgtype": "m.text",
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": ev_id,
        },
        "m.new_content": {
            "body": "bar",
            "msgtype": "m.text",
        },
    });

    assert_matches!(
        from_json_value::<MessageEventContent>(json_data).unwrap(),
        MessageEventContent {
            msgtype: MessageType::Text(TextMessageEventContent {
                body,
                formatted: None,
                ..
            }),
            relates_to: Some(Relation::Replacement(Replacement { event_id })),
            new_content: Some(new_content),
            ..
        } if body == "s/foo/bar"
            && event_id == ev_id
            && matches!(
                &*new_content,
                MessageEventContent {
                    msgtype: MessageType::Text(TextMessageEventContent {
                        body,
                        formatted: None,
                        ..
                    }),
                    ..
                } if body == "bar"
            )
    );
}

#[test]
#[cfg(feature = "unstable-pre-spec")]
fn verification_request_deserialization() {
    let user_id = user_id!("@example2:localhost");
    let device_id: DeviceIdBox = "XOWLHHFSWM".into();

    let json_data = json!({
        "body": "@example:localhost is requesting to verify your key, ...",
        "msgtype": "m.key.verification.request",
        "to": user_id,
        "from_device": device_id,
        "methods": [
            "m.sas.v1",
            "m.qr_code.show.v1",
            "m.reciprocate.v1"
        ]
    });

    assert_matches!(
        from_json_value::<MessageEventContent>(json_data).unwrap(),
        MessageEventContent {
            msgtype: MessageType::VerificationRequest(KeyVerificationRequestEventContent {
                body,
                to,
                from_device,
                methods,
            }),
            ..
        } if body == "@example:localhost is requesting to verify your key, ..."
            && to == user_id
            && from_device == device_id
            && methods.contains(&VerificationMethod::MSasV1)
    );
}

#[test]
#[cfg(feature = "unstable-pre-spec")]
fn verification_request_serialization() {
    let user_id = user_id!("@example2:localhost");
    let device_id: DeviceIdBox = "XOWLHHFSWM".into();
    let body = "@example:localhost is requesting to verify your key, ...".to_string();

    let methods = vec![
        VerificationMethod::MSasV1,
        VerificationMethod::_Custom("m.qr_code.show.v1".to_string()),
        VerificationMethod::_Custom("m.reciprocate.v1".to_string()),
    ];

    let json_data = json!({
        "body": body,
        "msgtype": "m.key.verification.request",
        "to": user_id,
        "from_device": device_id,
        "methods": methods
    });

    let content = MessageType::VerificationRequest(KeyVerificationRequestEventContent {
        to: user_id,
        from_device: device_id,
        body,
        methods,
    });

    assert_eq!(to_json_value(&content).unwrap(), json_data,);
}

#[test]
fn content_deserialization() {
    let json_data = json!({
        "body": "test",
        "msgtype": "m.audio",
        "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
    });

    assert_matches!(
        from_json_value::<Raw<MessageEventContent>>(json_data)
            .unwrap()
            .deserialize()
            .unwrap(),
        MessageEventContent {
            msgtype: MessageType::Audio(AudioMessageEventContent {
                body,
                info: None,
                url: Some(url),
                file: None,
            }),
            ..
        } if body == "test" && url.to_string() == "mxc://example.org/ffed755USFFxlgbQYZGtryd"
    );
}

#[test]
fn content_deserialization_failure() {
    let json_data = json!({
        "body": "test","msgtype": "m.location",
        "url": "http://example.com/audio.mp3"
    });
    assert!(from_json_value::<Raw<MessageEventContent>>(json_data).unwrap().deserialize().is_err());
}
<commit_msg>events: Fix recently broken test<commit_after>use std::time::{Duration, UNIX_EPOCH};

use assign::assign;
use matches::assert_matches;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events::{
    key::verification::VerificationMethod, room::message::KeyVerificationRequestEventContent,
};
use ruma_events::{
    room::{
        message::{
            AudioMessageEventContent, CustomEventContent, MessageEvent, MessageEventContent,
            MessageType, Relation, TextMessageEventContent,
        },
        relationships::InReplyTo,
    },
    Unsigned,
};
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::DeviceIdBox;
use ruma_identifiers::{event_id, mxc_uri, room_id, user_id};
use ruma_serde::Raw;
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

macro_rules! json_object {
    ( $($key:expr => $value:expr),* $(,)? ) => {
        {
            let mut _map = serde_json::Map::<String, serde_json::Value>::new();
            $(
                let _ = _map.insert($key, $value);
            )*
            _map
        }
    };
}

#[test]
fn serialization() {
    let ev = MessageEvent {
        content: MessageEventContent::new(MessageType::Audio(AudioMessageEventContent {
            body: "test".into(),
            info: None,
            url: Some(mxc_uri!("mxc://example.org/ffed755USFFxlgbQYZGtryd")),
            file: None,
        })),
        event_id: event_id!("$143273582443PhrSn:example.org"),
        origin_server_ts: UNIX_EPOCH + Duration::from_millis(10_000),
        room_id: room_id!("!testroomid:example.org"),
        sender: user_id!("@user:example.org"),
        unsigned: Unsigned::default(),
    };

    assert_eq!(
        to_json_value(ev).unwrap(),
        json!({
            "type": "m.room.message",
            "event_id": "$143273582443PhrSn:example.org",
            "origin_server_ts": 10_000,
            "room_id": "!testroomid:example.org",
            "sender": "@user:example.org",
            "content": {
                "body": "test",
                "msgtype": "m.audio",
                "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd",
            }
        })
    );
}

#[test]
fn content_serialization() {
    let message_event_content =
        MessageEventContent::new(MessageType::Audio(AudioMessageEventContent {
            body: "test".into(),
            info: None,
            url: Some(mxc_uri!("mxc://example.org/ffed755USFFxlgbQYZGtryd")),
            file: None,
        }));

    assert_eq!(
        to_json_value(&message_event_content).unwrap(),
        json!({
            "body": "test",
            "msgtype": "m.audio",
            "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
        })
    );
}

#[test]
fn custom_content_serialization() {
    let json_data = json_object! {
        "custom_field".into() => json!("baba"),
        "another_one".into() => json!("abab"),
    };
    let custom_event_content = MessageType::_Custom(CustomEventContent {
        msgtype: "my_custom_msgtype".into(),
        data: json_data,
    });

    assert_eq!(
        to_json_value(&custom_event_content).unwrap(),
        json!({
            "msgtype": "my_custom_msgtype",
            "custom_field": "baba",
            "another_one": "abab",
        })
    );
}

#[test]
fn custom_content_deserialization() {
    let json_data = json!({
        "msgtype": "my_custom_msgtype",
        "custom_field": "baba",
        "another_one": "abab",
    });

    let expected_json_data = json_object! {
        "custom_field".into() => json!("baba"),
        "another_one".into() => json!("abab"),
    };

    assert_matches!(
        from_json_value::<Raw<MessageType>>(json_data)
            .unwrap()
            .deserialize()
            .unwrap(),
        MessageType::_Custom(CustomEventContent {
            msgtype,
            data
        }) if msgtype == "my_custom_msgtype"
            && data == expected_json_data
    );
}

#[test]
fn formatted_body_serialization() {
    let message_event_content =
        MessageEventContent::text_html("Hello, World!", "Hello, World!");

    assert_eq!(
        to_json_value(&message_event_content).unwrap(),
        json!({
            "body": "Hello, World!",
            "msgtype": "m.text",
            "format": "org.matrix.custom.html",
            "formatted_body": "Hello, World!",
        })
    );
}

#[test]
fn plain_text_content_serialization() {
    let message_event_content =
        MessageEventContent::text_plain("> <@test:example.com> test\n\ntest reply");

    assert_eq!(
        to_json_value(&message_event_content).unwrap(),
        json!({
            "body": "> <@test:example.com> test\n\ntest reply",
            "msgtype": "m.text"
        })
    );
}

#[test]
fn relates_to_content_serialization() {
    let message_event_content =
        assign!(MessageEventContent::text_plain("> <@test:example.com> test\n\ntest reply"), {
            relates_to: Some(Relation::Reply {
                in_reply_to: InReplyTo { event_id: event_id!("$15827405538098VGFWH:example.com") },
            }),
        });

    let json_data = json!({
        "body": "> <@test:example.com> test\n\ntest reply",
        "msgtype": "m.text",
        "m.relates_to": {
            "m.in_reply_to": {
                "event_id": "$15827405538098VGFWH:example.com"
            }
        }
    });

    assert_eq!(to_json_value(&message_event_content).unwrap(), json_data);
}

#[test]
#[cfg(not(feature = "unstable-pre-spec"))]
fn edit_deserialization_061() {
    let json_data = json!({
        "body": "s/foo/bar",
        "msgtype": "m.text",
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": event_id!("$1598361704261elfgc:localhost"),
        },
        "m.new_content": {
            "body": "bar",
        },
    });

    assert_matches!(
        from_json_value::<MessageEventContent>(json_data).unwrap(),
        MessageEventContent {
            msgtype: MessageType::Text(TextMessageEventContent {
                body,
                formatted: None,
                ..
            }),
            relates_to: Some(Relation::_Custom(_)),
            ..
        } if body == "s/foo/bar"
    );
}

#[test]
#[cfg(feature = "unstable-pre-spec")]
fn edit_deserialization_future() {
    use ruma_events::room::relationships::Replacement;

    let ev_id = event_id!("$1598361704261elfgc:localhost");
    let json_data = json!({
        "body": "s/foo/bar",
        "msgtype": "m.text",
        "m.relates_to": {
            "rel_type": "m.replace",
            "event_id": ev_id,
        },
        "m.new_content": {
            "body": "bar",
            "msgtype": "m.text",
        },
    });

    assert_matches!(
        from_json_value::<MessageEventContent>(json_data).unwrap(),
        MessageEventContent {
            msgtype: MessageType::Text(TextMessageEventContent {
                body,
                formatted: None,
                ..
            }),
            relates_to: Some(Relation::Replacement(Replacement { event_id })),
            new_content: Some(new_content),
            ..
        } if body == "s/foo/bar"
            && event_id == ev_id
            && matches!(
                &*new_content,
                MessageEventContent {
                    msgtype: MessageType::Text(TextMessageEventContent {
                        body,
                        formatted: None,
                        ..
                    }),
                    ..
                } if body == "bar"
            )
    );
}

#[test]
#[cfg(feature = "unstable-pre-spec")]
fn verification_request_deserialization() {
    let user_id = user_id!("@example2:localhost");
    let device_id: DeviceIdBox = "XOWLHHFSWM".into();

    let json_data = json!({
        "body": "@example:localhost is requesting to verify your key, ...",
        "msgtype": "m.key.verification.request",
        "to": user_id,
        "from_device": device_id,
        "methods": [
            "m.sas.v1",
            "m.qr_code.show.v1",
            "m.reciprocate.v1"
        ]
    });

    assert_matches!(
        from_json_value::<MessageEventContent>(json_data).unwrap(),
        MessageEventContent {
            msgtype: MessageType::VerificationRequest(KeyVerificationRequestEventContent {
                body,
                to,
                from_device,
                methods,
            }),
            ..
        } if body == "@example:localhost is requesting to verify your key, ..."
            && to == user_id
            && from_device == device_id
            && methods.contains(&VerificationMethod::MSasV1)
    );
}

#[test]
#[cfg(feature = "unstable-pre-spec")]
fn verification_request_serialization() {
    let user_id = user_id!("@example2:localhost");
    let device_id: DeviceIdBox = "XOWLHHFSWM".into();
    let body = "@example:localhost is requesting to verify your key, ...".to_string();

    let methods = vec![
        VerificationMethod::MSasV1,
        VerificationMethod::_Custom("m.qr_code.show.v1".to_string()),
        VerificationMethod::_Custom("m.reciprocate.v1".to_string()),
    ];

    let json_data = json!({
        "body": body,
        "msgtype": "m.key.verification.request",
        "to": user_id,
        "from_device": device_id,
        "methods": methods
    });

    let content = MessageType::VerificationRequest(KeyVerificationRequestEventContent {
        to: user_id,
        from_device: device_id,
        body,
        methods,
    });

    assert_eq!(to_json_value(&content).unwrap(), json_data,);
}

#[test]
fn content_deserialization() {
    let json_data = json!({
        "body": "test",
        "msgtype": "m.audio",
        "url": "mxc://example.org/ffed755USFFxlgbQYZGtryd"
    });

    assert_matches!(
        from_json_value::<Raw<MessageEventContent>>(json_data)
            .unwrap()
            .deserialize()
            .unwrap(),
        MessageEventContent {
            msgtype: MessageType::Audio(AudioMessageEventContent {
                body,
                info: None,
                url: Some(url),
                file: None,
            }),
            ..
        } if body == "test" && url.to_string() == "mxc://example.org/ffed755USFFxlgbQYZGtryd"
    );
}

#[test]
fn content_deserialization_failure() {
    let json_data = json!({
        "body": "test","msgtype": "m.location",
        "url": "http://example.com/audio.mp3"
    });
    assert!(from_json_value::<Raw<MessageEventContent>>(json_data).unwrap().deserialize().is_err());
}
<|endoftext|>


<commit_before>use core::libc::size_t;
use core::ptr::{null, to_mut_unsafe_ptr};
use core::cast::transmute;
use ll::*;

fn require_ok(code: lwc_error) {
    match code {
        lwc_error_ok => (),
        e => fail fmt!("lwc error: %?", e)
    }
}

pub struct LwcStringRef {
    priv string: *lwc_string,

    drop {
        rust_lwc_string_unref(self.string);
    }
}

pub fn from_rust_string(s: &str) -> LwcStringRef {
    let mut interned_string = null();
    do str::as_c_str(s) |cs| {
        let code = lwc_intern_string(cs, s.len() as size_t, to_mut_unsafe_ptr(&mut interned_string));
        require_ok(code);
    }

    assert interned_string.is_not_null();

    LwcStringRef {
        string: interned_string
    }
}

pub fn from_lwc_string(s: *lwc_string) -> LwcStringRef {
    rust_lwc_string_ref(s);
    LwcStringRef {
        string: s
    }
}

impl LwcStringRef {
    fn len() -> uint {
        unsafe {
            (*self.string).len as uint
        }
    }

    fn clone() -> LwcStringRef {
        from_lwc_string(self.string)
    }

    fn raw_reffed() -> *lwc_string {
        self.string
    }
}

impl LwcStringRef: ToStr {
    pure fn to_str() -> ~str {
        unsafe {
            // The string is located immediately after the handle
            let p: *c_char = transmute(self.string.offset(1));
            str::raw::from_c_str_len(p, self.len())
        }
    }
}

#[test]
fn smoke_test() {
    let s1 = from_rust_string("test");
    let s2 = from_lwc_string(s1.string);
    debug!("%?", s1.len());
    debug!("%?", s2.len());
    assert s2.len() == 4;
    let s3 = s2.to_str();
    assert s3 == ~"test";
}

#[test]
fn multithreading_test() {
    for uint::range(0, 100) |i| {
        for iter::repeat(50) {
            do task::spawn {
                let s = vec::from_elem(i + 1, 0).to_str();
                let s = from_rust_string(s);
                let _t = s.clone();
            }
        }
    }
}<commit_msg>Remove -Ref suffixes<commit_after>use core::libc::size_t;
use core::ptr::{null, to_mut_unsafe_ptr};
use core::cast::transmute;
use ll::*;

fn require_ok(code: lwc_error) {
    match code {
        lwc_error_ok => (),
        e => fail fmt!("lwc error: %?", e)
    }
}

pub struct LwcString {
    priv string: *lwc_string,

    drop {
        rust_lwc_string_unref(self.string);
    }
}

pub fn from_rust_string(s: &str) -> LwcString {
    let mut interned_string = null();
    do str::as_c_str(s) |cs| {
        let code = lwc_intern_string(cs, s.len() as size_t, to_mut_unsafe_ptr(&mut interned_string));
        require_ok(code);
    }

    assert interned_string.is_not_null();

    LwcString {
        string: interned_string
    }
}

pub fn from_lwc_string(s: *lwc_string) -> LwcString {
    rust_lwc_string_ref(s);
    LwcString {
        string: s
    }
}

impl LwcString {
    fn len() -> uint {
        unsafe {
            (*self.string).len as uint
        }
    }

    fn clone() -> LwcString {
        from_lwc_string(self.string)
    }

    fn raw_reffed() -> *lwc_string {
        self.string
    }
}

impl LwcString: ToStr {
    pure fn to_str() -> ~str {
        unsafe {
            // The string is located immediately after the handle
            let p: *c_char = transmute(self.string.offset(1));
            str::raw::from_c_str_len(p, self.len())
        }
    }
}

#[test]
fn smoke_test() {
    let s1 = from_rust_string("test");
    let s2 = from_lwc_string(s1.string);
    debug!("%?", s1.len());
    debug!("%?", s2.len());
    assert s2.len() == 4;
    let s3 = s2.to_str();
    assert s3 == ~"test";
}

#[test]
fn multithreading_test() {
    for uint::range(0, 100) |i| {
        for iter::repeat(50) {
            do task::spawn {
                let s = vec::from_elem(i + 1, 0).to_str();
                let s = from_rust_string(s);
                let _t = s.clone();
            }
        }
    }
}<|endoftext|>


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

//! Sampling from random distributions.
//!
//! This is a generalization of `Rand` to allow parameters to control the
//! exact properties of the generated values, e.g. the mean and standard
//! deviation of a normal distribution. The `Sample` trait is the most
//! general, and allows for generating values that change some state
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.

use std::num::{Float, Int};
use std::marker;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup> {
    _marker: marker::PhantomData<fn() -> Sup>,
}

impl<Sup> Copy for RandSample<Sup> {}

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

impl<Sup> RandSample<Sup> {
    pub fn new() -> RandSample<Sup> {
        RandSample { _marker: marker::PhantomData }
    }
}

/// A value with a particular weight for use with `WeightedChoice`.
#[derive(Copy)]
pub struct Weighted<T> {
    /// The numerical weight of this item
    pub weight: u32,
    /// The actual item which is being weighted
    pub item: T,
}

/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `u32`, so one can store references or indices into
/// another vector.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
///
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
///                      Weighted { weight: 4, item: 'b' },
///                      Weighted { weight: 1, item: 'c' });
/// let wc = WeightedChoice::new(items.as_mut_slice());
/// let mut rng = rand::thread_rng();
/// for _ in 0..16 {
///      // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
///      println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
pub struct WeightedChoice<'a, T:'a> {
    items: &'a mut [Weighted<T>],
    weight_range: Range<u32>
}

impl<'a, T: Clone> WeightedChoice<'a, T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Panics if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `u32` can contain.
    pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(), "WeightedChoice::new called with no items");

        let mut running_total = 0;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in items.iter_mut() {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight \
                               larger than a u32 can contain")
            };

            item.weight = running_total;
        }
        assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");

        WeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total)
        }
    }
}

impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}

impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(
            rng: &mut R,
            symmetric: bool,
            x_tab: ziggurat_tables::ZigTable,
            f_tab: ziggurat_tables::ZigTable,
            mut pdf: P,
            mut zero_case: Z)
            -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
    const SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        //
        // This unfortunately misses out on the benefits of direct
        // floating point generation if an RNG like dSMFT is
        // used. (That is, such RNGs create floats directly, highly
        // efficiently and overload next_f32/f64, so by not calling it
        // this may be slower than it would be otherwise.)
        // FIXME: investigate/optimise for the above.
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as usize;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {2.0 * f - 1.0} else {f};
        let x = u * x_tab[i];

        let test_x = if symmetric { x.abs() } else {x};

        // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
        if test_x < x_tab[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen() < pdf(x) {
            return x;
        }
    }
}

#[cfg(test)]
mod tests {

    use {Rng, Rand};
    use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};

    #[derive(PartialEq, Debug)]
    struct ConstRand(usize);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    // 0, 1, 2, 3, ...
    struct CountingRng { i: u32 }
    impl Rng for CountingRng {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            self.i - 1
        }
        fn next_u64(&mut self) -> u64 {
            self.next_u32() as u64
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>::new();

        assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
        assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
    }
    #[test]
    fn test_weighted_choice() {
        // this makes assumptions about the internal implementation of
        // WeightedChoice, specifically: it doesn't reorder the items,
        // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
        // 1, internally; modulo a modulo operation).

        macro_rules! t {
            ($items:expr, $expected:expr) => {{
                let mut items = $items;
                let wc = WeightedChoice::new(items.as_mut_slice());
                let expected = $expected;

                let mut rng = CountingRng { i: 0 };

                for &val in expected.iter() {
                    assert_eq!(wc.ind_sample(&mut rng), val)
                }
            }}
        }

        t!(vec!(Weighted { weight: 1, item: 10}), [10]);

        // skip some
        t!(vec!(Weighted { weight: 0, item: 20},
                Weighted { weight: 2, item: 21},
                Weighted { weight: 0, item: 22},
                Weighted { weight: 1, item: 23}),
           [21,21, 23]);

        // different weights
        t!(vec!(Weighted { weight: 4, item: 30},
                Weighted { weight: 3, item: 31}),
           [30,30,30,30, 31,31,31]);

        // check that we're binary searching
        // correctly with some vectors of odd
        // length.
        t!(vec!(Weighted { weight: 1, item: 40},
                Weighted { weight: 1, item: 41},
                Weighted { weight: 1, item: 42},
                Weighted { weight: 1, item: 43},
                Weighted { weight: 1, item: 44}),
           [40, 41, 42, 43, 44]);
        t!(vec!(Weighted { weight: 1, item: 50},
                Weighted { weight: 1, item: 51},
                Weighted { weight: 1, item: 52},
                Weighted { weight: 1, item: 53},
                Weighted { weight: 1, item: 54},
                Weighted { weight: 1, item: 55},
                Weighted { weight: 1, item: 56}),
           [50, 51, 52, 53, 54, 55, 56]);
    }

    #[test] #[should_panic]
    fn test_weighted_choice_no_items() {
        WeightedChoice::<isize>::new(&mut []);
    }
    #[test] #[should_panic]
    fn test_weighted_choice_zero_weight() {
        WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
                                  Weighted { weight: 0, item: 1}]);
    }
    #[test] #[should_panic]
    fn test_weighted_choice_weight_overflows() {
        let x = !0 / 2; // x + x + 2 is the overflow
        WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
                                  Weighted { weight: 1, item: 1 },
                                  Weighted { weight: x, item: 2 },
                                  Weighted { weight: 1, item: 3 }]);
    }
}
<commit_msg>Implemented Clone trait on Weighted struct to allow cloning of weighted choices<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sampling from random distributions.
//!
//! This is a generalization of `Rand` to allow parameters to control the
//! exact properties of the generated values, e.g. the mean and standard
//! deviation of a normal distribution. The `Sample` trait is the most
//! general, and allows for generating values that change some state
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.

use std::num::{Float, Int};
use std::marker;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup> {
    _marker: marker::PhantomData<fn() -> Sup>,
}

impl<Sup> Copy for RandSample<Sup> {}

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

impl<Sup> RandSample<Sup> {
    pub fn new() -> RandSample<Sup> {
        RandSample { _marker: marker::PhantomData }
    }
}

/// A value with a particular weight for use with `WeightedChoice`.
#[derive(Copy)]
pub struct Weighted<T> {
    /// The numerical weight of this item
    pub weight: u32,
    /// The actual item which is being weighted
    pub item: T,
}

//implementation of Clone for Weighted
impl<T> Clone for Weighted<T> where T:Clone{
    fn clone(&self) -> Self {
        Weighted {
            weight: self.weight.clone(),
            item: self.item.clone()
        }
    }
    fn clone_from(&mut self, source: &Self) {
        self.weight = source.weight.clone();
        self.item = source.item.clone();
    }
}

/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `u32`, so one can store references or indices into
/// another vector.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
///
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
///                      Weighted { weight: 4, item: 'b' },
///                      Weighted { weight: 1, item: 'c' });
/// let wc = WeightedChoice::new(items.as_mut_slice());
/// let mut rng = rand::thread_rng();
/// for _ in 0..16 {
///      // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
///      println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
pub struct WeightedChoice<'a, T:'a> {
    items: &'a mut [Weighted<T>],
    weight_range: Range<u32>
}

impl<'a, T: Clone> WeightedChoice<'a, T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Panics if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `u32` can contain.
    pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(), "WeightedChoice::new called with no items");

        let mut running_total = 0;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in items.iter_mut() {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight \
                               larger than a u32 can contain")
            };

            item.weight = running_total;
        }
        assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");

        WeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total)
        }
    }
}

impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}

impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(
            rng: &mut R,
            symmetric: bool,
            x_tab: ziggurat_tables::ZigTable,
            f_tab: ziggurat_tables::ZigTable,
            mut pdf: P,
            mut zero_case: Z)
            -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
    const SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        //
        // This unfortunately misses out on the benefits of direct
        // floating point generation if an RNG like dSMFT is
        // used. (That is, such RNGs create floats directly, highly
        // efficiently and overload next_f32/f64, so by not calling it
        // this may be slower than it would be otherwise.)
        // FIXME: investigate/optimise for the above.
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as usize;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {2.0 * f - 1.0} else {f};
        let x = u * x_tab[i];

        let test_x = if symmetric { x.abs() } else {x};

        // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
        if test_x < x_tab[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen() < pdf(x) {
            return x;
        }
    }
}

#[cfg(test)]
mod tests {

    use {Rng, Rand};
    use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};

    #[derive(PartialEq, Debug)]
    struct ConstRand(usize);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    // 0, 1, 2, 3, ...
    struct CountingRng { i: u32 }
    impl Rng for CountingRng {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            self.i - 1
        }
        fn next_u64(&mut self) -> u64 {
            self.next_u32() as u64
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>::new();

        assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
        assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
    }
    #[test]
    fn test_weighted_choice() {
        // this makes assumptions about the internal implementation of
        // WeightedChoice, specifically: it doesn't reorder the items,
        // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
        // 1, internally; modulo a modulo operation).

        macro_rules! t {
            ($items:expr, $expected:expr) => {{
                let mut items = $items;
                let wc = WeightedChoice::new(items.as_mut_slice());
                let expected = $expected;

                let mut rng = CountingRng { i: 0 };

                for &val in expected.iter() {
                    assert_eq!(wc.ind_sample(&mut rng), val)
                }
            }}
        }

        t!(vec!(Weighted { weight: 1, item: 10}), [10]);

        // skip some
        t!(vec!(Weighted { weight: 0, item: 20},
                Weighted { weight: 2, item: 21},
                Weighted { weight: 0, item: 22},
                Weighted { weight: 1, item: 23}),
           [21,21, 23]);

        // different weights
        t!(vec!(Weighted { weight: 4, item: 30},
                Weighted { weight: 3, item: 31}),
           [30,30,30,30, 31,31,31]);

        // check that we're binary searching
        // correctly with some vectors of odd
        // length.
        t!(vec!(Weighted { weight: 1, item: 40},
                Weighted { weight: 1, item: 41},
                Weighted { weight: 1, item: 42},
                Weighted { weight: 1, item: 43},
                Weighted { weight: 1, item: 44}),
           [40, 41, 42, 43, 44]);
        t!(vec!(Weighted { weight: 1, item: 50},
                Weighted { weight: 1, item: 51},
                Weighted { weight: 1, item: 52},
                Weighted { weight: 1, item: 53},
                Weighted { weight: 1, item: 54},
                Weighted { weight: 1, item: 55},
                Weighted { weight: 1, item: 56}),
           [50, 51, 52, 53, 54, 55, 56]);
    }

    #[test] #[should_panic]
    fn test_weighted_choice_no_items() {
        WeightedChoice::<isize>::new(&mut []);
    }
    #[test] #[should_panic]
    fn test_weighted_choice_zero_weight() {
        WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
                                  Weighted { weight: 0, item: 1}]);
    }
    #[test] #[should_panic]
    fn test_weighted_choice_weight_overflows() {
        let x = !0 / 2; // x + x + 2 is the overflow
        WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
                                  Weighted { weight: 1, item: 1 },
                                  Weighted { weight: x, item: 2 },
                                  Weighted { weight: 1, item: 3 }]);
    }
}
<|endoftext|>


<commit_before>
use flowgger::config::Config;
use flowgger::{Decoder, Encoder, Input};
use openssl::ssl::*;
use openssl::ssl::SslMethod::*;
use openssl::x509::X509FileType;
use std::io::{stderr, Write, BufRead, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::mpsc::SyncSender;
use std::thread;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SH";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";

#[derive(Clone)]
struct TlsConfig {
    cert: String,
    key: String,
    ciphers: String
}

pub struct TlsInput {
    listen: String,
    tls_config: TlsConfig
}

impl Input for TlsInput {
    fn new(config: &Config) -> TlsInput {
        let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().unwrap()).to_owned();
        let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().unwrap()).to_owned();
        let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().unwrap()).to_owned();
        let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().unwrap()).to_owned();

        let tls_config = TlsConfig {
            cert: cert,
            key: key,
            ciphers: ciphers
        };
        TlsInput {
            listen: listen,
            tls_config: tls_config
        }
    }

    fn accept<TE>(&self, tx: SyncSender<Vec<u8>>, decoder: Box<Decoder + Send>, encoder: TE) where TE: Encoder + Clone + Send + 'static {
        let listener = TcpListener::bind(&self.listen as &str).unwrap();
        for client in listener.incoming() {
            match client {
                Ok(client) => {
                    let tx = tx.clone();
                    let (decoder, encoder) = (decoder.clone_boxed(), encoder.clone());
                    let tls_config = self.tls_config.clone();
                    thread::spawn(move|| {
                        handle_client(client, tx, decoder, encoder, tls_config);
                    });
                }
                Err(_) => { }
            }
        }
    }
}

fn handle_client<TE>(client: TcpStream, tx: SyncSender<Vec<u8>>, decoder: Box<Decoder>, encoder: TE, tls_config: TlsConfig) where TE: Encoder {
    let mut ctx = SslContext::new(Tlsv1_2).unwrap();
    ctx.set_verify(SSL_VERIFY_PEER, None); // Sigh
    ctx.set_options(SSL_OP_NO_COMPRESSION | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
    ctx.set_certificate_file(&Path::new(&tls_config.cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&tls_config.key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&tls_config.ciphers).unwrap();
    let sslclient = SslStream::accept(&ctx, client).unwrap();
    let reader = BufReader::new(sslclient);
    for line in reader.lines() {
        let line = match line {
            Err(_) => return,
            Ok(line) => line
        };
        if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
            let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
        }
    }
}

fn handle_line<TE>(line: &String, tx: &SyncSender<Vec<u8>>, decoder: &Box<Decoder>, encoder: &TE) -> Result<(), &'static str> where TE: Encoder {
    let decoded = try!(decoder.decode(&line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<commit_msg>Add a new input.framed preference to accept framed messages over TLS<commit_after>
use flowgger::config::Config;
use flowgger::{Decoder, Encoder, Input};
use openssl::ssl::*;
use openssl::ssl::SslMethod::*;
use openssl::x509::X509FileType;
use std::io::{stderr, Write, BufRead, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::str;
use std::sync::mpsc::SyncSender;
use std::thread;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SH";
const DEFAULT_FRAMED: bool = true;
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";

#[derive(Clone)]
struct TlsConfig {
    cert: String,
    key: String,
    ciphers: String,
    framed: bool
}

pub struct TlsInput {
    listen: String,
    tls_config: TlsConfig
}

impl Input for TlsInput {
    fn new(config: &Config) -> TlsInput {
        let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().unwrap()).to_owned();
        let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().unwrap()).to_owned();
        let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().unwrap()).to_owned();
        let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().unwrap()).to_owned();
        let framed = config.lookup("input.framed").map_or(DEFAULT_FRAMED, |x| x.as_bool().unwrap());

        let tls_config = TlsConfig {
            cert: cert,
            key: key,
            ciphers: ciphers,
            framed: framed
        };
        TlsInput {
            listen: listen,
            tls_config: tls_config
        }
    }

    fn accept<TE>(&self, tx: SyncSender<Vec<u8>>, decoder: Box<Decoder + Send>, encoder: TE) where TE: Encoder + Clone + Send + 'static {
        let listener = TcpListener::bind(&self.listen as &str).unwrap();
        for client in listener.incoming() {
            match client {
                Ok(client) => {
                    let tx = tx.clone();
                    let (decoder, encoder) = (decoder.clone_boxed(), encoder.clone());
                    let tls_config = self.tls_config.clone();
                    thread::spawn(move|| {
                        handle_client(client, tx, decoder, encoder, tls_config);
                    });
                }
                Err(_) => { }
            }
        }
    }
}

fn read_msglen(reader: &mut BufRead) -> Result<usize, &'static str> {
    let mut nbytes_v = Vec::with_capacity(16);
    let nbytes_vl = match reader.read_until(b' ', &mut nbytes_v) {
        Err(_) | Ok(0) | Ok(1) => return Err("EOF"),
        Ok(nbytes_vl) => nbytes_vl
    };
    let nbytes_s = match str::from_utf8(&nbytes_v[..nbytes_vl - 1]) {
        Err(_) => return Err("Invalid message length"),
        Ok(nbytes_s) => nbytes_s
    };
    let nbytes: usize = match nbytes_s.parse() {
        Err(_) => return Err("Invalid message length"),
        Ok(nbytes) => nbytes
    };
    Ok(nbytes)
}

fn handle_client<TE>(client: TcpStream, tx: SyncSender<Vec<u8>>, decoder: Box<Decoder>, encoder: TE, tls_config: TlsConfig) where TE: Encoder {
    let mut ctx = SslContext::new(Tlsv1_2).unwrap();
    ctx.set_verify(SSL_VERIFY_PEER, None); // Sigh
    ctx.set_options(SSL_OP_NO_COMPRESSION | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
    ctx.set_certificate_file(&Path::new(&tls_config.cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&tls_config.key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&tls_config.ciphers).unwrap();
    let sslclient = SslStream::accept(&ctx, client).unwrap();
    let mut reader = BufReader::new(sslclient);
    if tls_config.framed == false {
        for line in reader.lines() {
            let line = match line {
                Err(_) => return,
                Ok(line) => line
            };
            if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
                let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
            }
        }
    } else {
        loop {
            if let Err(e) = read_msglen(&mut reader) {
                let _ = writeln!(stderr(), "{}", e);
                return;
            }
            let mut line = String::new();
            if reader.read_line(&mut line).is_err() {
                println!("err");
                return;
            }
            if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
                let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
            }
        }
    }
}

fn handle_line<TE>(line: &String, tx: &SyncSender<Vec<u8>>, decoder: &Box<Decoder>, encoder: &TE) -> Result<(), &'static str> where TE: Encoder {
    let decoded = try!(decoder.decode(&line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonTruthy};
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct IfHelper {
    positive: bool,
}

impl HelperDef for IfHelper {
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let param = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"if\"")));

        let mut value = param.value().is_truthy();

        if !self.positive {
            value = !value;
        }

        let tmpl = if value {
            h.template()
        } else {
            h.inverse()
        };
        match tmpl {
            Some(ref t) => t.render(c, r, rc),
            None => Ok(()),
        }
    }
}

pub static IF_HELPER: IfHelper = IfHelper { positive: true };
pub static UNLESS_HELPER: IfHelper = IfHelper { positive: false };

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    use serialize::json::Json;

    #[test]
    fn test_if() {
        let t0 = Template::compile("{{#if this}}hello{{/if}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#unless this}}hello{{else}}world{{/unless}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.ok().unwrap(), "hello".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t0", &false);
        assert_eq!(r2.ok().unwrap(), "".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_if_context() {
        let json_str = r#"{"a":{"b":99,"c":{"d": true}}}"#;
        let data = Json::from_str(json_str).unwrap();

        let t0 = Template::compile("{{#if a.c.d}}hello {{a.b}}{{/if}}".to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#with a}}{{#if c.d}}hello {{../a.b}}{{/if}}{{/with}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_helper("with", Box::new(WITH_HELPER));
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "hello 99".to_string());

        let r1 = handlebars.render("t1", &data);
        assert_eq!(r1.ok().unwrap(), "hello 99".to_string());
    }
}
<commit_msg>(fix) unused imports<commit_after>use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonTruthy};
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct IfHelper {
    positive: bool,
}

impl HelperDef for IfHelper {
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let param = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"if\"")));

        let mut value = param.value().is_truthy();

        if !self.positive {
            value = !value;
        }

        let tmpl = if value {
            h.template()
        } else {
            h.inverse()
        };
        match tmpl {
            Some(ref t) => t.render(c, r, rc),
            None => Ok(()),
        }
    }
}

pub static IF_HELPER: IfHelper = IfHelper { positive: true };
pub static UNLESS_HELPER: IfHelper = IfHelper { positive: false };

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    use serialize::json::Json;
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    use helpers::WITH_HELPER;

    #[test]
    fn test_if() {
        let t0 = Template::compile("{{#if this}}hello{{/if}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#unless this}}hello{{else}}world{{/unless}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.ok().unwrap(), "hello".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t0", &false);
        assert_eq!(r2.ok().unwrap(), "".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_if_context() {
        let json_str = r#"{"a":{"b":99,"c":{"d": true}}}"#;
        let data = Json::from_str(json_str).unwrap();

        let t0 = Template::compile("{{#if a.c.d}}hello {{a.b}}{{/if}}".to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#with a}}{{#if c.d}}hello {{../a.b}}{{/if}}{{/with}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_helper("with", Box::new(WITH_HELPER));
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "hello 99".to_string());

        let r1 = handlebars.render("t1", &data);
        assert_eq!(r1.ok().unwrap(), "hello 99".to_string());
    }
}
<|endoftext|>


<commit_before>#[cfg(target_arch = "x86_64")]
macro_rules! hypercall {
    // Calling convention described here:
    // http://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-x86-64
    // This implementation based on the Mini-OS implementation of _hypercall0, _hypercall1, etc.
    ($ty : ty, $op : expr) => {
        unsafe {
            let result : i64;
            asm!("call HYPERCALL_PAGE + ${1:c}"
                : "={rax}" (result)
                : "i" ($op as i64 * 32)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr) => {
        unsafe {
            let result : i64;
            let __ign1 : i64;
            asm!("call HYPERCALL_PAGE + ${2:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr) => {
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            asm!("call HYPERCALL_PAGE + ${3:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr, $a3 : expr) => {
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            let __ign3 : i64;
            asm!("call HYPERCALL_PAGE + ${4:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2), "={rdx}" (__ign3)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64), "3" ($a3 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr, $a3 : expr, $a4 : expr) => {
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            let __ign3 : i64;
            let __ign4 : i64;
            asm!("call HYPERCALL_PAGE + ${5:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2), "={rdx}" (__ign3), "={r10}" (__ign4)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64), "3" ($a3 as i64), "4" ($a4 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr, $a3 : expr, $a4 : expr) => {
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            let __ign3 : i64;
            let __ign4 : i64;
            let __ign5 : i64;
            asm!("call HYPERCALL_PAGE + ${6:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2), "={rdx}" (__ign3), "={r10}" (__ign4), "={r8}" (__ign5)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64), "3" ($a3 as i64), "4" ($a4 as i64), "5" ($a5 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
}
<commit_msg>fix warning on hypercall macro<commit_after>#[cfg(target_arch = "x86_64")]
macro_rules! hypercall {
    // Calling convention described here:
    // http://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-x86-64
    // This implementation based on the Mini-OS implementation of _hypercall0, _hypercall1, etc.
    ($ty : ty, $op : expr) => {
        #[allow(unused_unsafe)] //https://github.com/rust-lang/rust/issues/8472
        unsafe {
            let result : i64;
            asm!("call HYPERCALL_PAGE + ${1:c}"
                : "={rax}" (result)
                : "i" ($op as i64 * 32)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr) => {
        #[allow(unused_unsafe)] //https://github.com/rust-lang/rust/issues/8472
        unsafe {
            let result : i64;
            let __ign1 : i64;
            asm!("call HYPERCALL_PAGE + ${2:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr) => {
        #[allow(unused_unsafe)] //https://github.com/rust-lang/rust/issues/8472
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            asm!("call HYPERCALL_PAGE + ${3:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr, $a3 : expr) => {
        #[allow(unused_unsafe)] //https://github.com/rust-lang/rust/issues/8472
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            let __ign3 : i64;
            asm!("call HYPERCALL_PAGE + ${4:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2), "={rdx}" (__ign3)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64), "3" ($a3 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr, $a3 : expr, $a4 : expr) => {
        #[allow(unused_unsafe)] //https://github.com/rust-lang/rust/issues/8472
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            let __ign3 : i64;
            let __ign4 : i64;
            asm!("call HYPERCALL_PAGE + ${5:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2), "={rdx}" (__ign3), "={r10}" (__ign4)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64), "3" ($a3 as i64), "4" ($a4 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
    ($ty : ty, $op : expr, $a1 : expr, $a2 : expr, $a3 : expr, $a4 : expr) => {
        #[allow(unused_unsafe)] //https://github.com/rust-lang/rust/issues/8472
        unsafe {
            let result : i64;
            let __ign1 : i64;
            let __ign2 : i64;
            let __ign3 : i64;
            let __ign4 : i64;
            let __ign5 : i64;
            asm!("call HYPERCALL_PAGE + ${6:c}"
                : "={rax}" (result),
                  "={rdi}" (__ign1), "={rsi}" (__ign2), "={rdx}" (__ign3), "={r10}" (__ign4), "={r8}" (__ign5)
                : "i" ($op as i64 * 32),
                  "1" ($a1 as i64), "2" ($a2 as i64), "3" ($a3 as i64), "4" ($a4 as i64), "5" ($a5 as i64)
                : "memory"
                : "volatile"
            );
            result as $ty;
        }
    };
}
<|endoftext|>


<commit_before>#![feature(ascii_ctype)]
use std::ascii::AsciiExt;

pub fn rotate(text: &str, key: usize) -> String {
    text.chars()
        .map(|x| match x {
            _ if x.is_ascii_lowercase() => {
                let v = (x as u8 - b'a' + key as u8) % 26 + b'a';
                v as char
            }
            _ if x.is_ascii_uppercase() => {
                let v = (x as u8 - b'A' + key as u8) % 26 + b'A';
                v as char
            }
            _ => x,
        })
        .collect()
}
<commit_msg>Use const instead of magic number<commit_after>#![feature(ascii_ctype)]
use std::ascii::AsciiExt;

pub fn rotate(text: &str, key: usize) -> String {
    const LA: u8 = b'a';
    const UA: u8 = b'A';
    text.chars()
        .map(|x| match x {
            _ if x.is_ascii_lowercase() => {
                let v = (x as u8 - LA + key as u8) % 26 + LA;
                v as char
            }
            _ if x.is_ascii_uppercase() => {
                let v = (x as u8 - UA + key as u8) % 26 + UA;
                v as char
            }
            _ => x,
        })
        .collect()
}
<|endoftext|>