<commit_before>use std::rand;
use std::rand::Rng;
use client::PluginRegister;
use events::CommandEvent;

fn choose(event: &CommandEvent) {
    let content = event.args.connect(" ");
    let mut rng = rand::task_rng();
    let split = if content.contains(",") {
        regex!(r"\s*,\s*").split(content.as_slice()).collect::<Vec<&str>>()
    } else {
        regex!(r"\s+").split(content.as_slice()).collect::<Vec<&str>>()
    };
    let message = match rng.choose(split.as_slice()) {
        Some(v) => *v,
        None => "I don't have anything to choose from.",
    };
    event.client.send_message(event.channel(), message);
}

fn coin(event: &CommandEvent) {
    let mut rng = rand::task_rng();
    let message = format!("\x01ACTION flips a coin... \x02{}\x02\x01", rng.choose(&["heads", "tails"]).unwrap());
    event.client.send_message(event.channel(), message.as_slice());
}

fn rand(event: &CommandEvent) {
    if event.args.len() != 1 {
        event.client.send_message(event.channel(), "Please specify exactly one argument.");
    }
    let max = match event.args[0].parse::<u64>() {
        Some(v) => v,
        None => {
            event.client.send_message(event.channel(), format!("Invalid number '{}'", event.args[0]).as_slice());
            return;
        },
    };
    let mut rng = rand::task_rng();
    event.client.send_message(event.channel(), format!("{}", rng.gen_range(1, max + 1)).as_slice())
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("choose", choose);
    register.register_command("coin", coin);
    register.register_command("rand", rand);
}
<commit_msg>Do calculation slightly differently so u64::MAX as a parameter doesn't crash the bot.<commit_after>use std::rand;
use std::rand::Rng;
use client::PluginRegister;
use events::CommandEvent;

fn choose(event: &CommandEvent) {
    let content = event.args.connect(" ");
    let mut rng = rand::task_rng();
    let split = if content.contains(",") {
        regex!(r"\s*,\s*").split(content.as_slice()).collect::<Vec<&str>>()
    } else {
        regex!(r"\s+").split(content.as_slice()).collect::<Vec<&str>>()
    };
    let message = match rng.choose(split.as_slice()) {
        Some(v) => *v,
        None => "I don't have anything to choose from.",
    };
    event.client.send_message(event.channel(), message);
}

fn coin(event: &CommandEvent) {
    let mut rng = rand::task_rng();
    let message = format!("\x01ACTION flips a coin... \x02{}\x02\x01", rng.choose(&["heads", "tails"]).unwrap());
    event.client.send_message(event.channel(), message.as_slice());
}

fn rand(event: &CommandEvent) {
    if event.args.len() != 1 {
        event.client.send_message(event.channel(), "Please specify exactly one argument.");
    }
    let max = match event.args[0].parse::<u64>() {
        Some(v) => v,
        None => {
            event.client.send_message(event.channel(), format!("Invalid number '{}'", event.args[0]).as_slice());
            return;
        },
    };
    let mut rng = rand::task_rng();
    event.client.send_message(event.channel(), format!("{}", rng.gen_range(0, max) + 1).as_slice())
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("choose", choose);
    register.register_command("coin", coin);
    register.register_command("rand", rand);
}
<|endoftext|>


<commit_before>use js_int::uint;
use matches::assert_matches;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_events::{
    custom::RedactedCustomEventContent,
    room::{
        aliases::RedactedRoomAliasesEventContent,
        create::RedactedRoomCreateEventContent,
        message::RedactedRoomMessageEventContent,
        redaction::{RoomRedactionEventContent, SyncRoomRedactionEvent},
    },
    AnyMessageEvent, AnyMessageEventContent, AnyRedactedMessageEvent,
    AnyRedactedMessageEventContent, AnyRedactedStateEventContent, AnyRedactedSyncMessageEvent,
    AnyRedactedSyncStateEvent, AnyRoomEvent, AnyStateEventContent, AnySyncRoomEvent, EventContent,
    Redact, RedactContent, RedactedMessageEvent, RedactedSyncMessageEvent, RedactedSyncStateEvent,
    RedactedUnsigned, Unsigned,
};
use ruma_identifiers::{event_id, room_id, user_id, RoomVersionId};
use serde_json::{
    from_value as from_json_value, json, to_value as to_json_value, value::to_raw_value,
};

fn unsigned() -> RedactedUnsigned {
    let mut unsigned = RedactedUnsigned::default();
    unsigned.redacted_because = Some(Box::new(SyncRoomRedactionEvent {
        content: RoomRedactionEventContent::with_reason("redacted because".into()),
        redacts: event_id!("$h29iv0s8:example.com"),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: Unsigned::default(),
    }));

    unsigned
}

#[test]
fn redacted_message_event_serialize() {
    let redacted = RedactedSyncMessageEvent {
        content: RedactedRoomMessageEventContent::new(),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: RedactedUnsigned::default(),
    };

    let expected = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "type": "m.room.message"
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redacted_aliases_event_serialize_no_content() {
    let redacted = RedactedSyncStateEvent {
        content: RedactedRoomAliasesEventContent::default(),
        event_id: event_id!("$h29iv0s8:example.com"),
        state_key: "".into(),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: RedactedUnsigned::default(),
    };

    let expected = json!({
      "event_id": "$h29iv0s8:example.com",
      "state_key": "",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "type": "m.room.aliases"
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redacted_aliases_event_serialize_with_content() {
    let redacted = RedactedSyncStateEvent {
        content: RedactedRoomAliasesEventContent::new_v1(vec![]),
        event_id: event_id!("$h29iv0s8:example.com"),
        state_key: "".to_owned(),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: RedactedUnsigned::default(),
    };

    let expected = json!({
      "content": {
          "aliases": []
      },
      "event_id": "$h29iv0s8:example.com",
      "state_key": "",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "type": "m.room.aliases"
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redacted_aliases_deserialize() {
    let redacted = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "state_key": "hello",
      "unsigned": unsigned(),
      "type": "m.room.aliases"
    });

    let actual = to_json_value(&redacted).unwrap();

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(actual).unwrap(),
        AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomAliases(
            RedactedSyncStateEvent {
                content: RedactedRoomAliasesEventContent { aliases, .. },
                event_id,
                ..
            },
        )) if event_id == event_id!("$h29iv0s8:example.com")
            && aliases.is_none()
    )
}

#[test]
fn redacted_deserialize_any_room() {
    let redacted = json!({
      "event_id": "$h29iv0s8:example.com",
      "room_id": "!roomid:room.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "unsigned": unsigned(),
      "type": "m.room.message"
    });

    let actual = to_json_value(&redacted).unwrap();

    assert_matches!(
        from_json_value::<AnyRoomEvent>(actual).unwrap(),
        AnyRoomEvent::RedactedMessage(AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
            content: RedactedRoomMessageEventContent { .. },
            event_id, room_id, ..
        })) if event_id == event_id!("$h29iv0s8:example.com")
            && room_id == room_id!("!roomid:room.com")
    )
}

#[test]
fn redacted_deserialize_any_room_sync() {
    let mut unsigned = RedactedUnsigned::default();
    // The presence of `redacted_because` triggers the event enum (AnySyncRoomEvent in this case)
    // to return early with `RedactedContent` instead of failing to deserialize according
    // to the event type string.
    unsigned.redacted_because = Some(Box::new(SyncRoomRedactionEvent {
        content: RoomRedactionEventContent::with_reason("redacted because".into()),
        redacts: event_id!("$h29iv0s8:example.com"),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: Unsigned::default(),
    }));

    let redacted = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "unsigned": unsigned,
      "type": "m.room.message"
    });

    let actual = to_json_value(&redacted).unwrap();

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(actual).unwrap(),
        AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(
            RedactedSyncMessageEvent {
                content: RedactedRoomMessageEventContent { .. },
                event_id,
                ..
            }
        )) if event_id == event_id!("$h29iv0s8:example.com")
    )
}

#[test]
fn redacted_state_event_deserialize() {
    let redacted = json!({
      "content": {
        "creator": "@carl:example.com",
      },
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "state_key": "hello there",
      "unsigned": unsigned(),
      "type": "m.room.create"
    });

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(redacted)
            .unwrap(),
        AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomCreate(
            RedactedSyncStateEvent {
                content: RedactedRoomCreateEventContent {
                    creator, ..
                },
                event_id,
                state_key,
                unsigned,
                ..
            }
        )) if event_id == event_id!("$h29iv0s8:example.com")
            && unsigned.redacted_because.is_some()
            && state_key == "hello there"
            && creator == user_id!("@carl:example.com")
    )
}

