<commit_before>use super::wayland::core::{default_display, Display, Registry};
use super::wayland::core::compositor::{Compositor, SurfaceId, WSurface};
use super::wayland::core::output::Output;
use super::wayland::core::seat::{ButtonState, Seat, Pointer, Keyboard, KeyState};
use super::wayland::core::shell::Shell;
use super::wayland_kbd::MappedKeyboard;
use super::keyboard::keycode_to_vkey;

use std::collections::{VecDeque, HashMap};
use std::sync::{Arc, Mutex};

use Event;
use MouseButton;
use ElementState;

enum AnyKeyboard {
    RawKeyBoard(Keyboard),
    XKB(MappedKeyboard)
}

pub struct WaylandContext {
    pub display: Display,
    pub registry: Registry,
    pub compositor: Compositor,
    pub shell: Shell,
    pub seat: Seat,
    pointer: Option<Mutex<Pointer<WSurface>>>,
    keyboard: Option<AnyKeyboard>,
    windows_event_queues: Arc<Mutex<HashMap<SurfaceId, Arc<Mutex<VecDeque<Event>>>>>>,
    current_pointer_surface: Arc<Mutex<Option<SurfaceId>>>,
    current_keyboard_surface: Arc<Mutex<Option<SurfaceId>>>,
    pub outputs: Vec<Arc<Output>>
}

impl WaylandContext {
    pub fn new() -> Option<WaylandContext> {
        let display = match default_display() {
            Some(d) => d,
            None => return None,
        };
        let registry = display.get_registry();
        // let the registry get its events
        display.sync_roundtrip();
        let compositor = match registry.get_compositor() {
            Some(c) => c,
            None => return None,
        };
        let shell = match registry.get_shell() {
            Some(s) => s,
            None => return None,
        };
        let seat = match registry.get_seats().into_iter().next() {
            Some(s) => s,
            None => return None,
        };
        let outputs = registry.get_outputs().into_iter().map(Arc::new).collect::<Vec<_>>();
        // let the other globals get their events
        display.sync_roundtrip();

        let current_pointer_surface = Arc::new(Mutex::new(None));

        // rustc has trouble finding the correct type here, so we explicit it.
        let windows_event_queues = Arc::new(Mutex::new(
            HashMap::<SurfaceId, Arc<Mutex<VecDeque<Event>>>>::new()
        ));

        // handle pointer inputs
        let mut pointer = seat.get_pointer();
        if let Some(ref mut p) = pointer {
            // set the enter/leave callbacks
            let current_surface = current_pointer_surface.clone();
            p.set_enter_action(move |_, _, sid, x, y| {
                *current_surface.lock().unwrap() = Some(sid);
            });
            let current_surface = current_pointer_surface.clone();
            p.set_leave_action(move |_, _, sid| {
                *current_surface.lock().unwrap() = None;
            });
            // set the events callbacks
            let current_surface = current_pointer_surface.clone();
            let event_queues = windows_event_queues.clone();
            p.set_motion_action(move |_, _, x, y| {
                // dispatch to the appropriate queue
                let sid = *current_surface.lock().unwrap();
                if let Some(sid) = sid {
                    let map = event_queues.lock().unwrap();
                    if let Some(queue) = map.get(&sid) {
                        queue.lock().unwrap().push_back(Event::Moved(x as i32,y as i32))
                    }
                }
            });
            let current_surface = current_pointer_surface.clone();
            let event_queues = windows_event_queues.clone();
            p.set_button_action(move |_, _, sid, b, s| {
                let button = match b {
                    0x110 => MouseButton::Left,
                    0x111 => MouseButton::Right,
                    0x112 => MouseButton::Middle,
                    _ => return
                };
                let state = match s {
                    ButtonState::Released => ElementState::Released,
                    ButtonState::Pressed => ElementState::Pressed
                };
                // dispatch to the appropriate queue
                let sid = *current_surface.lock().unwrap();
                if let Some(sid) = sid {
                    let map = event_queues.lock().unwrap();
                    if let Some(queue) = map.get(&sid) {
                        queue.lock().unwrap().push_back(Event::MouseInput(state, button))
                    }
                }
            });
        }

        // handle keyboard inputs
        let mut keyboard = None;
        let current_keyboard_surface = Arc::new(Mutex::new(None));
        if let Some(mut wkbd) = seat.get_keyboard() {
            display.sync_roundtrip();

            let current_surface = current_keyboard_surface.clone();
            wkbd.set_enter_action(move |_, _, sid, _| {
                *current_surface.lock().unwrap() = Some(sid);
            });
            let current_surface = current_keyboard_surface.clone();
            wkbd.set_leave_action(move |_, _, sid| {
                *current_surface.lock().unwrap() = None;
            });

            let kbd = match MappedKeyboard::new(wkbd) {
                Ok(mkbd) => {
                    // We managed to load a keymap
                    let current_surface = current_keyboard_surface.clone();
                    let event_queues = windows_event_queues.clone();
                    mkbd.set_key_action(move |state, _, _, _, keycode, keystate| {
                        let kstate = match keystate {
                            KeyState::Released => ElementState::Released,
                            KeyState::Pressed => ElementState::Pressed
                        };
                        let mut events = Vec::new();
                        // key event
                        events.push(Event::KeyboardInput(
                            kstate,
                            (keycode & 0xff) as u8,
                            keycode_to_vkey(state, keycode)
                        ));
                        // utf8 events
                        if kstate == ElementState::Pressed {
                            if let Some(txt) = state.get_utf8(keycode) {
                                events.extend(
                                    txt.chars().map(Event::ReceivedCharacter)
                                );
                            }
                        }
                        // dispatch to the appropriate queue
                        let sid = *current_surface.lock().unwrap();
                        if let Some(sid) = sid {
                            let map = event_queues.lock().unwrap();
                            if let Some(queue) = map.get(&sid) {
                                queue.lock().unwrap().extend(events.into_iter());
                            }
                        }
                    });
                    AnyKeyboard::XKB(mkbd)
                },
                Err(mut rkbd) => {
                    // fallback to raw inputs, no virtual keycodes
                    let current_surface = current_keyboard_surface.clone();
                    let event_queues = windows_event_queues.clone();
                    rkbd.set_key_action(move |_, _, _, keycode, keystate| {
                        let kstate = match keystate {
                            KeyState::Released => ElementState::Released,
                            KeyState::Pressed => ElementState::Pressed
                        };
                        let event = Event::KeyboardInput(kstate, (keycode & 0xff) as u8, None);
                        // dispatch to the appropriate queue
                        let sid = *current_surface.lock().unwrap();
                        if let Some(sid) = sid {
                            let map = event_queues.lock().unwrap();
                            if let Some(queue) = map.get(&sid) {
                                queue.lock().unwrap().push_back(event);
                            }
                        }
                    });
                    AnyKeyboard::RawKeyBoard(rkbd)
                }
            };
            keyboard = Some(kbd);
        }

        Some(WaylandContext {
            display: display,
            registry: registry,
            compositor: compositor,
            shell: shell,
            seat: seat,
            pointer: pointer.map(|p| Mutex::new(p)),
            keyboard: keyboard,
            windows_event_queues: windows_event_queues,
            current_pointer_surface: current_pointer_surface,
            current_keyboard_surface: current_keyboard_surface,
            outputs: outputs
        })
    }