#[test]
fn redacted_custom_event_serialize() {
    let redacted = json!({
        "event_id": "$h29iv0s8:example.com",
        "origin_server_ts": 1,
        "sender": "@carl:example.com",
        "state_key": "hello there",
        "unsigned": unsigned(),
        "type": "m.made.up"
    });

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(redacted.clone()),
        Ok(AnySyncRoomEvent::RedactedState(_))
    );

    let x = from_json_value::<AnyRedactedSyncStateEvent>(redacted).unwrap();
    assert_eq!(x.event_id(), &event_id!("$h29iv0s8:example.com"))
}

#[test]
fn redacted_custom_event_deserialize() {
    let unsigned = unsigned();

    let redacted = RedactedSyncStateEvent {
        content: RedactedCustomEventContent { event_type: "m.made.up".into() },
        event_id: event_id!("$h29iv0s8:example.com"),
        sender: user_id!("@carl:example.com"),
        state_key: "hello there".into(),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        unsigned: unsigned.clone(),
    };

    let expected = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "state_key": "hello there",
      "unsigned": unsigned,
      "type": "m.made.up"
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redact_method_properly_redacts() {
    let ev = json!({
        "type": "m.room.message",
        "event_id": "$143273582443PhrSn:example.com",
        "origin_server_ts": 1,
        "room_id": "!roomid:room.com",
        "sender": "@user:example.com",
        "content": {
            "body": "test",
            "msgtype": "m.audio",
            "url": "mxc://example.com/AuDi0",
        }
    });

    let redaction = SyncRoomRedactionEvent {
        content: RoomRedactionEventContent::with_reason("redacted because".into()),
        redacts: event_id!("$143273582443PhrSn:example.com"),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: Unsigned::default(),
    };

    let event: AnyMessageEvent = from_json_value(ev).unwrap();

    assert_matches!(
        event.redact(redaction, &RoomVersionId::Version6),
        AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
            content: RedactedRoomMessageEventContent { .. },
            event_id,
            room_id,
            sender,
            origin_server_ts,
            unsigned,
        }) if event_id == event_id!("$143273582443PhrSn:example.com")
            && unsigned.redacted_because.is_some()
            && room_id == room_id!("!roomid:room.com")
            && sender == user_id!("@user:example.com")
            && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
    );
}

#[test]
fn redact_message_content() {
    let json = json!({
        "body": "test",
        "msgtype": "m.audio",
        "url": "mxc://example.com/AuDi0",
    });

    let raw_json = to_raw_value(&json).unwrap();
    let content = AnyMessageEventContent::from_parts("m.room.message", &raw_json).unwrap();

    assert_matches!(
        content.redact(&RoomVersionId::Version6),
        AnyRedactedMessageEventContent::RoomMessage(RedactedRoomMessageEventContent { .. })
    );
}

#[test]
fn redact_state_content() {
    let json = json!({
        "creator": "@carl:example.com",
        "m.federate": true,
        "room_version": "4"
    });

    let raw_json = to_raw_value(&json).unwrap();
    let content = AnyStateEventContent::from_parts("m.room.create", &raw_json).unwrap();

    assert_matches!(
        content.redact(&RoomVersionId::Version6),
        AnyRedactedStateEventContent::RoomCreate(RedactedRoomCreateEventContent {
            creator,
            ..
        }) if creator == user_id!("@carl:example.com")
    );
}
<commit_msg>events: Add more trailing commas<commit_after>use js_int::uint;
use matches::assert_matches;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_events::{
    custom::RedactedCustomEventContent,
    room::{
        aliases::RedactedRoomAliasesEventContent,
        create::RedactedRoomCreateEventContent,
        message::RedactedRoomMessageEventContent,
        redaction::{RoomRedactionEventContent, SyncRoomRedactionEvent},
    },
    AnyMessageEvent, AnyMessageEventContent, AnyRedactedMessageEvent,
    AnyRedactedMessageEventContent, AnyRedactedStateEventContent, AnyRedactedSyncMessageEvent,
    AnyRedactedSyncStateEvent, AnyRoomEvent, AnyStateEventContent, AnySyncRoomEvent, EventContent,
    Redact, RedactContent, RedactedMessageEvent, RedactedSyncMessageEvent, RedactedSyncStateEvent,
    RedactedUnsigned, Unsigned,
};
use ruma_identifiers::{event_id, room_id, user_id, RoomVersionId};
use serde_json::{
    from_value as from_json_value, json, to_value as to_json_value, value::to_raw_value,
};

fn unsigned() -> RedactedUnsigned {
    let mut unsigned = RedactedUnsigned::default();
    unsigned.redacted_because = Some(Box::new(SyncRoomRedactionEvent {
        content: RoomRedactionEventContent::with_reason("redacted because".into()),
        redacts: event_id!("$h29iv0s8:example.com"),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: Unsigned::default(),
    }));

    unsigned
}

#[test]
fn redacted_message_event_serialize() {
    let redacted = RedactedSyncMessageEvent {
        content: RedactedRoomMessageEventContent::new(),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: RedactedUnsigned::default(),
    };

    let expected = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "type": "m.room.message",
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redacted_aliases_event_serialize_no_content() {
    let redacted = RedactedSyncStateEvent {
        content: RedactedRoomAliasesEventContent::default(),
        event_id: event_id!("$h29iv0s8:example.com"),
        state_key: "".into(),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: RedactedUnsigned::default(),
    };

    let expected = json!({
      "event_id": "$h29iv0s8:example.com",
      "state_key": "",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "type": "m.room.aliases",
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redacted_aliases_event_serialize_with_content() {
    let redacted = RedactedSyncStateEvent {
        content: RedactedRoomAliasesEventContent::new_v1(vec![]),
        event_id: event_id!("$h29iv0s8:example.com"),
        state_key: "".to_owned(),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: RedactedUnsigned::default(),
    };

    let expected = json!({
      "content": {
          "aliases": []
      },
      "event_id": "$h29iv0s8:example.com",
      "state_key": "",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "type": "m.room.aliases",
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redacted_aliases_deserialize() {
    let redacted = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "state_key": "hello",
      "unsigned": unsigned(),
      "type": "m.room.aliases",
    });

    let actual = to_json_value(&redacted).unwrap();

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(actual).unwrap(),
        AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomAliases(
            RedactedSyncStateEvent {
                content: RedactedRoomAliasesEventContent { aliases, .. },
                event_id,
                ..
            },
        )) if event_id == event_id!("$h29iv0s8:example.com")
            && aliases.is_none()
    )
}

#[test]
fn redacted_deserialize_any_room() {
    let redacted = json!({
      "event_id": "$h29iv0s8:example.com",
      "room_id": "!roomid:room.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "unsigned": unsigned(),
      "type": "m.room.message",
    });

    let actual = to_json_value(&redacted).unwrap();

    assert_matches!(
        from_json_value::<AnyRoomEvent>(actual).unwrap(),
        AnyRoomEvent::RedactedMessage(AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
            content: RedactedRoomMessageEventContent { .. },
            event_id, room_id, ..
        })) if event_id == event_id!("$h29iv0s8:example.com")
            && room_id == room_id!("!roomid:room.com")
    )
}

#[test]
fn redacted_deserialize_any_room_sync() {
    let mut unsigned = RedactedUnsigned::default();
    // The presence of `redacted_because` triggers the event enum (AnySyncRoomEvent in this case)
    // to return early with `RedactedContent` instead of failing to deserialize according
    // to the event type string.
    unsigned.redacted_because = Some(Box::new(SyncRoomRedactionEvent {
        content: RoomRedactionEventContent::with_reason("redacted because".into()),
        redacts: event_id!("$h29iv0s8:example.com"),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: Unsigned::default(),
    }));

    let redacted = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "unsigned": unsigned,
      "type": "m.room.message",
    });

    let actual = to_json_value(&redacted).unwrap();

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(actual).unwrap(),
        AnySyncRoomEvent::RedactedMessage(AnyRedactedSyncMessageEvent::RoomMessage(
            RedactedSyncMessageEvent {
                content: RedactedRoomMessageEventContent { .. },
                event_id,
                ..
            }
        )) if event_id == event_id!("$h29iv0s8:example.com")
    )
}

#[test]
fn redacted_state_event_deserialize() {
    let redacted = json!({
      "content": {
        "creator": "@carl:example.com",
      },
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "state_key": "hello there",
      "unsigned": unsigned(),
      "type": "m.room.create",
    });

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(redacted)
            .unwrap(),
        AnySyncRoomEvent::RedactedState(AnyRedactedSyncStateEvent::RoomCreate(
            RedactedSyncStateEvent {
                content: RedactedRoomCreateEventContent {
                    creator, ..
                },
                event_id,
                state_key,
                unsigned,
                ..
            }
        )) if event_id == event_id!("$h29iv0s8:example.com")
            && unsigned.redacted_because.is_some()
            && state_key == "hello there"
            && creator == user_id!("@carl:example.com")
    )
}

#[test]
fn redacted_custom_event_serialize() {
    let redacted = json!({
        "event_id": "$h29iv0s8:example.com",
        "origin_server_ts": 1,
        "sender": "@carl:example.com",
        "state_key": "hello there",
        "unsigned": unsigned(),
        "type": "m.made.up",
    });

    assert_matches!(
        from_json_value::<AnySyncRoomEvent>(redacted.clone()),
        Ok(AnySyncRoomEvent::RedactedState(_))
    );

    let x = from_json_value::<AnyRedactedSyncStateEvent>(redacted).unwrap();
    assert_eq!(x.event_id(), &event_id!("$h29iv0s8:example.com"))
}

#[test]
fn redacted_custom_event_deserialize() {
    let unsigned = unsigned();

    let redacted = RedactedSyncStateEvent {
        content: RedactedCustomEventContent { event_type: "m.made.up".into() },
        event_id: event_id!("$h29iv0s8:example.com"),
        sender: user_id!("@carl:example.com"),
        state_key: "hello there".into(),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        unsigned: unsigned.clone(),
    };

    let expected = json!({
      "event_id": "$h29iv0s8:example.com",
      "origin_server_ts": 1,
      "sender": "@carl:example.com",
      "state_key": "hello there",
      "unsigned": unsigned,
      "type": "m.made.up",
    });

    let actual = to_json_value(&redacted).unwrap();
    assert_eq!(actual, expected);
}

#[test]
fn redact_method_properly_redacts() {
    let ev = json!({
        "type": "m.room.message",
        "event_id": "$143273582443PhrSn:example.com",
        "origin_server_ts": 1,
        "room_id": "!roomid:room.com",
        "sender": "@user:example.com",
        "content": {
            "body": "test",
            "msgtype": "m.audio",
            "url": "mxc://example.com/AuDi0",
        },
    });

    let redaction = SyncRoomRedactionEvent {
        content: RoomRedactionEventContent::with_reason("redacted because".into()),
        redacts: event_id!("$143273582443PhrSn:example.com"),
        event_id: event_id!("$h29iv0s8:example.com"),
        origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
        sender: user_id!("@carl:example.com"),
        unsigned: Unsigned::default(),
    };

    let event: AnyMessageEvent = from_json_value(ev).unwrap();

    assert_matches!(
        event.redact(redaction, &RoomVersionId::Version6),
        AnyRedactedMessageEvent::RoomMessage(RedactedMessageEvent {
            content: RedactedRoomMessageEventContent { .. },
            event_id,
            room_id,
            sender,
            origin_server_ts,
            unsigned,
        }) if event_id == event_id!("$143273582443PhrSn:example.com")
            && unsigned.redacted_because.is_some()
            && room_id == room_id!("!roomid:room.com")
            && sender == user_id!("@user:example.com")
            && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
    );
}

#[test]
fn redact_message_content() {
    let json = json!({
        "body": "test",
        "msgtype": "m.audio",
        "url": "mxc://example.com/AuDi0",
    });

    let raw_json = to_raw_value(&json).unwrap();
    let content = AnyMessageEventContent::from_parts("m.room.message", &raw_json).unwrap();

    assert_matches!(
        content.redact(&RoomVersionId::Version6),
        AnyRedactedMessageEventContent::RoomMessage(RedactedRoomMessageEventContent { .. })
    );
}

#[test]
fn redact_state_content() {
    let json = json!({
        "creator": "@carl:example.com",
        "m.federate": true,
        "room_version": "4",
    });

    let raw_json = to_raw_value(&json).unwrap();
    let content = AnyStateEventContent::from_parts("m.room.create", &raw_json).unwrap();

    assert_matches!(
        content.redact(&RoomVersionId::Version6),
        AnyRedactedStateEventContent::RoomCreate(RedactedRoomCreateEventContent {
            creator,
            ..
        }) if creator == user_id!("@carl:example.com")
    );
}
<|endoftext|>


<commit_before>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }
}
<commit_msg>Add test for `decode_right_side`<commit_after>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }
}
<|endoftext|>


<commit_before>use time::{SteadyTime, Duration};
use std::thread::sleep_ms;
use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Debug;
use std::cmp::PartialEq;

#[derive(Clone)]
struct Task<Token> where Token: Clone {
    interval: Duration,
    run_offset: Duration,
    token: Token,
    bond: TaskBond
}

#[derive(Clone, Debug)]
enum TaskBond {
    OneOff,
    Perpetual
}

impl<Token> fmt::Debug for Task<Token> where Token: Clone {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.bond {
            TaskBond::Perpetual => write!(f, "Task(every {}ms)", self.interval.num_milliseconds()),
            TaskBond::OneOff => write!(f, "Task(after {}ms)", self.interval.num_milliseconds())
        }
    }
}

impl<Token> Task<Token> where Token: Clone {
    fn new(interval: Duration, run_offset: Duration, bond: TaskBond, token: Token) -> Task<Token> {
        assert!(interval > Duration::seconds(0)); // negative interval would make schedule go back in time!
        Task {
            interval: interval,
            run_offset: run_offset,
            bond: bond,
            token: token
        }
    }

    //TODO: OneOff task should not have this
    fn next(self) -> Task<Token> {
        Task {
            run_offset: self.run_offset + self.interval,
            .. self
        }
    }

    fn schedule(&self) -> Duration {
        self.run_offset + self.interval
    }
}

pub trait TimeSource {
    // Duration since this TimeSource was crated
    fn now(&self) -> Duration;
}

struct SteadyTimeSource {
    offset: SteadyTime
}

impl SteadyTimeSource {
    fn new() -> SteadyTimeSource {
        SteadyTimeSource {
            offset: SteadyTime::now()
        }
    }
}

impl TimeSource for SteadyTimeSource {
    fn now(&self) -> Duration {
        SteadyTime::now() - self.offset
    }
}

// TODO: should that be u64?
type TimePoint = u32;

pub enum SchedulerAction {
    None,
    Wait(Duration),
    Skip(Vec<TimePoint>),
    Yield(TimePoint)
}

pub enum Schedule<Token> {
    NextIn(Duration),
    Missed(Vec<Token>),
    Current(Vec<Token>)
}

impl<Token> PartialEq for Schedule<Token> where Token: PartialEq<Token> {
    fn eq(&self, other: &Self) -> bool {
        match self {
            &Schedule::NextIn(ref duration) => if let &Schedule::NextIn(ref other_duration) = other {
                duration == other_duration
            } else {
                false
            },
            &Schedule::Missed(ref tokens) => if let &Schedule::Missed(ref other_tokens) = other {
                tokens == other_tokens
            } else {
                false
            },
            &Schedule::Current(ref tokens) => if let &Schedule::Current(ref other_tokens) = other {
                tokens == other_tokens
            } else {
                false
            }
        }
    }
}

impl<Token> Debug for Schedule<Token> where Token: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Schedule::NextIn(ref duration) => write!(f, "Schedule::NextIn({}ms)", duration.num_milliseconds()),
            &Schedule::Missed(ref tokens) => write!(f, "Schedule::Missed({:?})", tokens),
            &Schedule::Current(ref tokens) => write!(f, "Schedule::Current({:?})", tokens),
        }
    }
}

pub struct Scheduler<Token, TS> where TS: TimeSource, Token: Clone {
    time_point_interval: Duration,
    tasks: BTreeMap<TimePoint, Vec<Task<Token>>>,
    time_source: TS
}

impl<Token, TS> Scheduler<Token, TS> where TS: TimeSource, Token: Clone {
    //TODO: way to specify how many durations it is OK to consider task current
    pub fn new(time_point_interval: Duration, time_source: TS) -> Scheduler<Token, TS> where TS: TimeSource {
        assert!(time_point_interval > Duration::seconds(0));
        Scheduler {
            time_point_interval: time_point_interval,
            tasks: BTreeMap::new(),
            time_source: time_source
        }
    }

    //TODO: with_time_source()

    fn schedule(&mut self, task: Task<Token>) {
        let now = self.time_source.now();

        let task = task;
        let time_point = self.to_time_point(task.schedule() - now);

        self.tasks.entry(time_point).or_insert(Vec::new()).push(task);
    }

    pub fn after(&mut self, duration: Duration, token: Token) {
        let task = Task::new(duration, self.time_source.now(), TaskBond::OneOff, token);
        self.schedule(task);
    }

    pub fn every(&mut self, duration: Duration, token: Token) {
        let task = Task::new(duration, self.time_source.now(), TaskBond::Perpetual, token);
        self.schedule(task);
    }

    // TODO: we may miss some time points if wait waits longer
    fn next_action(&self) -> SchedulerAction {
        let now = self.time_source.now();
        let current_time_point = self.to_time_point(now);

        match self.tasks.iter().next() {
            None => SchedulerAction::None,
            Some((&time_point, _)) => {
                match time_point.cmp(&current_time_point) {
                    Ordering::Greater => SchedulerAction::Wait((self.to_duration(time_point)) - now),
                    //TODO: make task Eq for sorting by time
                    Ordering::Less => SchedulerAction::Skip(self.tasks.iter().take_while(|&(&time_point, &_)| time_point < current_time_point).map(|(time_point, _)| time_point.clone()).collect()),
                    Ordering::Equal => SchedulerAction::Yield(time_point)
                }
            }
        }
    }