    pub fn register_surface(&self, sid: SurfaceId, queue: Arc<Mutex<VecDeque<Event>>>) {
        self.windows_event_queues.lock().unwrap().insert(sid, queue);
        if let Some(ref p) = self.pointer {
            p.lock().unwrap().add_handled_surface(sid);
        }
    }

    pub fn deregister_surface(&self, sid: SurfaceId) {
        self.windows_event_queues.lock().unwrap().remove(&sid);
        if let Some(ref p) = self.pointer {
            p.lock().unwrap().remove_handled_surface(sid);
        }
    }
}<commit_msg>wayland: fix events Moved -> MouseMoved<commit_after>use super::wayland::core::{default_display, Display, Registry};
use super::wayland::core::compositor::{Compositor, SurfaceId, WSurface};
use super::wayland::core::output::Output;
use super::wayland::core::seat::{ButtonState, Seat, Pointer, Keyboard, KeyState};
use super::wayland::core::shell::Shell;
use super::wayland_kbd::MappedKeyboard;
use super::keyboard::keycode_to_vkey;

use std::collections::{VecDeque, HashMap};
use std::sync::{Arc, Mutex};

use Event;
use MouseButton;
use ElementState;

enum AnyKeyboard {
    RawKeyBoard(Keyboard),
    XKB(MappedKeyboard)
}

pub struct WaylandContext {
    pub display: Display,
    pub registry: Registry,
    pub compositor: Compositor,
    pub shell: Shell,
    pub seat: Seat,
    pointer: Option<Mutex<Pointer<WSurface>>>,
    keyboard: Option<AnyKeyboard>,
    windows_event_queues: Arc<Mutex<HashMap<SurfaceId, Arc<Mutex<VecDeque<Event>>>>>>,
    current_pointer_surface: Arc<Mutex<Option<SurfaceId>>>,
    current_keyboard_surface: Arc<Mutex<Option<SurfaceId>>>,
    pub outputs: Vec<Arc<Output>>
}

impl WaylandContext {
    pub fn new() -> Option<WaylandContext> {
        let display = match default_display() {
            Some(d) => d,
            None => return None,
        };
        let registry = display.get_registry();
        // let the registry get its events
        display.sync_roundtrip();
        let compositor = match registry.get_compositor() {
            Some(c) => c,
            None => return None,
        };
        let shell = match registry.get_shell() {
            Some(s) => s,
            None => return None,
        };
        let seat = match registry.get_seats().into_iter().next() {
            Some(s) => s,
            None => return None,
        };
        let outputs = registry.get_outputs().into_iter().map(Arc::new).collect::<Vec<_>>();
        // let the other globals get their events
        display.sync_roundtrip();

        let current_pointer_surface = Arc::new(Mutex::new(None));

        // rustc has trouble finding the correct type here, so we explicit it.
        let windows_event_queues = Arc::new(Mutex::new(
            HashMap::<SurfaceId, Arc<Mutex<VecDeque<Event>>>>::new()
        ));

        // handle pointer inputs
        let mut pointer = seat.get_pointer();
        if let Some(ref mut p) = pointer {
            // set the enter/leave callbacks
            let current_surface = current_pointer_surface.clone();
            p.set_enter_action(move |_, _, sid, x, y| {
                *current_surface.lock().unwrap() = Some(sid);
            });
            let current_surface = current_pointer_surface.clone();
            p.set_leave_action(move |_, _, sid| {
                *current_surface.lock().unwrap() = None;
            });
            // set the events callbacks
            let current_surface = current_pointer_surface.clone();
            let event_queues = windows_event_queues.clone();
            p.set_motion_action(move |_, _, x, y| {
                // dispatch to the appropriate queue
                let sid = *current_surface.lock().unwrap();
                if let Some(sid) = sid {
                    let map = event_queues.lock().unwrap();
                    if let Some(queue) = map.get(&sid) {
                        queue.lock().unwrap().push_back(Event::MouseMoved((x as i32,y as i32)))
                    }
                }
            });
            let current_surface = current_pointer_surface.clone();
            let event_queues = windows_event_queues.clone();
            p.set_button_action(move |_, _, sid, b, s| {
                let button = match b {
                    0x110 => MouseButton::Left,
                    0x111 => MouseButton::Right,
                    0x112 => MouseButton::Middle,
                    _ => return
                };
                let state = match s {
                    ButtonState::Released => ElementState::Released,
                    ButtonState::Pressed => ElementState::Pressed
                };
                // dispatch to the appropriate queue
                let sid = *current_surface.lock().unwrap();
                if let Some(sid) = sid {
                    let map = event_queues.lock().unwrap();
                    if let Some(queue) = map.get(&sid) {
                        queue.lock().unwrap().push_back(Event::MouseInput(state, button))
                    }
                }
            });
        }

        // handle keyboard inputs
        let mut keyboard = None;
        let current_keyboard_surface = Arc::new(Mutex::new(None));
        if let Some(mut wkbd) = seat.get_keyboard() {
            display.sync_roundtrip();

            let current_surface = current_keyboard_surface.clone();
            wkbd.set_enter_action(move |_, _, sid, _| {
                *current_surface.lock().unwrap() = Some(sid);
            });
            let current_surface = current_keyboard_surface.clone();
            wkbd.set_leave_action(move |_, _, sid| {
                *current_surface.lock().unwrap() = None;
            });

            let kbd = match MappedKeyboard::new(wkbd) {
                Ok(mkbd) => {
                    // We managed to load a keymap
                    let current_surface = current_keyboard_surface.clone();
                    let event_queues = windows_event_queues.clone();
                    mkbd.set_key_action(move |state, _, _, _, keycode, keystate| {
                        let kstate = match keystate {
                            KeyState::Released => ElementState::Released,
                            KeyState::Pressed => ElementState::Pressed
                        };
                        let mut events = Vec::new();
                        // key event
                        events.push(Event::KeyboardInput(
                            kstate,
                            (keycode & 0xff) as u8,
                            keycode_to_vkey(state, keycode)
                        ));
                        // utf8 events
                        if kstate == ElementState::Pressed {
                            if let Some(txt) = state.get_utf8(keycode) {
                                events.extend(
                                    txt.chars().map(Event::ReceivedCharacter)
                                );
                            }
                        }
                        // dispatch to the appropriate queue
                        let sid = *current_surface.lock().unwrap();
                        if let Some(sid) = sid {
                            let map = event_queues.lock().unwrap();
                            if let Some(queue) = map.get(&sid) {
                                queue.lock().unwrap().extend(events.into_iter());
                            }
                        }
                    });
                    AnyKeyboard::XKB(mkbd)
                },
                Err(mut rkbd) => {
                    // fallback to raw inputs, no virtual keycodes
                    let current_surface = current_keyboard_surface.clone();
                    let event_queues = windows_event_queues.clone();
                    rkbd.set_key_action(move |_, _, _, keycode, keystate| {
                        let kstate = match keystate {
                            KeyState::Released => ElementState::Released,
                            KeyState::Pressed => ElementState::Pressed
                        };
                        let event = Event::KeyboardInput(kstate, (keycode & 0xff) as u8, None);
                        // dispatch to the appropriate queue
                        let sid = *current_surface.lock().unwrap();
                        if let Some(sid) = sid {
                            let map = event_queues.lock().unwrap();
                            if let Some(queue) = map.get(&sid) {
                                queue.lock().unwrap().push_back(event);
                            }
                        }
                    });
                    AnyKeyboard::RawKeyBoard(rkbd)
                }
            };
            keyboard = Some(kbd);
        }

        Some(WaylandContext {
            display: display,
            registry: registry,
            compositor: compositor,
            shell: shell,
            seat: seat,
            pointer: pointer.map(|p| Mutex::new(p)),
            keyboard: keyboard,
            windows_event_queues: windows_event_queues,
            current_pointer_surface: current_pointer_surface,
            current_keyboard_surface: current_keyboard_surface,
            outputs: outputs
        })
    }