    pub fn next(&mut self) -> Option<Schedule<Token>> {
        match self.next_action() {
            SchedulerAction::None => None,
            SchedulerAction::Wait(duration) => {
                Some(Schedule::NextIn(duration))
            },
            SchedulerAction::Skip(time_points) => {
                let tasks: Vec<Task<Token>> = time_points.iter().flat_map(|time_point|
                        self.tasks.remove(&time_point).unwrap()
                    ).collect();
                for task in tasks.iter() {
                    match task.bond {
                        TaskBond::Perpetual => self.schedule(task.clone()),
                        TaskBond::OneOff => ()
                    };
                }
                Some(Schedule::Missed(tasks.into_iter().map(|task| task.token).collect()))
            },
            SchedulerAction::Yield(time_point) => {
                let mut tasks = self.tasks.remove(&time_point).unwrap();
                for task in tasks.iter() {
                    match task.bond {
                        TaskBond::Perpetual => self.schedule(task.clone()),
                        TaskBond::OneOff => ()
                    };
                }

                tasks.sort_by(|a, b| a.run_offset.cmp(&b.run_offset));

                Some(Schedule::Current(tasks.into_iter().map(|task| task.token).collect()))
            }
        }
    }

    #[allow(dead_code)]
    pub fn replace_time_source(&mut self, time_source: TS) where TS: TimeSource  {
        self.time_source = time_source
    }

    fn to_time_point(&self, duration: Duration) -> TimePoint {
        let interval = self.time_point_interval.num_microseconds().unwrap();
        let duration = duration.num_microseconds().unwrap();
        assert!(duration >= 0);

        let time_point = duration / interval;
        (if duration % interval == 0 { time_point } else { time_point + 1 /* celi */ }) as TimePoint
    }

    fn to_duration(&self, time_point: TimePoint) -> Duration {
        self.time_point_interval * (time_point as i32)
    }
}

#[cfg(test)]
mod task {
    use time::Duration;
    use super::{Task, TaskBond, TimeSource, Scheduler, Schedule};

    struct MockTimeSource {
        current_time: Duration
    }

    impl MockTimeSource {
        fn new() -> MockTimeSource {
            MockTimeSource {
                current_time: Duration::seconds(0)
            }
        }

        fn fast_forward(self, duration: Duration) -> Self {
            MockTimeSource {
                current_time: self.current_time + duration
            }
        }
    }

    impl TimeSource for MockTimeSource {
        fn now(&self) -> Duration {
            self.current_time
        }
    }

    #[test]
    fn getting_next_schedule() {
        let now = Duration::seconds(0);
        let interval = Duration::seconds(1);
        let task = Task::new(interval, now, TaskBond::OneOff, 42);
        println!("task: {:?}", task);
        assert_eq!(task.schedule(), now + interval);
        assert_eq!(task.next().next().schedule(), now + interval * 3);
    }

    #[test]
    fn scheduler_to_time_point() {
        let scheduler: Scheduler<(),_> = Scheduler::new(Duration::seconds(1), MockTimeSource::new());
        assert_eq!(scheduler.to_time_point(Duration::seconds(0)), 0);
        assert_eq!(scheduler.to_time_point(Duration::seconds(1)), 1);
        assert_eq!(scheduler.to_time_point(Duration::seconds(2)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(2000)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(100)), 1);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(1100)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(1500)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(1800)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(2800)), 3);
    }

    #[test]
    fn scheduler() {
        let mut scheduler = Scheduler::new(Duration::seconds(1), MockTimeSource::new());

        scheduler.after(Duration::seconds(1), 1i32);

        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::seconds(1))));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::seconds(1))));

        scheduler.replace_time_source(MockTimeSource::new().fast_forward(Duration::milliseconds(700)));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
    }
}

<commit_msg>using FastForward trait to let compatible time source be forwarded through scheduler<commit_after>use time::{SteadyTime, Duration};
use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Debug;
use std::cmp::PartialEq;

#[derive(Clone)]
struct Task<Token> where Token: Clone {
    interval: Duration,
    run_offset: Duration,
    token: Token,
    bond: TaskBond
}

#[derive(Clone, Debug)]
enum TaskBond {
    OneOff,
    Perpetual
}

impl<Token> fmt::Debug for Task<Token> where Token: Clone {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.bond {
            TaskBond::Perpetual => write!(f, "Task(every {}ms)", self.interval.num_milliseconds()),
            TaskBond::OneOff => write!(f, "Task(after {}ms)", self.interval.num_milliseconds())
        }
    }
}

impl<Token> Task<Token> where Token: Clone {
    fn new(interval: Duration, run_offset: Duration, bond: TaskBond, token: Token) -> Task<Token> {
        assert!(interval > Duration::seconds(0)); // negative interval would make schedule go back in time!
        Task {
            interval: interval,
            run_offset: run_offset,
            bond: bond,
            token: token
        }
    }

    //TODO: OneOff task should not have this
    fn next(self) -> Task<Token> {
        Task {
            run_offset: self.run_offset + self.interval,
            .. self
        }
    }

    fn schedule(&self) -> Duration {
        self.run_offset + self.interval
    }
}

pub trait TimeSource {
    // Duration since this TimeSource was crated
    fn now(&self) -> Duration;
}

pub trait FastForward {
    fn fast_forward(&mut self, duration: Duration);
}

struct SteadyTimeSource {
    offset: SteadyTime
}

impl SteadyTimeSource {
    fn new() -> SteadyTimeSource {
        SteadyTimeSource {
            offset: SteadyTime::now()
        }
    }
}

impl TimeSource for SteadyTimeSource {
    fn now(&self) -> Duration {
        SteadyTime::now() - self.offset
    }
}

// TODO: should that be u64?
type TimePoint = u32;

pub enum SchedulerAction {
    None,
    Wait(Duration),
    Skip(Vec<TimePoint>),
    Yield(TimePoint)
}

pub enum Schedule<Token> {
    NextIn(Duration),
    Missed(Vec<Token>),
    Current(Vec<Token>)
}

impl<Token> PartialEq for Schedule<Token> where Token: PartialEq<Token> {
    fn eq(&self, other: &Self) -> bool {
        match self {
            &Schedule::NextIn(ref duration) => if let &Schedule::NextIn(ref other_duration) = other {
                duration == other_duration
            } else {
                false
            },
            &Schedule::Missed(ref tokens) => if let &Schedule::Missed(ref other_tokens) = other {
                tokens == other_tokens
            } else {
                false
            },
            &Schedule::Current(ref tokens) => if let &Schedule::Current(ref other_tokens) = other {
                tokens == other_tokens
            } else {
                false
            }
        }
    }
}

impl<Token> Debug for Schedule<Token> where Token: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Schedule::NextIn(ref duration) => write!(f, "Schedule::NextIn({}ms)", duration.num_milliseconds()),
            &Schedule::Missed(ref tokens) => write!(f, "Schedule::Missed({:?})", tokens),
            &Schedule::Current(ref tokens) => write!(f, "Schedule::Current({:?})", tokens),
        }
    }
}

pub struct Scheduler<Token, TS> where TS: TimeSource, Token: Clone {
    time_point_interval: Duration,
    tasks: BTreeMap<TimePoint, Vec<Task<Token>>>,
    time_source: TS
}

impl<Token, TS> Scheduler<Token, TS> where TS: TimeSource, Token: Clone {
    //TODO: way to specify how many durations it is OK to consider task current
    pub fn new(time_point_interval: Duration, time_source: TS) -> Scheduler<Token, TS> where TS: TimeSource {
        assert!(time_point_interval > Duration::seconds(0));
        Scheduler {
            time_point_interval: time_point_interval,
            tasks: BTreeMap::new(),
            time_source: time_source
        }
    }

    //TODO: with_time_source()

    fn schedule(&mut self, task: Task<Token>) {
        let now = self.time_source.now();

        let task = task;
        let time_point = self.to_time_point(task.schedule() - now);

        self.tasks.entry(time_point).or_insert(Vec::new()).push(task);
    }

    pub fn after(&mut self, duration: Duration, token: Token) {
        let task = Task::new(duration, self.time_source.now(), TaskBond::OneOff, token);
        self.schedule(task);
    }

    pub fn every(&mut self, duration: Duration, token: Token) {
        let task = Task::new(duration, self.time_source.now(), TaskBond::Perpetual, token);
        self.schedule(task);
    }

    // TODO: we may miss some time points if wait waits longer
    fn next_action(&self) -> SchedulerAction {
        let now = self.time_source.now();
        let current_time_point = self.to_time_point(now);

        match self.tasks.iter().next() {
            None => SchedulerAction::None,
            Some((&time_point, _)) => {
                match time_point.cmp(&current_time_point) {
                    Ordering::Greater => SchedulerAction::Wait((self.to_duration(time_point)) - now),
                    //TODO: make task Eq for sorting by time
                    Ordering::Less => SchedulerAction::Skip(self.tasks.iter().take_while(|&(&time_point, &_)| time_point < current_time_point).map(|(time_point, _)| time_point.clone()).collect()),
                    Ordering::Equal => SchedulerAction::Yield(time_point)
                }
            }
        }
    }

    pub fn next(&mut self) -> Option<Schedule<Token>> {
        match self.next_action() {
            SchedulerAction::None => None,
            SchedulerAction::Wait(duration) => {
                Some(Schedule::NextIn(duration))
            },
            SchedulerAction::Skip(time_points) => {
                let tasks: Vec<Task<Token>> = time_points.iter().flat_map(|time_point|
                        self.tasks.remove(&time_point).unwrap()
                    ).collect();
                for task in tasks.iter() {
                    match task.bond {
                        TaskBond::Perpetual => self.schedule(task.clone()),
                        TaskBond::OneOff => ()
                    };
                }
                Some(Schedule::Missed(tasks.into_iter().map(|task| task.token).collect()))
            },
            SchedulerAction::Yield(time_point) => {
                let mut tasks = self.tasks.remove(&time_point).unwrap();
                for task in tasks.iter() {
                    match task.bond {
                        TaskBond::Perpetual => self.schedule(task.clone()),
                        TaskBond::OneOff => ()
                    };
                }

                tasks.sort_by(|a, b| a.run_offset.cmp(&b.run_offset));

                Some(Schedule::Current(tasks.into_iter().map(|task| task.token).collect()))
            }
        }
    }

    fn to_time_point(&self, duration: Duration) -> TimePoint {
        let interval = self.time_point_interval.num_microseconds().unwrap();
        let duration = duration.num_microseconds().unwrap();
        assert!(duration >= 0);

        let time_point = duration / interval;
        (if duration % interval == 0 { time_point } else { time_point + 1 /* celi */ }) as TimePoint
    }

    fn to_duration(&self, time_point: TimePoint) -> Duration {
        self.time_point_interval * (time_point as i32)
    }
}

impl<Token, TS> FastForward for Scheduler<Token, TS> where TS: TimeSource + FastForward, Token: Clone {
    fn fast_forward(&mut self, duration: Duration) {
        self.time_source.fast_forward(duration);
    }
}

#[cfg(test)]
mod task {
    use time::Duration;
    use super::{Task, TaskBond, TimeSource, Scheduler, Schedule, FastForward};

    struct MockTimeSource {
        current_time: Duration
    }

    impl MockTimeSource {
        fn new() -> MockTimeSource {
            MockTimeSource {
                current_time: Duration::seconds(0)
            }
        }
    }

    impl FastForward for MockTimeSource {
        fn fast_forward(&mut self, duration: Duration) {
            self.current_time = self.current_time + duration;
        }
    }

    impl TimeSource for MockTimeSource {
        fn now(&self) -> Duration {
            self.current_time
        }
    }

    #[test]
    fn getting_next_schedule() {
        let now = Duration::seconds(0);
        let interval = Duration::seconds(1);
        let task = Task::new(interval, now, TaskBond::OneOff, 42);
        println!("task: {:?}", task);
        assert_eq!(task.schedule(), now + interval);
        assert_eq!(task.next().next().schedule(), now + interval * 3);
    }

    #[test]
    fn scheduler_to_time_point() {
        let scheduler: Scheduler<(),_> = Scheduler::new(Duration::seconds(1), MockTimeSource::new());
        assert_eq!(scheduler.to_time_point(Duration::seconds(0)), 0);
        assert_eq!(scheduler.to_time_point(Duration::seconds(1)), 1);
        assert_eq!(scheduler.to_time_point(Duration::seconds(2)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(2000)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(100)), 1);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(1100)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(1500)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(1800)), 2);
        assert_eq!(scheduler.to_time_point(Duration::milliseconds(2800)), 3);
    }

    #[test]
    fn scheduler() {
        let mut scheduler = Scheduler::new(Duration::seconds(1), MockTimeSource::new());

        scheduler.after(Duration::seconds(1), 1i32);
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::seconds(1))));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::seconds(1))));

        scheduler.fast_forward(Duration::milliseconds(100));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
        assert_eq!(scheduler.next(), Option::None);
    }
}

<|endoftext|>


<commit_before>extern crate rand;

use vec3::Vec3;

use std::fmt::Debug;
use rand::distributions::{IndependentSample, Range};

//
// Texture Definition
//
pub trait Texture: Debug + Clone {
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3;
}

//
// Constant Texture
//
#[derive(Debug, Clone)]
pub struct ConstantTexture {
    pub color: Vec3,
}

impl Texture for ConstantTexture {
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 {
        self.color
    }
}

//
// Checker Texture
// Alternates between two textures in checkerboard pattern
//
#[derive(Debug, Clone)]
pub struct CheckerTexture<T1: Texture, T2: Texture> {
    pub odd: T1,
    pub even: T2,
    pub scale: f64,
}

impl<T1, T2> Texture for CheckerTexture<T1, T2>
    where T1: Texture,
          T2: Texture
{
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 {
        let sines = p.map(&|x| (x * self.scale).sin());
        let sines = sines.x * sines.y * sines.z;

        if sines < 0.0 {
            self.odd.value(u,v,p)
        } else {
            self.even.value(u,v,p)
        }
    }
}

//
// Perlin Texture
//
#[derive(Debug, Clone)]
pub struct PerlinNoise {
    pub rand_float: Vec<f64>,
    pub perm_x: Vec<i32>,
    pub perm_y: Vec<i32>,
    pub perm_z: Vec<i32>,
}

impl PerlinNoise {
    pub fn new() -> PerlinNoise {
        PerlinNoise {
            rand_float: PerlinNoise::generate_rand_float(),
            perm_x: PerlinNoise::generate_perm(),
            perm_y: PerlinNoise::generate_perm(),
            perm_z: PerlinNoise::generate_perm(),
        }
    }

    fn noise(&self, p: &Vec3) -> f64 {
        let uvw = p.map(&|x| x - x.floor());
        let i = p.x.floor() as i32;
        let j = p.y.floor() as i32;
        let k = p.z.floor() as i32;
        let to_index = |x: i32, dx: i32| ((x+dx) & 255) as usize;

        let mut neighbors = [[[0.0f64; 2]; 2]; 2];
        for di in 0..2 {
            for dj in 0..2 {
                for dk in 0..2 {
                    let index =
                        self.perm_x[to_index(i,di)] ^
                        self.perm_y[to_index(j,dj)] ^
                        self.perm_z[to_index(k,dk)];
                    neighbors[di as usize][dj as usize][dk as usize] = self.rand_float[index as usize];
                }
            }
        }

        PerlinNoise::trilinear_interpolate(neighbors, uvw.x, uvw.y, uvw.z)
    }

    fn generate_rand_float() -> Vec<f64> {
        let mut v = Vec::with_capacity(256);
        let range = Range::new(0.0,1.0);
        let mut rng = rand::thread_rng();
        for _ in 0..256 {
            v.push(range.ind_sample(&mut rng));
        }
        v
    }

    fn permute(p: &mut Vec<i32>) {
        let mut rng = rand::thread_rng();
        for i in (0..p.len()).rev() {
            let range = Range::new(0,i+1);
            let target = range.ind_sample(&mut rng);
            let tmp = p[i];
            p[i] = p[target];
            p[target] = tmp;
        }
    }

    fn generate_perm() -> Vec<i32> {
        let mut p = Vec::with_capacity(256);
        for i in 0..256 {
            p.push(i as i32);
        }
        PerlinNoise::permute(&mut p);
        p
    }

    fn trilinear_interpolate(c: [[[f64; 2]; 2]; 2], u: f64, v: f64, w: f64) -> f64 {
        let mut acc = 0.0;
        for i in 0..2 {
            for j in 0..2 {
                for k in 0..2 {
                    let fi = (i as i32 as f64);
                    let fj = (j as i32 as f64);
                    let fk = (k as i32 as f64);
                    acc += (fi*u + (1.0-fi) * (1.0-u)) *
                           (fj*v + (1.0-fj) * (1.0-v)) *
                           (fk*w + (1.0-fk) * (1.0-w)) *
                           c[i as usize][j as usize][k as usize];
                }
            }
        }
        acc
    }
}

impl Texture for PerlinNoise {
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 {
        Vec3::new(1.0,1.0,1.0) * self.noise(p)
    }
}