    pub fn register_surface(&self, sid: SurfaceId, queue: Arc<Mutex<VecDeque<Event>>>) {
        self.windows_event_queues.lock().unwrap().insert(sid, queue);
        if let Some(ref p) = self.pointer {
            p.lock().unwrap().add_handled_surface(sid);
        }
    }

    pub fn deregister_surface(&self, sid: SurfaceId) {
        self.windows_event_queues.lock().unwrap().remove(&sid);
        if let Some(ref p) = self.pointer {
            p.lock().unwrap().remove_handled_surface(sid);
        }
    }
}<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::fs;
use std::path::Path;
use std::io::{stdout, stderr, Stderr, Write};
use std::os::unix::fs::MetadataExt;
use std::process::exit;

use coreutils::to_human_readable_string;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{ls} */ r#"
NAME
    ls - list directory contents

SYNOPSIS
    ls [ -h | --help | -l ][FILE]...

DESCRIPTION
    List information about the FILE(s), or the current directory

OPTIONS
    -h
        with -l, print human readable sizes
    --help
        display this help and exit
    -l
        use a long listing format
"#; /* @MANEND */

fn list_dir(path: &str, long_format: bool, human_readable: bool, string: &mut String, stderr: &mut Stderr) {
    let metadata = fs::metadata(path).try(stderr);
    if metadata.is_dir() {
        let read_dir = Path::new(path).read_dir().try(stderr);

        let mut entries: Vec<String> = read_dir.filter_map(|x| x.ok()).map(|dir| {
                let mut file_name = dir.file_name().to_string_lossy().into_owned();
                if dir.file_type().try(stderr).is_dir() {
                    file_name.push('/');
                }
                file_name
            })
            .collect();

        entries.sort();

        for entry in entries.iter() {
            if long_format {
                let mut entry_path = path.to_owned();
                if !entry_path.ends_with('/') {
                    entry_path.push('/');
                }
                entry_path.push_str(&entry);

                let metadata = fs::metadata(entry_path).try(stderr);
                string.push_str(&format!("{:>7o} {:>5} {:>5} ",
                                         metadata.mode(),
                                         metadata.uid(),
                                         metadata.gid()));
                if human_readable {
                    string.push_str(&format!("{:>6} ", to_human_readable_string(metadata.size())));
                } else {
                    string.push_str(&format!("{:>8} ", metadata.size()));
                }
            }
            string.push_str(entry);
            string.push('\n');
        }
    } else {
        if long_format {
            string.push_str(&format!("{:>7o} {:>5} {:>5} ",
                                     metadata.mode(),
                                     metadata.uid(),
                                     metadata.gid()));
             if human_readable {
                 string.push_str(&format!("{:>6} ", to_human_readable_string(metadata.size())));
             } else {
                 string.push_str(&format!("{:>8} ", metadata.size()));
             }
        }
        string.push_str(path);
        string.push('\n');
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    let mut long_format = false;
    let mut human_readable = false;
    let mut args = Vec::new();
    for arg in env::args().skip(1) {
        if arg.as_str() == "--help" {
            stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
            stdout.flush().try(&mut stderr);
            exit(0);
        } else if arg.as_str() == "-l" {
            long_format = true;
        } else if arg.as_str() == "-h" {
            human_readable = true;
        } else {
            args.push(arg);
        }
    }

    let mut string = String::new();
    if args.is_empty() {
        list_dir(".", long_format, human_readable, &mut string, &mut stderr);
    } else {
        for dir in args {
            list_dir(&dir, long_format, human_readable, &mut string, &mut stderr);
        }
    }
    stdout.write(string.as_bytes()).try(&mut stderr);
}

#[test]
fn test_human_readable() {
    assert_eq!(to_human_readable_string(0), "0");
    assert_eq!(to_human_readable_string(1023), "1023");
    assert_eq!(to_human_readable_string(1024), "1.0K");
    assert_eq!(to_human_readable_string(1024 + 100), "1.1K");
    assert_eq!(to_human_readable_string(1024u64.pow(2) * 2), "2.0M");
    assert_eq!(to_human_readable_string(1024u64.pow(3) * 3), "3.0G");
    assert_eq!(to_human_readable_string(1024u64.pow(4) * 4), "4.0T");
    assert_eq!(to_human_readable_string(1024u64.pow(5) * 5), "5.0P");
    assert_eq!(to_human_readable_string(1024u64.pow(6) * 6), "6.0E");
}
<commit_msg>Implement a Flags struct to manage flags in one type & Move help arg parsing into `list_dir()` call & Reorganize arg parsing with match & support `--human-readable` flag<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::fs;
use std::path::Path;
use std::io::{stdout, stderr, StdoutLock, Stderr, Write};
use std::os::unix::fs::MetadataExt;
use std::process::exit;

use coreutils::to_human_readable_string;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{ls} */ r#"
NAME
    ls - list directory contents

SYNOPSIS
    ls [ -h | --help | -l ][FILE]...

DESCRIPTION
    List information about the FILE(s), or the current directory

OPTIONS
    -h
    --human-readable
        with -l, print human readable sizes
    --help
        display this help and exit
    -l
        use a long listing format
"#; /* @MANEND */

#[derive(Copy, Clone, Debug, Default)]
struct Flags {
    long_format: bool,
    help: bool,
    human_readable: bool,
}

fn list_dir(path: &str, flags: Flags, string: &mut String, stdout: &mut StdoutLock, stderr: &mut Stderr) {
    if flags.help {
        stdout.write(MAN_PAGE.as_bytes()).try(stderr);
        stdout.flush().try(stderr);
        exit(0);
    }

    let metadata = fs::metadata(path).try(stderr);
    if metadata.is_dir() {
        let read_dir = Path::new(path).read_dir().try(stderr);

        let mut entries: Vec<String> = read_dir.filter_map(|x| x.ok()).map(|dir| {
                let mut file_name = dir.file_name().to_string_lossy().into_owned();
                if dir.file_type().try(stderr).is_dir() {
                    file_name.push('/');
                }
                file_name
            })
            .collect();

        entries.sort();

        for entry in entries.iter() {
            if flags.long_format {
                let mut entry_path = path.to_owned();
                if !entry_path.ends_with('/') {
                    entry_path.push('/');
                }
                entry_path.push_str(&entry);

                let metadata = fs::metadata(entry_path).try(stderr);
                string.push_str(&format!("{:>7o} {:>5} {:>5} ",
                                         metadata.mode(),
                                         metadata.uid(),
                                         metadata.gid()));
                if flags.human_readable {
                    string.push_str(&format!("{:>6} ", to_human_readable_string(metadata.size())));
                } else {
                    string.push_str(&format!("{:>8} ", metadata.size()));
                }
            }
            string.push_str(entry);
            string.push('\n');
        }
    } else {
        if flags.long_format {
            string.push_str(&format!("{:>7o} {:>5} {:>5} ",
                                     metadata.mode(),
                                     metadata.uid(),
                                     metadata.gid()));
             if flags.human_readable {
                 string.push_str(&format!("{:>6} ", to_human_readable_string(metadata.size())));
             } else {
                 string.push_str(&format!("{:>8} ", metadata.size()));
             }
        }
        string.push_str(path);
        string.push('\n');
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    let mut flags = Flags::default();
    let mut dirs = Vec::new();
    for arg in env::args().skip(1) {
        if arg.starts_with("-") {
            match arg.as_str() {
                "--help" => flags.help = true,
                "-l" => flags.long_format = true,
                "-h" | "--human-readable" => flags.human_readable = true,
                _ => (),
            }
        } else {
            dirs.push(arg);
        }
    }

    let mut string = String::new();
    if dirs.is_empty() {
        list_dir(".", flags, &mut string, &mut stdout, &mut stderr);
    } else {
        for dir in dirs {
            list_dir(&dir, flags, &mut string, &mut stdout, &mut stderr);
        }
    }
    stdout.write(string.as_bytes()).try(&mut stderr);
}

#[test]
fn test_human_readable() {
    assert_eq!(to_human_readable_string(0), "0");
    assert_eq!(to_human_readable_string(1023), "1023");
    assert_eq!(to_human_readable_string(1024), "1.0K");
    assert_eq!(to_human_readable_string(1024 + 100), "1.1K");
    assert_eq!(to_human_readable_string(1024u64.pow(2) * 2), "2.0M");
    assert_eq!(to_human_readable_string(1024u64.pow(3) * 3), "3.0G");
    assert_eq!(to_human_readable_string(1024u64.pow(4) * 4), "4.0T");
    assert_eq!(to_human_readable_string(1024u64.pow(5) * 5), "5.0P");
    assert_eq!(to_human_readable_string(1024u64.pow(6) * 6), "6.0E");
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use irc;
use matrix;
use irc::protocol::{Command,Message};
use irc::streams::AsEvented;
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;
use std::io;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::model::RoomID, Room>,
    seen_events: Vec<matrix::model::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!("Got a really weird Token in the mio event loop!")
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                match self.handle_matrix(e) {
                    Err(err) => warn!("Could not handle matrix event: {:?}", err),
                    _ => ()
                }
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::model::RoomID,
    irc_name: Option<String>,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::model::UserID>,
    aliases: Vec<String>,
    pending_events: Vec<matrix::events::RoomEvent>,
    pending_sync: bool
}

impl Room {
    fn handle_part<F>(&mut self, user: matrix::model::UserID, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {

        if self.irc_name != None && self.members.contains(&user) {
            callback(irc::protocol::Message {
                prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                command: irc::protocol::Command::Part,
                args: vec![self.irc_name.clone().unwrap()],
                suffix: None
            });
        }

        match self.members.iter().position(|u| u == &user) {
            Some(idx) => {
                self.members.remove(idx);
            },
            None => ()
        }
    }

    fn handle_join<F>(&mut self, user: matrix::model::UserID, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.irc_name != None && !self.members.contains(&user) {
            callback(irc::protocol::Message {
                prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                command: irc::protocol::Command::Join,
                args: vec![self.irc_name.clone().unwrap()],
                suffix: None
            });
        }
        self.members.push(user);
    }

    fn new(id: matrix::model::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![],
            aliases: vec![],
            pending_sync: true,
            irc_name: None
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        assert!(self.pending_sync);
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    pub fn finish_sync<F>(&mut self, my_uid: &matrix::model::UserID, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        for a in &self.aliases {
            if a.ends_with(format!(":{}", my_uid.homeserver).trim()) {
                self.irc_name = Some(a.clone());
                break;
            }
        }
        if self.irc_name == None {
            self.irc_name = match self.canonical_alias {
                None => {
                    if self.aliases.len() == 0 {
                        Some(format!("#{}:{}", self.id.id, self.id.homeserver))
                    } else {
                        Some(self.aliases[0].clone())
                    }
                },
                Some(ref a) => Some(a.clone())
            }
        }
        callback(irc::protocol::Message {
            prefix: Some(format!("{}!{}@{}", my_uid.nickname, my_uid.nickname, my_uid.homeserver)),
            command: irc::protocol::Command::Join,
            args: vec![self.irc_name.clone().unwrap()],
            suffix: None
        });
        let mut usernames: Vec<String> = vec![];
        for u in &self.members {
            usernames.push(format!("{}", u.nickname));
        }
        callback(irc::protocol::Message {
            prefix: Some("pto".to_string()),
            command: irc::protocol::Command::Numeric(353),
            args: vec![my_uid.nickname.clone(), "@".to_string(), self.irc_name.clone().unwrap()],
            suffix: Some(usernames.join(" "))
        });

        self.run_pending(callback);
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.irc_name != None {
            match evt {
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.irc_name.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.irc_name.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                self.canonical_alias = Some(name.clone());
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) =>
                self.aliases = aliases,
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                self.handle_join(user, &mut callback);
            },
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                self.handle_part(user, &mut callback);
            },
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::model::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!("Couldn't find the room that we just created")
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> Option<&mut Room> {
        let mut room_id: Option<matrix::model::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.irc_name {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        match room_id {
            Some(id) => Some(self.room_from_matrix(&id)),
            None => None
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.as_evented(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn finish_sync<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        for (_, mut room) in &mut self.rooms {
            room.finish_sync(&self.matrix.uid.as_ref().unwrap(), callback);
        }
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) -> io::Result<usize> {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let mut append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    matrix::events::EventData::EndOfSync => self.finish_sync(&mut append_msg),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            let mut res: Option<io::Result<usize>> = None;
            for ref msg in messages {
                res = Some(match res {
                    None => self.client.send(msg),
                    Some(r) => r.and(self.client.send(msg))
                })
            }
            match res {
                None => Ok(0),
                Some(e) => e
            }
        } else {
            Ok(0)
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync().and_then(|events| {
            for e in events {
                match self.handle_matrix(e) {
                    // FIXME: Return error
                    Err(err) => warn!("Could not handle matrix event: {:?}", err),
                    _ => ()
                }
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            let nickname = match message.suffix {
                                None => message.args[0].clone(),
                                Some(n) => n
                            };
                            self.client.set_nickname(nickname)
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and_then(|_| {
                                            self.start_matrix(events.channel())
                                        })
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing, and anonymous access isn't built yet.")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let room_id = match self.room_from_irc(&message.args[0]) {
                                None => return (),
                                Some(room) => room.id.clone()
                            };
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                matrix::events::EventData::Room(
                                    room_id,
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>Fix privacy warnings.<commit_after>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use irc;
use matrix;
use irc::protocol::{Command,Message};
use irc::streams::AsEvented;
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;
use std::io;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::model::RoomID, Room>,
    seen_events: Vec<matrix::model::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!("Got a really weird Token in the mio event loop!")
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                match self.handle_matrix(e) {
                    Err(err) => warn!("Could not handle matrix event: {:?}", err),
                    _ => ()
                }
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::model::RoomID,
    irc_name: Option<String>,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::model::UserID>,
    aliases: Vec<String>,
    pending_events: Vec<matrix::events::RoomEvent>,
    pending_sync: bool
}

impl Room {
    fn handle_part<F>(&mut self, user: matrix::model::UserID, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {

        if self.irc_name != None && self.members.contains(&user) {
            callback(irc::protocol::Message {
                prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                command: irc::protocol::Command::Part,
                args: vec![self.irc_name.clone().unwrap()],
                suffix: None
            });
        }

        match self.members.iter().position(|u| u == &user) {
            Some(idx) => {
                self.members.remove(idx);
            },
            None => ()
        }
    }

    fn handle_join<F>(&mut self, user: matrix::model::UserID, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.irc_name != None && !self.members.contains(&user) {
            callback(irc::protocol::Message {
                prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                command: irc::protocol::Command::Join,
                args: vec![self.irc_name.clone().unwrap()],
                suffix: None
            });
        }
        self.members.push(user);
    }

    fn new(id: matrix::model::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![],
            aliases: vec![],
            pending_sync: true,
            irc_name: None
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        assert!(self.pending_sync);
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    pub fn finish_sync<F>(&mut self, my_uid: &matrix::model::UserID, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        for a in &self.aliases {
            if a.ends_with(format!(":{}", my_uid.homeserver).trim()) {
                self.irc_name = Some(a.clone());
                break;
            }
        }
        if self.irc_name == None {
            self.irc_name = match self.canonical_alias {
                None => {
                    if self.aliases.len() == 0 {
                        Some(format!("#{}:{}", self.id.id, self.id.homeserver))
                    } else {
                        Some(self.aliases[0].clone())
                    }
                },
                Some(ref a) => Some(a.clone())
            }
        }
        callback(irc::protocol::Message {
            prefix: Some(format!("{}!{}@{}", my_uid.nickname, my_uid.nickname, my_uid.homeserver)),
            command: irc::protocol::Command::Join,
            args: vec![self.irc_name.clone().unwrap()],
            suffix: None
        });
        let mut usernames: Vec<String> = vec![];
        for u in &self.members {
            usernames.push(format!("{}", u.nickname));
        }
        callback(irc::protocol::Message {
            prefix: Some("pto".to_string()),
            command: irc::protocol::Command::Numeric(353),
            args: vec![my_uid.nickname.clone(), "@".to_string(), self.irc_name.clone().unwrap()],
            suffix: Some(usernames.join(" "))
        });

        self.run_pending(callback);
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.irc_name != None {
            match evt {
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.irc_name.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.irc_name.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                self.canonical_alias = Some(name.clone());
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) =>
                self.aliases = aliases,
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                self.handle_join(user, &mut callback);
            },
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                self.handle_part(user, &mut callback);
            },
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    fn room_from_matrix(&mut self, id: &matrix::model::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!("Couldn't find the room that we just created")
        }
    }

    fn room_from_irc(&mut self, id: &String) -> Option<&mut Room> {
        let mut room_id: Option<matrix::model::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.irc_name {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        match room_id {
            Some(id) => Some(self.room_from_matrix(&id)),
            None => None
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.as_evented(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn finish_sync<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        for (_, mut room) in &mut self.rooms {
            room.finish_sync(&self.matrix.uid.as_ref().unwrap(), callback);
        }
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) -> io::Result<usize> {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let mut append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    matrix::events::EventData::EndOfSync => self.finish_sync(&mut append_msg),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            let mut res: Option<io::Result<usize>> = None;
            for ref msg in messages {
                res = Some(match res {
                    None => self.client.send(msg),
                    Some(r) => r.and(self.client.send(msg))
                })
            }
            match res {
                None => Ok(0),
                Some(e) => e
            }
        } else {
            Ok(0)
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync().and_then(|events| {
            for e in events {
                match self.handle_matrix(e) {
                    // FIXME: Return error
                    Err(err) => warn!("Could not handle matrix event: {:?}", err),
                    _ => ()
                }
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            let nickname = match message.suffix {
                                None => message.args[0].clone(),
                                Some(n) => n
                            };
                            self.client.set_nickname(nickname)
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and_then(|_| {
                                            self.start_matrix(events.channel())
                                        })
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing, and anonymous access isn't built yet.")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let room_id = match self.room_from_irc(&message.args[0]) {
                                None => return (),
                                Some(room) => room.id.clone()
                            };
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                matrix::events::EventData::Room(
                                    room_id,
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>use hyper::Client;
use hyper::client::Body;

use serde_json::{to_string, from_reader, Map, Value};

use errors::HueError;
use ::hue::*;

/// Attempt to discover bridges using `https://www.meethue.com/api/nupnp`
pub fn discover() -> Result<Vec<Discovery>, HueError> {
    Client::new()
        .get("https://www.meethue.com/api/nupnp")
        .send()
        .map_err(HueError::from)
        .and_then(|ref mut r| from_reader(r).map_err(From::from))
}

/// Tries to register a user, returning the username if successful
///
/// This usually returns a `HueError::BridgeError` saying the link button needs to be pressed.
/// Therefore it recommended to call this function in a loop:
/// ## Example
/// ```no_run
/// use philipshue::errors::{HueError, BridgeError};
/// use philipshue::bridge::{self, Bridge};
///
/// let mut bridge = None;
/// // Discover a bridge
/// let bridge_ip = philipshue::bridge::discover().unwrap().pop().unwrap().into_ip();
/// let devicetype = "my_hue_app#homepc";
///
/// // Keep trying to register a user
/// loop{
///     match bridge::register_user(&bridge_ip, devicetype){
///         // A new user has succesfully been registered and the username is returned
///         Ok(username) => {
///             bridge = Some(Bridge::new(bridge_ip, username));
///             break;
///         },
///         // Prompt the user to press the link button
///         Err(HueError::BridgeError{error: BridgeError::LinkButtonNotPressed, ..}) => {
///             println!("Please, press the link on the bridge. Retrying in 5 seconds");
///             std::thread::sleep(std::time::Duration::from_secs(5));
///         },
///         // Some other error happened
///         Err(e) => {
///             println!("Unexpected error occured: {:?}", e);
///             break
///         }
///     }
/// }
/// ```
pub fn register_user(ip: &str, devicetype: &str) -> Result<String, HueError>{
    let client = Client::new();

    let body = format!("{{\"devicetype\": {:?}}}", devicetype);
    let body = body.as_bytes();
    let url = format!("http://{}/api", ip);
    let mut resp = try!(client.post(&url)
        .body(Body::BufBody(body, body.len()))
        .send());

    let rur = try!(from_reader::<_, Vec<HueResponse<User>>>(&mut resp)).pop().unwrap();

    if let Some(User{username}) = rur.success{
        Ok(username)
    }else if let Some(error) = rur.error{
        Err(error.into())
    }else{
        Err(HueError::MalformedResponse)
    }
}

#[derive(Debug, Clone)]
/// A light with an ID
pub struct IdentifiedLight {
    /// The ID number of this light
    pub id: usize,
    /// The light object
    pub light: Light,
}

#[derive(Debug)]
/// The bridge connection
pub struct Bridge {
    client: Client,
    url: String
}

fn send_with_body<'a, T: Deserialize>(rb: RequestBuilder<'a>, body: &'a str) -> Result<T, HueError> {
    send(rb.body(Body::BufBody(body.as_bytes(), body.len())))
}

fn send<T: Deserialize>(rb: RequestBuilder) -> Result<T, HueError> {
    rb.send()
      .map_err(HueError::from)
      .and_then(|ref mut resp| from_reader::<_, T>(resp).map_err(From::from))
}

#[test]
fn get_ip_and_username() {
    let b = Bridge::new("test", "hello");
    assert_eq!(b.get_ip(), "test");
    assert_eq!(b.get_username(), "hello");
}

use serde::Deserialize;
use hyper::client::RequestBuilder;
use ::clean::clean_json;

impl Bridge {
    /// Creates a `Bridge` on the given IP with the given username
    pub fn new<S: Into<String>, U: Into<String>>(ip: S, username: U) -> Self{
        Bridge{
            client: Client::new(),
            url: format!("http://{}/api/{}/", ip.into(), username.into())
        }
    }
    /// Gets the IP of bridge
    pub fn get_ip(&self) -> &str{
        self.url.split('/').nth(2).unwrap()
    }
    /// Gets the username this `Bridge` uses
    pub fn get_username(&self) -> &str{
        self.url.split('/').nth(4).unwrap()
    }
    /// Gets all lights that are connected to the bridge
    pub fn get_all_lights(&self) -> Result<Map<usize, Light>, HueError> {
        send(self.client.get(&format!("{}lights", self.url)))
    }
    /// Gets the light with the specific id
    pub fn get_light(&self, id: usize) -> Result<Light, HueError> {
        send(self.client.get(&format!("{}lights/{}", self.url, id)))
    }
    /// Gets all the light that were found last time a search for new lights was done
    pub fn get_new_lights(&self) -> Result<Map<usize, Light>, HueError> {
        // TODO return lastscan too
        send(self.client.get(&format!("{}lights/new", self.url)))
    }
    /// Makes the bridge search for new lights (and switches).
    ///
    /// The found lights can be retrieved with `get_new_lights()`
    pub fn search_for_new_lights(&self) -> Result<(), HueError> {
        // TODO Allow deviceids to be specified
        send(self.client.post(&format!("{}lights", self.url)))
    }
    /// Sets the state of a light by sending a `LightCommand` to the bridge for this light
    pub fn set_light_state(&self, id: usize, command: LightCommand) -> Result<Vec<HueResponse<Value>>, HueError>{
        send_with_body(self.client.put(&format!("{}lights/{}/state", self.url, id)), &clean_json(to_string(&command)?))
    }
    /// Renames the light
    pub fn rename_light(&self, id: usize, name: String) -> Result<(), HueError> {
        let mut name_map = Map::new();
        name_map.insert("name".to_owned(), name);
        send_with_body(self.client.put(&format!("{}lights/{}", self.url, id)), &clean_json(to_string(&name_map)?))
    }
    /// Deletes a light from the bridge
    pub fn delete_light(&self, id: usize) -> Result<(), HueError> {
        send(self.client.delete(&format!("{}lights/{}", self.url, id)))
    }
}
<commit_msg>Fix some bridge functions<commit_after>use hyper::Client;
use hyper::client::Body;

use serde_json::{to_string, from_reader, Map, Value};

use errors::HueError;
use ::hue::*;

/// Attempt to discover bridges using `https://www.meethue.com/api/nupnp`
pub fn discover() -> Result<Vec<Discovery>, HueError> {
    Client::new()
        .get("https://www.meethue.com/api/nupnp")
        .send()
        .map_err(HueError::from)
        .and_then(|ref mut r| from_reader(r).map_err(From::from))
}

/// Tries to register a user, returning the username if successful
///
/// This usually returns a `HueError::BridgeError` saying the link button needs to be pressed.
/// Therefore it recommended to call this function in a loop:
/// ## Example
/// ```no_run
/// use philipshue::errors::{HueError, BridgeError};
/// use philipshue::bridge::{self, Bridge};
///
/// let mut bridge = None;
/// // Discover a bridge
/// let bridge_ip = philipshue::bridge::discover().unwrap().pop().unwrap().into_ip();
/// let devicetype = "my_hue_app#homepc";
///
/// // Keep trying to register a user
/// loop{
///     match bridge::register_user(&bridge_ip, devicetype){
///         // A new user has succesfully been registered and the username is returned
///         Ok(username) => {
///             bridge = Some(Bridge::new(bridge_ip, username));
///             break;
///         },
///         // Prompt the user to press the link button
///         Err(HueError::BridgeError{error: BridgeError::LinkButtonNotPressed, ..}) => {
///             println!("Please, press the link on the bridge. Retrying in 5 seconds");
///             std::thread::sleep(std::time::Duration::from_secs(5));
///         },
///         // Some other error happened
///         Err(e) => {
///             println!("Unexpected error occured: {:?}", e);
///             break
///         }
///     }
/// }
/// ```
pub fn register_user(ip: &str, devicetype: &str) -> Result<String, HueError>{
    let client = Client::new();

    let body = format!("{{\"devicetype\": {:?}}}", devicetype);
    let body = body.as_bytes();
    let url = format!("http://{}/api", ip);
    let mut resp = try!(client.post(&url)
        .body(Body::BufBody(body, body.len()))
        .send());

    let rur = try!(from_reader::<_, Vec<HueResponse<User>>>(&mut resp)).pop().unwrap();

    if let Some(User{username}) = rur.success{
        Ok(username)
    }else if let Some(error) = rur.error{
        Err(error.into())
    }else{
        Err(HueError::MalformedResponse)
    }
}

#[derive(Debug, Clone)]
/// A light with an ID
pub struct IdentifiedLight {
    /// The ID number of this light
    pub id: usize,
    /// The light object
    pub light: Light,
}

#[derive(Debug)]
/// The bridge connection
pub struct Bridge {
    client: Client,
    url: String
}

fn send_with_body<'a, T: Deserialize>(rb: RequestBuilder<'a>, body: &'a str) -> Result<T, HueError> {
    send(rb.body(Body::BufBody(body.as_bytes(), body.len())))
}

fn send<T: Deserialize>(rb: RequestBuilder) -> Result<T, HueError> {
    rb.send()
      .map_err(HueError::from)
      .and_then(|ref mut resp| from_reader::<_, T>(resp).map_err(From::from))
}

#[test]
fn get_ip_and_username() {
    let b = Bridge::new("test", "hello");
    assert_eq!(b.get_ip(), "test");
    assert_eq!(b.get_username(), "hello");
}

use serde::Deserialize;
use hyper::client::RequestBuilder;
use ::clean::clean_json;

impl Bridge {
    /// Creates a `Bridge` on the given IP with the given username
    pub fn new<S: Into<String>, U: Into<String>>(ip: S, username: U) -> Self{
        Bridge{
            client: Client::new(),
            url: format!("http://{}/api/{}/", ip.into(), username.into())
        }
    }
    /// Gets the IP of bridge
    pub fn get_ip(&self) -> &str{
        self.url.split('/').nth(2).unwrap()
    }
    /// Gets the username this `Bridge` uses
    pub fn get_username(&self) -> &str{
        self.url.split('/').nth(4).unwrap()
    }
    /// Gets all lights that are connected to the bridge
    pub fn get_all_lights(&self) -> Result<Map<usize, Light>, HueError> {
        send(self.client.get(&format!("{}lights", self.url)))
    }
    /// Gets the light with the specific id
    pub fn get_light(&self, id: usize) -> Result<Light, HueError> {
        send(self.client.get(&format!("{}lights/{}", self.url, id)))
    }
    /// Gets all the light that were found last time a search for new lights was done
    pub fn get_new_lights(&self) -> Result<Map<usize, Light>, HueError> {
        // TODO return lastscan too
        send(self.client.get(&format!("{}lights/new", self.url)))
    }
    /// Makes the bridge search for new lights (and switches).
    ///
    /// The found lights can be retrieved with `get_new_lights()`
    pub fn search_for_new_lights(&self) -> Result<Vec<HueResponse<Value>>, HueError> {
        // TODO Allow deviceids to be specified
        send(self.client.post(&format!("{}lights", self.url)))
    }
    /// Sets the state of a light by sending a `LightCommand` to the bridge for this light
    pub fn set_light_state(&self, id: usize, command: LightCommand) -> Result<Vec<HueResponse<Value>>, HueError>{
        send_with_body(self.client.put(&format!("{}lights/{}/state", self.url, id)), &clean_json(to_string(&command)?))
    }
    /// Renames the light
    pub fn rename_light(&self, id: usize, name: String) -> Result<Vec<HueResponse<Value>>, HueError> {
        let mut name_map = Map::new();
        name_map.insert("name".to_owned(), name);
        send_with_body(self.client.put(&format!("{}lights/{}", self.url, id)), &clean_json(to_string(&name_map)?))
    }
    /// Deletes a light from the bridge
    pub fn delete_light(&self, id: usize) -> Result<Vec<HueResponse<Value>>, HueError> {
        send(self.client.delete(&format!("{}lights/{}", self.url, id)))
    }
}
<|endoftext|>


<commit_before>use luminance::M44;
use nalgebra::{Quaternion, Rotate, ToHomogeneous, Unit, UnitQuaternion, Vector3};
use std::default::Default;
use std::f32::consts::FRAC_PI_4;

use projection::{Projectable, perspective};
use transform::{Axis, Orientation, Transformable, Translation, X_AXIS, Y_AXIS, Z_AXIS,
                translation_matrix};

pub struct Camera<P> {
  position: Translation,
  orientation: Orientation,
  properties: P
}

impl<P> Camera<P> {
  pub fn new(position: Translation, orientation: Orientation, properties: P) -> Self {
    Camera {
      position: position,
      orientation: orientation,
      properties: properties
    }
  }
}

impl<P> Default for Camera<P> where P: Default {
  fn default() -> Self {
    Camera::new(Translation::new(0., 0., 0.),
                Orientation::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
                P::default())
  }
}

impl<P> Transformable for Camera<P> {
  fn transform(&self) -> M44 {
    let m = self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(self.position);
    m.as_ref().clone()
  }
}

pub struct Freefly {
  // sensitivities
  pub yaw_sens: f32,
  pub pitch_sens: f32,
  pub roll_sens: f32,
  pub forward_sens: f32,
  pub strafe_sens: f32,
  pub upward_sens: f32,
  // projection
  pub ratio: f32,
  pub fovy: f32,
  // clipping
  pub znear: f32,
  pub zfar: f32,
}

impl Freefly {
  pub fn new() -> Self {
    Freefly {
      yaw_sens: 0.01,
      pitch_sens: 0.01,
      roll_sens: 0.01,
      forward_sens: 0.1,
      strafe_sens: 0.1,
      upward_sens: 0.1,
      ratio: 4. / 3.,
      fovy: FRAC_PI_4,
      znear: 0.1,
      zfar: 10.,
    }
  }
}

impl Default for Freefly {
  fn default() -> Self {
    Self::new()
  }
}

impl Projectable for Freefly {
  fn projection(&self) -> M44 {
    perspective(self.ratio, self.fovy, self.znear, self.zfar)
  }
}

impl Camera<Freefly> {
  pub fn mv(&mut self, dir: Translation) {
    let p = &self.properties;
    let axis = dir * Axis::new(p.strafe_sens, p.upward_sens, p.forward_sens);
    let v = self.orientation.inverse_rotate(&axis);

    self.position -= v;
  }

  pub fn look_around(&mut self, dir: Translation) {
    let p = &self.properties;

    fn orient(axis: &Axis, phi: f32) -> Orientation {
      UnitQuaternion::from_axisangle(Unit::new(&axis), phi)
    }

    self.orientation = orient(&Y_AXIS, p.yaw_sens * dir.y) * self.orientation;
    self.orientation = orient(&X_AXIS, p.pitch_sens * dir.x) * self.orientation;
    self.orientation = orient(&Z_AXIS, p.roll_sens * dir.z) * self.orientation;
  }
}
<commit_msg>Fixed Translation -> Position in camera.rs.<commit_after>use luminance::M44;
use nalgebra::{Quaternion, Rotate, ToHomogeneous, Unit, UnitQuaternion, Vector3};
use std::default::Default;
use std::f32::consts::FRAC_PI_4;

use projection::{Projectable, perspective};
use transform::{Axis, Orientation, Position, Transformable, Translation, X_AXIS, Y_AXIS, Z_AXIS,
                translation_matrix};

pub struct Camera<P> {
  position: Position,
  orientation: Orientation,
  properties: P
}

impl<P> Camera<P> {
  pub fn new(position: Position, orientation: Orientation, properties: P) -> Self {
    Camera {
      position: position,
      orientation: orientation,
      properties: properties
    }
  }
}

impl<P> Default for Camera<P> where P: Default {
  fn default() -> Self {
    Camera::new(Position::new(0., 0., 0.),
                Orientation::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
                P::default())
  }
}

impl<P> Transformable for Camera<P> {
  fn transform(&self) -> M44 {
    let m = self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(-self.position);
    m.as_ref().clone()
  }
}

pub struct Freefly {
  // sensitivities
  pub yaw_sens: f32,
  pub pitch_sens: f32,
  pub roll_sens: f32,
  pub forward_sens: f32,
  pub strafe_sens: f32,
  pub upward_sens: f32,
  // projection
  pub ratio: f32,
  pub fovy: f32,
  // clipping
  pub znear: f32,
  pub zfar: f32,
}

impl Freefly {
  pub fn new() -> Self {
    Freefly {
      yaw_sens: 0.01,
      pitch_sens: 0.01,
      roll_sens: 0.01,
      forward_sens: 0.1,
      strafe_sens: 0.1,
      upward_sens: 0.1,
      ratio: 4. / 3.,
      fovy: FRAC_PI_4,
      znear: 0.1,
      zfar: 10.,
    }
  }
}

impl Default for Freefly {
  fn default() -> Self {
    Self::new()
  }
}

impl Projectable for Freefly {
  fn projection(&self) -> M44 {
    perspective(self.ratio, self.fovy, self.znear, self.zfar)
  }
}

impl Camera<Freefly> {
  pub fn mv(&mut self, dir: Translation) {
    let p = &self.properties;
    let axis = dir * Axis::new(p.strafe_sens, p.upward_sens, p.forward_sens);
    let v = self.orientation.inverse_rotate(&axis);

    self.position -= v;
  }

  pub fn look_around(&mut self, dir: Translation) {
    let p = &self.properties;

    fn orient(axis: &Axis, phi: f32) -> Orientation {
      UnitQuaternion::from_axisangle(Unit::new(&axis), phi)
    }

    self.orientation = orient(&Y_AXIS, p.yaw_sens * dir.y) * self.orientation;
    self.orientation = orient(&X_AXIS, p.pitch_sens * dir.x) * self.orientation;
    self.orientation = orient(&Z_AXIS, p.roll_sens * dir.z) * self.orientation;
  }
}
<|endoftext|>


<commit_before>use libc::{uint32_t, c_void};

use sys::timer as ll;

pub fn get_ticks() -> u32 {
    unsafe { ll::SDL_GetTicks() }
}

pub fn get_performance_counter() -> u64 {
    unsafe { ll::SDL_GetPerformanceCounter() }
}

pub fn get_performance_frequency() -> u64 {
    unsafe { ll::SDL_GetPerformanceFrequency() }
}

pub fn delay(ms: u32) {
    unsafe { ll::SDL_Delay(ms) }
}

pub type TimerCallback = extern "C" fn (interval: uint32_t, param: *const c_void) -> u32;

pub struct Timer {
    delay: usize,
    raw: ll::SDL_TimerID,
    callback: TimerCallback,
    param: *const c_void,
    remove_on_drop: bool,
}

impl Timer {
    pub fn new(delay: usize, callback: TimerCallback, param: *const c_void, remove_on_drop: bool) -> Timer {
        Timer { delay: delay, raw: 0, callback: callback, param: param, remove_on_drop: remove_on_drop }
    }

    pub fn start(&mut self) {
        unsafe {
            let timer_id = ll::SDL_AddTimer(self.delay as u32, Some(self.callback), self.param);
            self.raw = timer_id;
        }
    }

    pub fn remove(&mut self) -> bool {
        let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
        if self.raw != 0 {
            self.raw = 0
        }
        ret == 1
    }
}

#[unsafe_destructor]
impl Drop for Timer {
    fn drop(&mut self) {
        if self.remove_on_drop {
            let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
            if ret != 1 {
                println!("error dropping timer {}, maybe already removed.", self.raw);
            }
        }
    }
}

#[cfg(test)]
extern "C" fn test_timer_1_callback(_interval: uint32_t, param: *const c_void) -> uint32_t {
    use std::sync::{Arc, Mutex};
    use std::mem;

    let locked_num: &Arc<Mutex<u32>> = unsafe { mem::transmute(param) };
    let mut num = locked_num.lock().unwrap();
    *num = *num + 1;
    10
}

#[test]
fn test_timer_1() {
    use std::sync::{Arc, Mutex};
    use std::mem;

    let local_num: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
    let timer_num = local_num.clone();

    let final_num = {
        let param = unsafe { mem::transmute(&timer_num) };
        let mut timer = Timer::new(10, test_timer_1_callback, param, true);
        timer.start();
        delay(500);
        let num = local_num.lock().unwrap();
        assert!(*num > 0);

        *num
    };

    // Check that timer has stopped
    delay(1000);
    let num = local_num.lock().unwrap();
    assert!(*num == final_num);
}

#[cfg(test)]
extern "C" fn test_timer_2_callback(_interval: uint32_t, _param: *const c_void) -> uint32_t {
    0
}

#[test]
fn test_timer_2() {
    use std::ptr;

    let _ = {
        let mut timer = Timer::new(1000, test_timer_2_callback, ptr::null(), true);
        timer.start();
        timer
    };
    delay(200);
    delay(200);
    delay(200);
    delay(200);
    delay(200);
    delay(200);
}
<commit_msg>Update `Timer` API for unboxed closures<commit_after>use libc::{uint32_t, c_void};
use std::mem;
use sys::timer as ll;

pub fn get_ticks() -> u32 {
    unsafe { ll::SDL_GetTicks() }
}

pub fn get_performance_counter() -> u64 {
    unsafe { ll::SDL_GetPerformanceCounter() }
}

pub fn get_performance_frequency() -> u64 {
    unsafe { ll::SDL_GetPerformanceFrequency() }
}

pub fn delay(ms: u32) {
    unsafe { ll::SDL_Delay(ms) }
}

pub struct Timer<F> {
    _callback: Box<F>,
    _delay: usize,
    raw: ll::SDL_TimerID,
}

impl<F> Timer<F> {
    #[unstable]
    /// Constructs a new timer using the boxed closure `callback`.
    /// The timer is started immediately, it will be cancelled either:
    ///   * when the timer is dropped
    ///   * or when the callback returns a non-positive continuation interval
    pub fn new(delay: usize, callback: Box<F>) -> Timer<F>
    where F: Fn() -> u32, F: Send {

        let timer = unsafe {
            let timer_id = ll::SDL_AddTimer(delay as u32,
                                            Some(c_timer_callback::<F>),
                                            mem::transmute_copy(&callback));

            Timer {
                _callback: callback,
                _delay: delay,
                raw: timer_id,
            }
        };

        return timer;
    }
}

#[unsafe_destructor]
impl<F> Drop for Timer<F> {
    fn drop(&mut self) {
        let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
        if ret != 1 {
            println!("error dropping timer {}, maybe already removed.", self.raw);
        }
    }
}

extern "C" fn c_timer_callback<F>(_interval: u32, param: *const c_void) -> uint32_t
where F: Fn() -> u32, F: Send {
    unsafe {
        let f: *const F = mem::transmute(param);
        (*f)() as uint32_t
    }
}

#[test]
fn test_timer_runs_multiple_times() {
    use std::sync::{Arc, Mutex};

    let local_num = Arc::new(Mutex::new(0));
    let timer_num = local_num.clone();

    let timer = Timer::new(100, Box::new(move|| {
        // increment up to 10 times (0 -> 9)
        // tick again in 100ms after each increment
        //
        let mut num = timer_num.lock().unwrap();
        if *num < 9 {
            *num += 1;
            100
        } else { 0 }
    }));

    delay(1200);                         // tick the timer at least 10 times w/ 200ms of "buffer"
    let num = local_num.lock().unwrap(); // read the number back
    assert_eq!(*num, 9);                 // it should have incremented at least 10 times...
}

#[test]
fn test_timer_runs_at_least_once() {
    use std::sync::{Arc, Mutex};

    let local_flag = Arc::new(Mutex::new(false));
    let timer_flag = local_flag.clone();

    let timer = Timer::new(500, Box::new(move|| {
        let mut flag = timer_flag.lock().unwrap();
        *flag = true; 0
    }));

    delay(700);
    let flag = local_flag.lock().unwrap();
    assert_eq!(*flag, true);
}
<|endoftext|>