// Constructors
pub fn constant_texture(c: Vec3) -> ConstantTexture {
    ConstantTexture { color: c }
}

pub fn checker_texture<T1, T2>(t1: T1, t2: T2, scale: f64) -> CheckerTexture<T1,T2>
    where T1: Texture,
          T2: Texture
{
    CheckerTexture {
        odd: t1,
        even: t2,
        scale: scale,
    }
}

pub fn perlin_noise_texture() -> PerlinNoise {
    PerlinNoise::new()
}
<commit_msg>Chapter 4: Hermite Cubic<commit_after>extern crate rand;

use vec3::Vec3;

use std::fmt::Debug;
use rand::distributions::{IndependentSample, Range};

//
// Texture Definition
//
pub trait Texture: Debug + Clone {
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3;
}

//
// Constant Texture
//
#[derive(Debug, Clone)]
pub struct ConstantTexture {
    pub color: Vec3,
}

impl Texture for ConstantTexture {
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 {
        self.color
    }
}

//
// Checker Texture
// Alternates between two textures in checkerboard pattern
//
#[derive(Debug, Clone)]
pub struct CheckerTexture<T1: Texture, T2: Texture> {
    pub odd: T1,
    pub even: T2,
    pub scale: f64,
}

impl<T1, T2> Texture for CheckerTexture<T1, T2>
    where T1: Texture,
          T2: Texture
{
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 {
        let sines = p.map(&|x| (x * self.scale).sin());
        let sines = sines.x * sines.y * sines.z;

        if sines < 0.0 {
            self.odd.value(u,v,p)
        } else {
            self.even.value(u,v,p)
        }
    }
}

//
// Perlin Texture
//
#[derive(Debug, Clone)]
pub struct PerlinNoise {
    pub rand_float: Vec<f64>,
    pub perm_x: Vec<i32>,
    pub perm_y: Vec<i32>,
    pub perm_z: Vec<i32>,
}

impl PerlinNoise {
    pub fn new() -> PerlinNoise {
        PerlinNoise {
            rand_float: PerlinNoise::generate_rand_float(),
            perm_x: PerlinNoise::generate_perm(),
            perm_y: PerlinNoise::generate_perm(),
            perm_z: PerlinNoise::generate_perm(),
        }
    }

    fn noise(&self, p: &Vec3) -> f64 {
        let uvw = p.map(&|x| x - x.floor());
        let uvw = uvw.map(&|x| x*x*(3.0-2.0*x)); // hermite cubic
        let i = p.x.floor() as i32;
        let j = p.y.floor() as i32;
        let k = p.z.floor() as i32;
        let to_index = |x: i32, dx: i32| ((x+dx) & 255) as usize;

        let mut neighbors = [[[0.0f64; 2]; 2]; 2];
        for di in 0..2 {
            for dj in 0..2 {
                for dk in 0..2 {
                    let index =
                        self.perm_x[to_index(i,di)] ^
                        self.perm_y[to_index(j,dj)] ^
                        self.perm_z[to_index(k,dk)];
                    neighbors[di as usize][dj as usize][dk as usize] = self.rand_float[index as usize];
                }
            }
        }

        PerlinNoise::trilinear_interpolate(neighbors, uvw.x, uvw.y, uvw.z)
    }

    fn generate_rand_float() -> Vec<f64> {
        let mut v = Vec::with_capacity(256);
        let range = Range::new(0.0,1.0);
        let mut rng = rand::thread_rng();
        for _ in 0..256 {
            v.push(range.ind_sample(&mut rng));
        }
        v
    }

    fn permute(p: &mut Vec<i32>) {
        let mut rng = rand::thread_rng();
        for i in (0..p.len()).rev() {
            let range = Range::new(0,i+1);
            let target = range.ind_sample(&mut rng);
            let tmp = p[i];
            p[i] = p[target];
            p[target] = tmp;
        }
    }

    fn generate_perm() -> Vec<i32> {
        let mut p = Vec::with_capacity(256);
        for i in 0..256 {
            p.push(i as i32);
        }
        PerlinNoise::permute(&mut p);
        p
    }

    fn trilinear_interpolate(c: [[[f64; 2]; 2]; 2], u: f64, v: f64, w: f64) -> f64 {
        let mut acc = 0.0;
        for i in 0..2 {
            for j in 0..2 {
                for k in 0..2 {
                    let fi = i as i32 as f64;
                    let fj = j as i32 as f64;
                    let fk = k as i32 as f64;
                    acc += (fi*u + (1.0-fi) * (1.0-u)) *
                           (fj*v + (1.0-fj) * (1.0-v)) *
                           (fk*w + (1.0-fk) * (1.0-w)) *
                           c[i as usize][j as usize][k as usize];
                }
            }
        }
        acc
    }
}

impl Texture for PerlinNoise {
    fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 {
        Vec3::new(1.0,1.0,1.0) * self.noise(p)
    }
}

// Constructors
pub fn constant_texture(c: Vec3) -> ConstantTexture {
    ConstantTexture { color: c }
}

pub fn checker_texture<T1, T2>(t1: T1, t2: T2, scale: f64) -> CheckerTexture<T1,T2>
    where T1: Texture,
          T2: Texture
{
    CheckerTexture {
        odd: t1,
        even: t2,
        scale: scale,
    }
}

pub fn perlin_noise_texture() -> PerlinNoise {
    PerlinNoise::new()
}
<|endoftext|>


<commit_before>use command_with_sender_iter::CommandWithSenderIterable;
use starred_message::StarredMessage;
use irc::client::prelude::*;
use irc::client::server::NetIrcServer;

pub struct IrcResponder {
	server: NetIrcServer,
}

impl IrcResponder {
	pub fn from_config(config: Config) -> IrcResponder {
		let server = IrcServer::from_config(config).unwrap();
		server.identify().unwrap();

		IrcResponder{
			server: server,
		}
	}

	pub fn handle(&mut self) {
		let mut starred: Vec<StarredMessage> = Vec::new();

		for message in self.server.iter_cmd_sender() {
			match message {
				Ok((Command::JOIN(_, _, _), Some(sender))) =>
					if sender == "StarBot" {
						println!("I'm in")
					},
				Ok((Command::PRIVMSG(target, msg), sender)) => {
					match (&target[..], &msg[..], sender.as_ref().map(|s| &s[..])) {
						(_,         "Navaer, StarBot",  _) => self.quit(),
						("StarBot", "Navaer",           _) => self.quit(),
						("StarBot", "board", Some(sender)) => {
							let mut sorted_stars = starred.clone();
							sorted_stars.sort_by(|lhs, rhs| lhs.stars.cmp(&rhs.stars));

							for message in sorted_stars.iter().take(10) {
								self.server.send_notice(&*&sender, &*&format!("{}", message)).unwrap();
							}
						},
						("StarBot", "_dump", Some(sender)) => self.server.send_privmsg(&*&sender, &*&format!("{:?}", starred)).unwrap(),
						("StarBot", "help",  Some(sender)) => {
							self.server.send_notice(&*&sender, r#"Cummands, level 0:"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "add <" username ">" message content -- add your star to a message"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "remove <" username ">" message content -- remove your star from a message"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "help" -- send this help notice to sender"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "board" -- pretty-print the starboard, snackchat-style"#).unwrap();
							self.server.send_notice(&*&sender, r#"Execute via sending a PRIVMSG (as by "/msg") to StarBot"#).unwrap();
						},
						("StarBot", "_help", Some(sender)) => {
							self.server.send_notice(&*&sender, r#"Cummands, level 1:"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "Navaer" -- murder StarBot"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "_dump" -- dump raw star data to sender"#).unwrap();
							self.server.send_notice(&*&sender, r#"Execute via sending a PRIVMSG (as by "/msg") to StarBot"#).unwrap();
						},
						("StarBot", "__help", Some(sender)) => {
							self.server.send_notice(&*&sender, r#"Cummands, level 2:"#).unwrap();
							self.server.send_notice(&*&sender, r#"  "Navaer, StarBot" -- murder StarBot"#).unwrap();
							self.server.send_notice(&*&sender, r#"Execute via sending a PRIVMSG any channel StarBot is listening to"#).unwrap();
						},
						("StarBot", msg, Some(sender)) => {
							if msg.starts_with("add ") {
								if let Some(star_message) = StarredMessage::from_message_content(&msg[4..], sender) {
									if match starred.iter_mut().find(|fmsg| (&fmsg.sender, &fmsg.message) == (&star_message.sender, &star_message.message)) {
										Some(ref mut existing_message) => {
											existing_message.stars += 1;
											existing_message.starrers.extend(star_message.starrers.clone());
											false
										},
										None => true,
									} {
										starred.push(star_message);  // Can't do it in match arm because it'd borrow starred as &mut twice
									}
								}
							} else if msg.starts_with("remove ") {
								if let Some(star_message) = StarredMessage::from_message_content(&msg[7..], sender) {
									if let Some(index) = match starred.iter_mut().enumerate().find(
										|fmsg| (&fmsg.1.sender, &fmsg.1.message) == (&star_message.sender, &star_message.message)
									) {
										Some((idx, ref mut existing_message)) =>
											if let Some(starrer_pos) = existing_message.starrers.iter().position(|starrer| starrer == &existing_message.starrers[0]) {
												existing_message.stars -= 1;
												existing_message.starrers.swap_remove(starrer_pos);
												Some(idx)
											} else {
												None
											},
										None => None,
									} {
										starred.swap_remove(index);  // Can't do it in match arm because it'd borrow starred as &mut twice
									}
								}
							}
						},
						_ => (),
					}
				},
				_ => (),
			}
		}
	}

	fn quit(&self) {
		self.server.send_quit("Mára mesta").unwrap();
	}
}
<commit_msg>Extract help into function<commit_after>use command_with_sender_iter::CommandWithSenderIterable;
use starred_message::StarredMessage;
use irc::client::prelude::*;
use irc::client::server::NetIrcServer;

pub struct IrcResponder {
	server: NetIrcServer,
}

impl IrcResponder {
	pub fn from_config(config: Config) -> IrcResponder {
		let server = IrcServer::from_config(config).unwrap();
		server.identify().unwrap();

		IrcResponder{
			server: server,
		}
	}

	pub fn handle(&mut self) {
		let mut starred: Vec<StarredMessage> = Vec::new();

		for message in self.server.iter_cmd_sender() {
			match message {
				Ok((Command::JOIN(_, _, _), Some(sender))) =>
					if sender == "StarBot" {
						println!("I'm in")
					},
				Ok((Command::PRIVMSG(target, msg), sender)) => {
					match (&target[..], &msg[..], sender.as_ref().map(|s| &s[..])) {
						(_,         "Navaer, StarBot",   _) => self.quit(),
						("StarBot", "Navaer",            _) => self.quit(),
						("StarBot", "help",   Some(sender)) => self.help(&*&sender, 0),
						("StarBot", "_help",  Some(sender)) => self.help(&*&sender, 1),
						("StarBot", "__help", Some(sender)) => self.help(&*&sender, 2),
						("StarBot", "_dump",  Some(sender)) => self.server.send_privmsg(&*&sender, &*&format!("{:?}", starred)).unwrap(),
						("StarBot", "board",  Some(sender)) => {
							let mut sorted_stars = starred.clone();
							sorted_stars.sort_by(|lhs, rhs| lhs.stars.cmp(&rhs.stars));

							for message in sorted_stars.iter().take(10) {
								self.server.send_notice(&*&sender, &*&format!("{}", message)).unwrap();
							}
						},
						("StarBot", msg, Some(sender)) => {
							if msg.starts_with("add ") {
								if let Some(star_message) = StarredMessage::from_message_content(&msg[4..], sender) {
									if match starred.iter_mut().find(|fmsg| (&fmsg.sender, &fmsg.message) == (&star_message.sender, &star_message.message)) {
										Some(ref mut existing_message) => {
											existing_message.stars += 1;
											existing_message.starrers.extend(star_message.starrers.clone());
											false
										},
										None => true,
									} {
										starred.push(star_message);  // Can't do it in match arm because it'd borrow starred as &mut twice
									}
								}
							} else if msg.starts_with("remove ") {
								if let Some(star_message) = StarredMessage::from_message_content(&msg[7..], sender) {
									if let Some(index) = match starred.iter_mut().enumerate().find(
										|fmsg| (&fmsg.1.sender, &fmsg.1.message) == (&star_message.sender, &star_message.message)
									) {
										Some((idx, ref mut existing_message)) =>
											if let Some(starrer_pos) = existing_message.starrers.iter().position(|starrer| starrer == &existing_message.starrers[0]) {
												existing_message.stars -= 1;
												existing_message.starrers.swap_remove(starrer_pos);
												Some(idx)
											} else {
												None
											},
										None => None,
									} {
										starred.swap_remove(index);  // Can't do it in match arm because it'd borrow starred as &mut twice
									}
								}
							}
						},
						_ => (),
					}
				},
				_ => (),
			}
		}
	}

	fn quit(&self) {
		self.server.send_quit("Mára mesta").unwrap();
	}

	fn help(&self, whom: &str, level: i32) {
		self.server.send_notice(whom, r#"Cummands, level 0:"#).unwrap();
		self.server.send_notice(whom, r#"  "add <" username ">" message content -- add your star to a message"#).unwrap();
		self.server.send_notice(whom, r#"  "remove <" username ">" message content -- remove your star from a message"#).unwrap();
		self.server.send_notice(whom, r#"  "help" -- send this help notice to sender"#).unwrap();
		self.server.send_notice(whom, r#"  "board" -- pretty-print the starboard, snackchat-style"#).unwrap();
		self.server.send_notice(whom, r#"Execute via sending a PRIVMSG (as by "/msg") to StarBot"#).unwrap();

		if level >= 1 {
			self.server.send_notice(whom, r#"Cummands, level 1:"#).unwrap();
			self.server.send_notice(whom, r#"  "Navaer" -- murder StarBot"#).unwrap();
			self.server.send_notice(whom, r#"  "_dump" -- dump raw star data to sender"#).unwrap();
			self.server.send_notice(whom, r#"Execute via sending a PRIVMSG (as by "/msg") to StarBot"#).unwrap();
		}

		if level >= 2 {
			self.server.send_notice(whom, r#"Cummands, level 2:"#).unwrap();
			self.server.send_notice(whom, r#"  "Navaer, StarBot" -- murder StarBot"#).unwrap();
			self.server.send_notice(whom, r#"Execute via sending a PRIVMSG any channel StarBot is listening to"#).unwrap();
		}
	}
}
<|endoftext|>


<commit_before>use std::{Box, String};
use std::collections::VecDeque;
use std::ops::DerefMut;

use orbital::{Color, Point, Size, Event, KeyEvent, MouseEvent, QuitEvent};

use super::display::Display;
use super::scheduler;

/// A window
pub struct Window {
    /// The position of the window
    pub point: Point,
    /// The size of the window
    pub size: Size,
    /// The title of the window
    pub title: String,
    /// The content of the window
    pub content: Box<Display>,
    /// The color of the window title
    pub title_color: Color,
    /// The color of the border
    pub border_color: Color,
    /// Is the window focused?
    pub focused: bool,
    /// Is the window minimized?
    pub minimized: bool,
    dragging: bool,
    last_mouse_event: MouseEvent,
    events: VecDeque<Event>,
    ptr: *mut Window,
}

impl Window {
    /// Create a new window
    pub fn new(point: Point, size: Size, title: String) -> Box<Self> {
        let mut ret = box Window {
            point: point,
            size: size,
            title: title,
            content: Display::new(size.width, size.height),
            title_color: Color::rgb(255, 255, 255),
            border_color: Color::rgba(64, 64, 64, 128),
            focused: false,
            minimized: false,
            dragging: false,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                right_button: false,
                middle_button: false,
            },
            events: VecDeque::new(),
            ptr: 0 as *mut Window,
        };

        unsafe {
            ret.ptr = ret.deref_mut();

            if ret.ptr as usize > 0 {
                (*super::session_ptr).add_window(ret.ptr);
            }
        }

        ret
    }

    /// Poll the window (new)
    pub fn poll(&mut self) -> Option<Event> {
        let event_option;
        unsafe {
            let reenable = scheduler::start_no_ints();
            event_option = self.events.pop_front();
            scheduler::end_no_ints(reenable);
        }
        return event_option;
    }

    /// Redraw the window
    pub fn redraw(&mut self) {
        unsafe {
            let reenable = scheduler::start_no_ints();
            self.content.flip();
            (*super::session_ptr).redraw = true;
            (*super::session_ptr).redraw();
            scheduler::end_no_ints(reenable);
        }
    }

    /// Draw the window using a `Display`
    pub fn draw(&mut self, display: &Display, font: usize) {
        if self.focused {
            self.border_color = Color::rgba(128, 128, 128, 192);
        } else {
            self.border_color = Color::rgba(64, 64, 64, 128);
        }

        if self.minimized {
            self.title_color = Color::rgb(0, 0, 0);
        } else {
            self.title_color = Color::rgb(255, 255, 255);

            display.rect(Point::new(self.point.x - 2, self.point.y - 18),
                         Size::new(self.size.width + 4, 18),
                         self.border_color);

            let mut cursor = Point::new(self.point.x, self.point.y - 17);
            for c in self.title.chars() {
                if cursor.x + 8 <= self.point.x + self.size.width as isize {
                    display.char(cursor, c, self.title_color, font);
                }
                cursor.x += 8;
            }

            display.rect(Point::new(self.point.x - 2, self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);
            display.rect(Point::new(self.point.x - 2, self.point.y + self.size.height as isize),
                         Size::new(self.size.width + 4, 2),
                         self.border_color);
            display.rect(Point::new(self.point.x + self.size.width as isize, self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);

            unsafe {
                let reenable = scheduler::start_no_ints();
                display.image(self.point,
                              self.content.onscreen as *const Color,
                              Size::new(self.content.width, self.content.height));
                scheduler::end_no_ints(reenable);
            }
        }
    }

    /// Called on key press
    pub fn on_key(&mut self, key_event: KeyEvent) {
        unsafe {
            let reenable = scheduler::start_no_ints();
            self.events.push_back(key_event.to_event());
            scheduler::end_no_ints(reenable);
        }
    }

    fn on_window_decoration(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= -2 && x < self.size.width as isize + 4 && y >= -18 && y < 0
    }

    fn on_window_body(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= 0 && x < self.size.width as isize && y >= 0 &&
        y < self.size.height as isize
    }

    fn mouse_button_pressed(mouse_event: &MouseEvent) -> bool {
        mouse_event.left_button || mouse_event.middle_button || mouse_event.right_button
    }

    /// Called on mouse movement
    pub fn on_mouse(&mut self, orig_mouse_event: MouseEvent, allow_catch: bool, active_window: bool) -> bool {
        let mut mouse_event = orig_mouse_event;

        mouse_event.x -= self.point.x;
        mouse_event.y -= self.point.y;

        let mut caught = false;

        if allow_catch && (active_window || Window::mouse_button_pressed(&mouse_event)) {
            if self.on_window_body(mouse_event.x, mouse_event.y) {
                caught = true;
            } else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                caught = true;

                if mouse_event.left_button {
                    if !self.last_mouse_event.left_button {
                        self.dragging = true;
                    }
                } else {
                    self.dragging = false;
                }

                if mouse_event.right_button {
                    if !self.last_mouse_event.right_button {
                        self.minimized = !self.minimized;
                    }
                }

                if mouse_event.middle_button {
                    unsafe {
                        let reenable = scheduler::start_no_ints();
                        self.events.push_back(QuitEvent.to_event());
                        scheduler::end_no_ints(reenable);
                    }
                }
            }

            if self.dragging {
                self.point.x += orig_mouse_event.x - self.last_mouse_event.x;
                self.point.y += orig_mouse_event.y - self.last_mouse_event.y;
                caught = true;
            }
        } else {
            self.dragging = false;
        }

        self.last_mouse_event = orig_mouse_event;

        if caught && !self.dragging {
            unsafe {
                let reenable = scheduler::start_no_ints();
                self.events.push_back(mouse_event.to_event());
                scheduler::end_no_ints(reenable);
            }
        }

        caught
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            if self.ptr as usize > 0 {
                (*super::session_ptr).remove_window(self.ptr);
            }
        }
    }
}
<commit_msg>Fix for case when mouse button held down<commit_after>use std::{Box, String};
use std::collections::VecDeque;
use std::ops::DerefMut;

use orbital::{Color, Point, Size, Event, KeyEvent, MouseEvent, QuitEvent};

use super::display::Display;
use super::scheduler;

/// A window
pub struct Window {
    /// The position of the window
    pub point: Point,
    /// The size of the window
    pub size: Size,
    /// The title of the window
    pub title: String,
    /// The content of the window
    pub content: Box<Display>,
    /// The color of the window title
    pub title_color: Color,
    /// The color of the border
    pub border_color: Color,
    /// Is the window focused?
    pub focused: bool,
    /// Is the window minimized?
    pub minimized: bool,
    dragging: bool,
    last_mouse_event: MouseEvent,
    events: VecDeque<Event>,
    ptr: *mut Window,
}

impl Window {
    /// Create a new window
    pub fn new(point: Point, size: Size, title: String) -> Box<Self> {
        let mut ret = box Window {
            point: point,
            size: size,
            title: title,
            content: Display::new(size.width, size.height),
            title_color: Color::rgb(255, 255, 255),
            border_color: Color::rgba(64, 64, 64, 128),
            focused: false,
            minimized: false,
            dragging: false,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                right_button: false,
                middle_button: false,
            },
            events: VecDeque::new(),
            ptr: 0 as *mut Window,
        };

        unsafe {
            ret.ptr = ret.deref_mut();

            if ret.ptr as usize > 0 {
                (*super::session_ptr).add_window(ret.ptr);
            }
        }

        ret
    }

    /// Poll the window (new)
    pub fn poll(&mut self) -> Option<Event> {
        let event_option;
        unsafe {
            let reenable = scheduler::start_no_ints();
            event_option = self.events.pop_front();
            scheduler::end_no_ints(reenable);
        }
        return event_option;
    }

    /// Redraw the window
    pub fn redraw(&mut self) {
        unsafe {
            let reenable = scheduler::start_no_ints();
            self.content.flip();
            (*super::session_ptr).redraw = true;
            (*super::session_ptr).redraw();
            scheduler::end_no_ints(reenable);
        }
    }

    /// Draw the window using a `Display`
    pub fn draw(&mut self, display: &Display, font: usize) {
        if self.focused {
            self.border_color = Color::rgba(128, 128, 128, 192);
        } else {
            self.border_color = Color::rgba(64, 64, 64, 128);
        }

        if self.minimized {
            self.title_color = Color::rgb(0, 0, 0);
        } else {
            self.title_color = Color::rgb(255, 255, 255);

            display.rect(Point::new(self.point.x - 2, self.point.y - 18),
                         Size::new(self.size.width + 4, 18),
                         self.border_color);

            let mut cursor = Point::new(self.point.x, self.point.y - 17);
            for c in self.title.chars() {
                if cursor.x + 8 <= self.point.x + self.size.width as isize {
                    display.char(cursor, c, self.title_color, font);
                }
                cursor.x += 8;
            }

            display.rect(Point::new(self.point.x - 2, self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);
            display.rect(Point::new(self.point.x - 2, self.point.y + self.size.height as isize),
                         Size::new(self.size.width + 4, 2),
                         self.border_color);
            display.rect(Point::new(self.point.x + self.size.width as isize, self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);

            unsafe {
                let reenable = scheduler::start_no_ints();
                display.image(self.point,
                              self.content.onscreen as *const Color,
                              Size::new(self.content.width, self.content.height));
                scheduler::end_no_ints(reenable);
            }
        }
    }

    /// Called on key press
    pub fn on_key(&mut self, key_event: KeyEvent) {
        unsafe {
            let reenable = scheduler::start_no_ints();
            self.events.push_back(key_event.to_event());
            scheduler::end_no_ints(reenable);
        }
    }

    fn on_window_decoration(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= -2 && x < self.size.width as isize + 4 && y >= -18 && y < 0
    }

    fn on_window_body(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= 0 && x < self.size.width as isize && y >= 0 &&
        y < self.size.height as isize
    }

    fn mouse_button_pressed(mouse_event: &MouseEvent) -> bool {
        mouse_event.left_button || mouse_event.middle_button || mouse_event.right_button
    }

    /// Called on mouse movement
    pub fn on_mouse(&mut self, orig_mouse_event: MouseEvent, allow_catch: bool, active_window: bool) -> bool {
        let mut mouse_event = orig_mouse_event;

        mouse_event.x -= self.point.x;
        mouse_event.y -= self.point.y;

        let mut caught = false;

        if allow_catch && (active_window || (Window::mouse_button_pressed(&mouse_event) && !Window::mouse_button_pressed(&self.last_mouse_event))) {
            if self.on_window_body(mouse_event.x, mouse_event.y) {
                caught = true;
            } else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                caught = true;

                if mouse_event.left_button {
                    if !self.last_mouse_event.left_button {
                        self.dragging = true;
                    }
                } else {
                    self.dragging = false;
                }

                if mouse_event.right_button {
                    if !self.last_mouse_event.right_button {
                        self.minimized = !self.minimized;
                    }
                }

                if mouse_event.middle_button {
                    unsafe {
                        let reenable = scheduler::start_no_ints();
                        self.events.push_back(QuitEvent.to_event());
                        scheduler::end_no_ints(reenable);
                    }
                }
            }

            if self.dragging {
                self.point.x += orig_mouse_event.x - self.last_mouse_event.x;
                self.point.y += orig_mouse_event.y - self.last_mouse_event.y;
                caught = true;
            }
        } else {
            self.dragging = false;
        }

        self.last_mouse_event = orig_mouse_event;

        if caught && !self.dragging {
            unsafe {
                let reenable = scheduler::start_no_ints();
                self.events.push_back(mouse_event.to_event());
                scheduler::end_no_ints(reenable);
            }
        }

        caught
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            if self.ptr as usize > 0 {
                (*super::session_ptr).remove_window(self.ptr);
            }
        }
    }
}
<|endoftext|>