<commit_before>use std::io::{BufferedReader, File, IoResult};

// http://www.midi.org/techspecs/midimessages.php
// http://www.ccarh.org/courses/253/handout/smf/
// http://www.ccarh.org/courses/253-2008/files/midifiles-20080227-2up.pdf

#[repr(u8)]
#[deriving(FromPrimitive, PartialEq, Copy, Show)]
pub enum MidiEventType {
    NoteOff = 0x8,
    NoteOn = 0x9,
    PolyponicKeyPressure = 0xa,
    ControlChange = 0xb,
    ProgramChange = 0xc,
    ChannelPressure = 0xd,
    PitchBendChange = 0xe,
    System = 0xf
}

#[repr(u8)]
#[deriving(FromPrimitive, PartialEq, Copy, Show)]
pub enum MidiSystemEventType {
    SequenceNumber = 0x00,
    TextEvent = 0x01,
    CopyrightNotice = 0x02,
    SequenceOrTrackName = 0x03,
    InstrumentName = 0x04,
    LyricText = 0x05,
    MarkerText = 0x06,
    CuePoint = 0x07,
    MidiChannelPrefixAssignment = 0x20,
    EndOfTrack = 0x2f,
    TempoSetting = 0x51,
    SmpteOffset = 0x54,
    TimeSignature = 0x58,
    SequencerSpecificEvent = 0x7f
}

#[deriving(Copy, Show)]
pub struct MidiEvent {
    pub message_type: MidiEventType,
    pub time: uint,
    pub channel: u8,
    pub value1: u8,
    pub value2: Option<u8>
}

#[deriving(Show)]
pub struct MidiTrack {
    pub messages: Vec<MidiEvent>
}

impl MidiTrack {
    fn new() -> MidiTrack {
        let messages: Vec<MidiEvent> = Vec::new();
        MidiTrack {
            messages: messages
        }
    }
}

#[deriving(Show)]
pub struct MidiSong {
    pub max_time: uint,
    pub time_unit: uint,
    pub tracks: Vec<MidiTrack>,
    pub track_count: uint
}

pub fn read_midi(filename: &str) -> IoResult<MidiSong> {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    // Header
    let _chunk_name = try!(file.read_be_u32()); // MThd
    let _chunk_size = try!(file.read_be_u32());
    let _file_format = try!(file.read_be_u16());
    let track_count = try!(file.read_be_u16());
    let time_division = try!(file.read_be_u16());

    if time_division & 0x8000 == 0 {
        // ticks per beat MIDI
    } else {
        // return Err("frames per second not supported");
        panic!("frames per second MIDI files are not supported")
    }

    let tracks: Vec<MidiTrack> = Vec::new();
    let mut song = MidiSong {
        max_time: 0,
        time_unit: time_division as uint,
        tracks: tracks,
        track_count: track_count as uint
    };

    // Track chunk
    let _track_chunk_name = try!(file.read_be_u32()); // MTrk
    let _track_chunk_size = try!(file.read_be_u32());

    // Track data
    let mut track = MidiTrack::new();
    let mut track_time = 0u;

    let mut keep_reading = true;

    while keep_reading {
        let delta_time = read_variable_number(&mut file).unwrap();
        track_time += delta_time;
        if track_time > song.max_time { song.max_time = track_time };

        let next_byte = try!(file.read_byte());
        let message_type: MidiEventType = FromPrimitive::from_u8(next_byte >> 4).unwrap();
        let channel = next_byte & 0b00001111;

        // TODO: use an enum for this
        match message_type {
            MidiEventType::NoteOff
            | MidiEventType::NoteOn
            | MidiEventType::PolyponicKeyPressure
            | MidiEventType::ControlChange
            | MidiEventType::PitchBendChange => {
                track.messages.push(MidiEvent {
                    message_type: message_type,
                    time: track_time,
                    channel: channel,
                    value1: try!(file.read_byte()),
                    value2: Some(try!(file.read_byte()))
                });
            },
            MidiEventType::ProgramChange
            | MidiEventType::ChannelPressure => {
                track.messages.push(MidiEvent {
                    message_type: message_type,
                    time: track_time,
                    channel: channel,
                    value1: try!(file.read_byte()),
                    value2: None
                });
            },
            MidiEventType::System => {
                let system_message_type = FromPrimitive::from_u8(try!(file.read_byte()));
                let system_data_size = try!(read_variable_number(&mut file));

                match system_message_type {
                    Some(MidiSystemEventType::EndOfTrack) => {
                        song.tracks.push(track);
                        track = MidiTrack::new();

                        let next_track_chunk_name = file.read_be_u32();
                        if next_track_chunk_name.is_ok() {
                            let _next_track_chunk_size = try!(file.read_be_u32());
                            track_time = 0u;
                        } else {
                            keep_reading = false;
                        }
                    },
                    None => {
                        // Discard unhandled system messages
                        try!(file.read_exact(system_data_size as uint));
                    }
                }
            }
        }
    }

    Ok(song)
}

fn read_variable_number<T>(reader: &mut T) -> IoResult<uint> where T: Reader {
    // http://en.wikipedia.org/wiki/Variable-length_quantity
    // cont. bit---V
    //             7[6 5 4 3 2 1 0]+-+
    // more bytes: 1 b b b b b b b   | concat bits to form new number
    //                               V
    //                             7[6 5 4 3 2 1 0]
    //              no more bytes: 0 b b b b b b b

    let mut octet = try!(reader.read_byte());
    let mut value = (octet & 0b01111111) as uint;
    while octet >= 0b10000000 {
        octet = try!(reader.read_byte());
        value = (value << 7) as uint + (octet & 0b01111111) as uint;
    }

    Ok(value)
}

#[test]
fn it_parses_a_midi_file() {
    let song = read_midi("tests/assets/test.mid").ok().expect("Failed");

    assert_eq!(song.tracks.len(), 2); // metadata track included
    let ref messages = song.tracks[1].messages;

    // ProgramChange
    assert_eq!(messages[0].message_type, MidiEventType::ProgramChange);
    assert_eq!(messages[0].time, 0);
    assert_eq!(messages[0].channel, 0);
    assert_eq!(messages[0].value1, 0);
    assert_eq!(messages[0].value2, None);

    // NoteOn
    assert_eq!(messages[1].message_type, MidiEventType::NoteOn);
    assert_eq!(messages[1].time, 0);
    assert_eq!(messages[1].channel, 0);
    assert_eq!(messages[1].value1, 57);
    assert_eq!(messages[1].value2, Some(64));

    // NoteOff
    assert_eq!(messages[2].message_type, MidiEventType::NoteOff);
    assert_eq!(messages[2].time, 960);
    assert_eq!(messages[2].channel, 0);
    assert_eq!(messages[2].value1, 57);
    assert_eq!(messages[2].value2, Some(0));
}

#[test]
fn it_parses_a_multitrack_midi_file() {
    let song = read_midi("tests/assets/multitrack.mid").unwrap();
    assert_eq!(song.tracks.len(), 3); // metadata track included
}
<commit_msg>Fix compilation error<commit_after>use std::io::{BufferedReader, File, IoResult};

// http://www.midi.org/techspecs/midimessages.php
// http://www.ccarh.org/courses/253/handout/smf/
// http://www.ccarh.org/courses/253-2008/files/midifiles-20080227-2up.pdf

#[repr(u8)]
#[deriving(FromPrimitive, PartialEq, Copy, Show)]
pub enum MidiEventType {
    NoteOff = 0x8,
    NoteOn = 0x9,
    PolyponicKeyPressure = 0xa,
    ControlChange = 0xb,
    ProgramChange = 0xc,
    ChannelPressure = 0xd,
    PitchBendChange = 0xe,
    System = 0xf
}

#[repr(u8)]
#[deriving(FromPrimitive, PartialEq, Copy, Show)]
pub enum MidiSystemEventType {
    SequenceNumber = 0x00,
    TextEvent = 0x01,
    CopyrightNotice = 0x02,
    SequenceOrTrackName = 0x03,
    InstrumentName = 0x04,
    LyricText = 0x05,
    MarkerText = 0x06,
    CuePoint = 0x07,
    MidiChannelPrefixAssignment = 0x20,
    EndOfTrack = 0x2f,
    TempoSetting = 0x51,
    SmpteOffset = 0x54,
    TimeSignature = 0x58,
    SequencerSpecificEvent = 0x7f
}

#[deriving(Copy, Show)]
pub struct MidiEvent {
    pub message_type: MidiEventType,
    pub time: uint,
    pub channel: u8,
    pub value1: u8,
    pub value2: Option<u8>
}

#[deriving(Show)]
pub struct MidiTrack {
    pub messages: Vec<MidiEvent>
}

impl MidiTrack {
    fn new() -> MidiTrack {
        let messages: Vec<MidiEvent> = Vec::new();
        MidiTrack {
            messages: messages
        }
    }
}

#[deriving(Show)]
pub struct MidiSong {
    pub max_time: uint,
    pub time_unit: uint,
    pub tracks: Vec<MidiTrack>,
    pub track_count: uint
}

pub fn read_midi(filename: &str) -> IoResult<MidiSong> {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    // Header
    let _chunk_name = try!(file.read_be_u32()); // MThd
    let _chunk_size = try!(file.read_be_u32());
    let _file_format = try!(file.read_be_u16());
    let track_count = try!(file.read_be_u16());
    let time_division = try!(file.read_be_u16());

    if time_division & 0x8000 == 0 {
        // ticks per beat MIDI
    } else {
        // return Err("frames per second not supported");
        panic!("frames per second MIDI files are not supported")
    }

    let tracks: Vec<MidiTrack> = Vec::new();
    let mut song = MidiSong {
        max_time: 0,
        time_unit: time_division as uint,
        tracks: tracks,
        track_count: track_count as uint
    };

    // Track chunk
    let _track_chunk_name = try!(file.read_be_u32()); // MTrk
    let _track_chunk_size = try!(file.read_be_u32());

    // Track data
    let mut track = MidiTrack::new();
    let mut track_time = 0u;

    let mut keep_reading = true;

    while keep_reading {
        let delta_time = read_variable_number(&mut file).unwrap();
        track_time += delta_time;
        if track_time > song.max_time { song.max_time = track_time };

        let next_byte = try!(file.read_byte());
        let message_type: MidiEventType = FromPrimitive::from_u8(next_byte >> 4).unwrap();
        let channel = next_byte & 0b00001111;

        // TODO: use an enum for this
        match message_type {
            MidiEventType::NoteOff
            | MidiEventType::NoteOn
            | MidiEventType::PolyponicKeyPressure
            | MidiEventType::ControlChange
            | MidiEventType::PitchBendChange => {
                track.messages.push(MidiEvent {
                    message_type: message_type,
                    time: track_time,
                    channel: channel,
                    value1: try!(file.read_byte()),
                    value2: Some(try!(file.read_byte()))
                });
            },
            MidiEventType::ProgramChange
            | MidiEventType::ChannelPressure => {
                track.messages.push(MidiEvent {
                    message_type: message_type,
                    time: track_time,
                    channel: channel,
                    value1: try!(file.read_byte()),
                    value2: None
                });
            },
            MidiEventType::System => {
                let system_message_type = FromPrimitive::from_u8(try!(file.read_byte()));
                let system_data_size = try!(read_variable_number(&mut file));

                match system_message_type {
                    Some(MidiSystemEventType::EndOfTrack) => {
                        song.tracks.push(track);
                        track = MidiTrack::new();

                        let next_track_chunk_name = file.read_be_u32();
                        if next_track_chunk_name.is_ok() {
                            let _next_track_chunk_size = try!(file.read_be_u32());
                            track_time = 0u;
                        } else {
                            keep_reading = false;
                        }
                    },
                    _ => {
                        // Discard unhandled system messages
                        try!(file.read_exact(system_data_size as uint));
                    }
                }
            }
        }
    }

    Ok(song)
}

fn read_variable_number<T>(reader: &mut T) -> IoResult<uint> where T: Reader {
    // http://en.wikipedia.org/wiki/Variable-length_quantity
    // cont. bit---V
    //             7[6 5 4 3 2 1 0]+-+
    // more bytes: 1 b b b b b b b   | concat bits to form new number
    //                               V
    //                             7[6 5 4 3 2 1 0]
    //              no more bytes: 0 b b b b b b b

    let mut octet = try!(reader.read_byte());
    let mut value = (octet & 0b01111111) as uint;
    while octet >= 0b10000000 {
        octet = try!(reader.read_byte());
        value = (value << 7) as uint + (octet & 0b01111111) as uint;
    }

    Ok(value)
}

#[test]
fn it_parses_a_midi_file() {
    let song = read_midi("tests/assets/test.mid").ok().expect("Failed");

    assert_eq!(song.tracks.len(), 2); // metadata track included
    let ref messages = song.tracks[1].messages;

    // ProgramChange
    assert_eq!(messages[0].message_type, MidiEventType::ProgramChange);
    assert_eq!(messages[0].time, 0);
    assert_eq!(messages[0].channel, 0);
    assert_eq!(messages[0].value1, 0);
    assert_eq!(messages[0].value2, None);

    // NoteOn
    assert_eq!(messages[1].message_type, MidiEventType::NoteOn);
    assert_eq!(messages[1].time, 0);
    assert_eq!(messages[1].channel, 0);
    assert_eq!(messages[1].value1, 57);
    assert_eq!(messages[1].value2, Some(64));

    // NoteOff
    assert_eq!(messages[2].message_type, MidiEventType::NoteOff);
    assert_eq!(messages[2].time, 960);
    assert_eq!(messages[2].channel, 0);
    assert_eq!(messages[2].value1, 57);
    assert_eq!(messages[2].value2, Some(0));
}

#[test]
fn it_parses_a_multitrack_midi_file() {
    let song = read_midi("tests/assets/multitrack.mid").unwrap();
    assert_eq!(song.tracks.len(), 3); // metadata track included
}
<|endoftext|>


<commit_before>use rand::Rng;
use Packing;

pub mod kyber;

pub trait KeyExchange {
    type PrivateKey: Packing;
    type PublicKey: Packing;
    type Message: Packing;

    const SHARED_LENGTH: usize;

    fn kerpair<R: Rng>(r: R) -> (Self::PrivateKey, Self::PublicKey);

    /// TODO should be `sharedkey: &mut [u8; Self::SHARED_LENGTH]`
    fn exchange_to<R: Rng>(r: R, sharedkey: &mut [u8], pk: &Self::PublicKey) -> Self::Message;

    /// TODO should be `sharedkey: &mut [u8; Self::SHARED_LENGTH]`
    fn exchange_from(sharedkey: &mut [u8], sk: &Self::PrivateKey, m: &Self::Message);
}

pub trait DeterministicExchange: KeyExchange {
    fn exchange_to(sharedkey: &mut [u8], pk: &Self::PublicKey) -> Self::Message;
}

pub trait CheckedExchange: KeyExchange {
    fn exchange_from(sharedkey: &mut [u8], sk: &Self::PrivateKey, m: &Self::Message) -> bool;
}
<commit_msg>Fix typo in trait<commit_after>use rand::Rng;
use Packing;

pub mod kyber;

pub trait KeyExchange {
    type PrivateKey: Packing;
    type PublicKey: Packing;
    type Message: Packing;

    const SHARED_LENGTH: usize;

    fn keypair<R: Rng>(r: R) -> (Self::PrivateKey, Self::PublicKey);

    /// TODO should be `sharedkey: &mut [u8; Self::SHARED_LENGTH]`
    fn exchange_to<R: Rng>(r: R, sharedkey: &mut [u8], pk: &Self::PublicKey) -> Self::Message;

    /// TODO should be `sharedkey: &mut [u8; Self::SHARED_LENGTH]`
    fn exchange_from(sharedkey: &mut [u8], sk: &Self::PrivateKey, m: &Self::Message);
}

pub trait DeterministicExchange: KeyExchange {
    fn exchange_to(sharedkey: &mut [u8], pk: &Self::PublicKey) -> Self::Message;
}

pub trait CheckedExchange: KeyExchange {
    fn exchange_from(sharedkey: &mut [u8], sk: &Self::PrivateKey, m: &Self::Message) -> bool;
}
<|endoftext|>


<commit_before>use std::mem::transmute;
use std::marker::PhantomData;
use std::collections::VecDeque;

use super::instr::Instr;
use super::Program;

pub struct Kleisli<'a, I: Instr<Param=A>, A, B> {
    phan: PhantomData<(A, B)>,
    deque: VecDeque<Box<Fn(Box<()>) -> Program<'a, I, ()> + 'a>>
}

unsafe fn fn_transmute<'a, I: Instr, A, B, F: 'a + Fn(Box<A>) -> Program<'a, I, B>>(f: F)
    -> Box<Fn(Box<()>) -> Program<'a, I, ()> + 'a> {
    Box::new(move |ptr| transmute(f(transmute::<Box<()>, Box<A>>(ptr))))
}

impl<'a, I: Instr<Param=A>, A> Kleisli<'a, I, A, A> {
    pub fn new() -> Kleisli<'a, I, A, A> {
        Kleisli { phan: PhantomData, deque: VecDeque::new() }
    }
}

pub fn append_boxed<'a, I: 'a + Instr<Param=A>, A, B, C, F>
    (mut k: Kleisli<'a, I, A, B>, f: F) -> Kleisli<'a, I, A, C>
    where F: 'a + Fn(Box<B>) -> Program<'a, I, C> {
    k.deque.push_back(unsafe { fn_transmute(f) });
    Kleisli { phan: PhantomData, deque: k.deque }
}

impl<'a, I: 'a + Instr<Param=A>, A, B> Kleisli<'a, I, A, B> {

    pub fn append<F, C>(self, f: F) -> Kleisli<'a, I, A, C>
        where F: 'a + Fn(B) -> Program<'a, I, C> {
        append_boxed(self, move |b| f(*b))
    }

    pub fn run(mut self, a: A) -> Program<'a, I, B> {
        unsafe {
            let mut r = transmute::<Program<'a, I, A>, Program<'a, I, ()>>(Program::new(a));
            loop {
                match self.deque.pop_front() {
                    None => return transmute(r),
                    Some(f) => r = r.and_then_boxed(move |a| (*f)(a))
                }
            }
        }
    }

}

#[test]
fn kleisli_run_plus_one() {
    use super::instr::Identity;
    let k: Kleisli<Identity<i32>, _, _> = Kleisli::new().append(|a| Program::new(a + 1));
    assert_eq!(k.run(42), Program::new(43));
}
<commit_msg>add kleisli to_string test<commit_after>use std::mem::transmute;
use std::marker::PhantomData;
use std::collections::VecDeque;

use super::instr::Instr;
use super::Program;

pub struct Kleisli<'a, I: Instr<Param=A>, A, B> {
    phan: PhantomData<(A, B)>,
    deque: VecDeque<Box<Fn(Box<()>) -> Program<'a, I, ()> + 'a>>
}

unsafe fn fn_transmute<'a, I: Instr, A, B, F: 'a + Fn(Box<A>) -> Program<'a, I, B>>(f: F)
    -> Box<Fn(Box<()>) -> Program<'a, I, ()> + 'a> {
    Box::new(move |ptr| transmute(f(transmute::<Box<()>, Box<A>>(ptr))))
}

impl<'a, I: Instr<Param=A>, A> Kleisli<'a, I, A, A> {
    pub fn new() -> Kleisli<'a, I, A, A> {
        Kleisli { phan: PhantomData, deque: VecDeque::new() }
    }
}

pub fn append_boxed<'a, I: 'a + Instr<Param=A>, A, B, C, F>
    (mut k: Kleisli<'a, I, A, B>, f: F) -> Kleisli<'a, I, A, C>
    where F: 'a + Fn(Box<B>) -> Program<'a, I, C> {
    k.deque.push_back(unsafe { fn_transmute(f) });
    Kleisli { phan: PhantomData, deque: k.deque }
}

impl<'a, I: 'a + Instr<Param=A>, A, B> Kleisli<'a, I, A, B> {

    pub fn append<F, C>(self, f: F) -> Kleisli<'a, I, A, C>
        where F: 'a + Fn(B) -> Program<'a, I, C> {
        append_boxed(self, move |b| f(*b))
    }

    pub fn run(mut self, a: A) -> Program<'a, I, B> {
        unsafe {
            let mut r = transmute::<Program<'a, I, A>, Program<'a, I, ()>>(Program::new(a));
            loop {
                match self.deque.pop_front() {
                    None => return transmute(r),
                    Some(f) => r = r.and_then_boxed(move |a| (*f)(a))
                }
            }
        }
    }

}

#[test]
fn kleisli_run_plus_one() {
    use super::instr::Identity;
    let k: Kleisli<Identity<i32>, _, _> = Kleisli::new().append(|a| Program::new(a + 1));
    assert_eq!(k.run(42), Program::new(43));
}

#[test]
fn kleisli_run_to_string() {
    use super::instr::Identity;
    let k: Kleisli<Identity<i32>, _, _> = Kleisli::new().append(|a: i32| Program::new(a.to_string()));
    assert_eq!(k.run(42), Program::new("42".to_string()));
}
<|endoftext|>


<commit_before>use std;
use std::cmp;
use std::io::stdout;
use std::io::Write;
use std::thread;
use std::time;

use termion;
use termion::clear;
use termion::color;
use termion::cursor;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;

use core::Core;
use update::Update;

pub struct Screen {
    pub stdout: MouseTerminal<RawTerminal<std::io::Stdout>>,
    pub size: (u16, u16),
}

impl Screen {
    pub fn new() -> Screen {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    // TODO: handle lines that are longer than terminal width.
    // Should we wrap them or truncate them?
    pub fn redraw(&mut self, update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();

        let nb_lines = cmp::min(update.lines.len(), self.size.1 as usize);
        if nb_lines > 0 {
            for line in update.lines.iter().take(nb_lines - 1) {
                write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();

                if let Some(selection) = line.selection {
                    let start = selection.0 as usize;
                    let end = selection.1 as usize;
                    let mut str_before = String::new();
                    for c in line.text.chars().take(start) {
                        str_before.push(c);
                    }
                    let mut str_selection = String::new();
                    for c in line.text.chars().skip(start).take(end) {
                        str_selection.push(c);
                    }
                    let mut str_after = String::new();
                    for c in line.text.chars().skip(end) {
                        str_after.push(c);
                    }
                    write!(self.stdout, "{}{}{}{}{}{}",
                           termion::style::Reset,
                           str_before,
                           termion::color::Bg(color::Red),
                           str_selection,
                           termion::style::Reset,
                           str_after).unwrap();
                } else {
                    self.stdout.write_all(line.text.as_bytes()).unwrap();
                }
            }

            // If the last line has a trailing \n, we need to remove it
            let mut last_line = update.lines[nb_lines - 1].text.clone();
            match last_line.pop() {
                Some('\n') | None => {
                },
                Some(c) => {
                    last_line.push(c);
                }
            }
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(last_line.as_bytes()).unwrap();
        }

        let cursor_line_idx = update.scroll_to.0 - update.first_line;
        let cursor_line = update.lines[cursor_line_idx as usize].text.clone();
        let mut cols =  0;
        for c in cursor_line.chars().take(update.scroll_to.1 as usize) {
            if c == '\t' {
                cols += 4;
            } else {
                cols += 1;
            }
        }
        self.scroll(cols + 1, cursor_line_idx + 1);
    }

    pub fn scroll(&mut self, col: u64, line: u64) {
        write!(self.stdout, "{}", cursor::Goto(col as u16, line as u16)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn update(&mut self, core: &mut Core) {
        // TODO: check if terminal size changed. If so, send a `render_line` command to the backend,
        // and a `scroll` command for future updates.
        if let Ok(msg) = core.update_rx.try_recv() {
            let msg_list = msg.as_array().unwrap();
            let (method, params) = (msg_list[0].as_str().unwrap(), msg_list[1].as_object().unwrap());
            if method == "update" {
                let update = Update::from_value(params.get("update").unwrap());
                self.redraw(&update);
            } else if method == "scroll_to" {
                let (col, line) = (params.get("col").unwrap().as_u64().unwrap(), params.get("line").unwrap().as_u64().unwrap());
                self.scroll(col, line);
            } else if method == "set_style" {
                // TODO: ???
            } else {
                info!("Unknown request from backend {:?}", method);
            }
        } else {
            thread::sleep(time::Duration::from_millis(10));
        }
    }
}
<commit_msg>Temporarily marks redraw() as unimplemented<commit_after>use std;
use std::cmp;
use std::io::stdout;
use std::io::Write;
use std::thread;
use std::time;

use termion;
use termion::clear;
use termion::color;
use termion::cursor;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;

use core::Core;
use update::Update;

pub struct Screen {
    pub stdout: MouseTerminal<RawTerminal<std::io::Stdout>>,
    pub size: (u16, u16),
}

impl Screen {
    pub fn new() -> Screen {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    // TODO: handle lines that are longer than terminal width.
    // Should we wrap them or truncate them?
    pub fn redraw(&mut self, update: &Update) {
        unimplemented!();
        /*
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();

        let nb_lines = cmp::min(update.lines.len(), self.size.1 as usize);
        if nb_lines > 0 {
            for line in update.lines.iter().take(nb_lines - 1) {
                write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();

                if let Some(selection) = line.selection {
                    let start = selection.0 as usize;
                    let end = selection.1 as usize;
                    let mut str_before = String::new();
                    for c in line.text.chars().take(start) {
                        str_before.push(c);
                    }
                    let mut str_selection = String::new();
                    for c in line.text.chars().skip(start).take(end) {
                        str_selection.push(c);
                    }
                    let mut str_after = String::new();
                    for c in line.text.chars().skip(end) {
                        str_after.push(c);
                    }
                    write!(self.stdout, "{}{}{}{}{}{}",
                           termion::style::Reset,
                           str_before,
                           termion::color::Bg(color::Red),
                           str_selection,
                           termion::style::Reset,
                           str_after).unwrap();
                } else {
                    self.stdout.write_all(line.text.as_bytes()).unwrap();
                }
            }

            // If the last line has a trailing \n, we need to remove it
            let mut last_line = update.lines[nb_lines - 1].text.clone();
            match last_line.pop() {
                Some('\n') | None => {
                },
                Some(c) => {
                    last_line.push(c);
                }
            }
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(last_line.as_bytes()).unwrap();
        }

        let cursor_line_idx = update.scroll_to.0 - update.first_line;
        let cursor_line = update.lines[cursor_line_idx as usize].text.clone();
        let mut cols =  0;
        for c in cursor_line.chars().take(update.scroll_to.1 as usize) {
            if c == '\t' {
                cols += 4;
            } else {
                cols += 1;
            }
        }
        self.scroll(cols + 1, cursor_line_idx + 1);
        */
    }

    pub fn scroll(&mut self, col: u64, line: u64) {
        write!(self.stdout, "{}", cursor::Goto(col as u16, line as u16)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn update(&mut self, core: &mut Core) {
        // TODO: check if terminal size changed. If so, send a `render_line` command to the backend,
        // and a `scroll` command for future updates.
        if let Ok(msg) = core.update_rx.try_recv() {
            let msg_list = msg.as_array().unwrap();
            let (method, params) = (msg_list[0].as_str().unwrap(), msg_list[1].as_object().unwrap());
            if method == "update" {
                let update = Update::from_value(params.get("update").unwrap());
                self.redraw(&update);
            } else if method == "scroll_to" {
                let (col, line) = (params.get("col").unwrap().as_u64().unwrap(), params.get("line").unwrap().as_u64().unwrap());
                self.scroll(col, line);
            } else if method == "set_style" {
                // TODO: ???
            } else {
                info!("Unknown request from backend {:?}", method);
            }
        } else {
            thread::sleep(time::Duration::from_millis(10));
        }
    }
}
<|endoftext|>


<commit_before>#![crate_id = "github.com/TomBebbington/js.rs#js:0.1"]
#![comment = "Javascript parsing, compilation and execution using LibJIT"]
#![license = "MIT"]
#![crate_type = "lib"]
#![doc(
    html_favicon_url = "http://tombebbington.github.io/favicon.png"
  )
#![experimental]
#![feature(phase, macro_rules, globs)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint,
	unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation,
	uppercase_variables, non_camel_case_types, unused_must_use)]
//! This is a library with seperate modules for Javascript parsing, the Javascript
//! standard library, and Javascript execution through LibJIT
extern crate collections;
extern crate jit;
#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate time;
extern crate url;
/// The backend-defining traits and the Javascript standard library
pub mod front {
	#[macro_escape]
	/// A macro which makes Javascript objects with pretty Rust syntax
	pub mod macro;
	/// Backend-defining traits
	pub mod run {
		/// For compiling Javascript values
		pub mod compiler;
		/// For executing the compiled Javascript values
		pub mod executor;
	}
	/// The Javascript standard library
	pub mod stdlib {
		/// The `Array` global object
		pub mod array;
		/// The `Boolean` global object
		pub mod boolean;
		/// The `console` global object
		pub mod console;
		/// The `Error` global objects
		pub mod error;
		/// The `Function` global object
		pub mod function;
		/// The `JSON` global object
		pub mod json;
		/// The `Math` global object
		pub mod math;
		/// The `Number` global object and related global methods
		pub mod number;
		/// The `Object` global object
		pub mod object;
		/// The `String` global object
		pub mod string;
		/// The global URI methods
		pub mod uri;
		/// An arbritary Javascript value
		pub mod value;
	}
}
/// The default backend implemented on top of LibJIT
pub mod back {
	/// The compiler, which transforms Javascript expressions to LibJIT IR
	pub mod compiler;
	/// The executor, which runs the LibJIT IR by compiling it then running it
	pub mod executor;
}
/// Javascript parsing and syntax
pub mod syntax {
	/// The Javascript Abstract Syntax Tree
	pub mod ast {
		/// Constants
		pub mod constant;
		/// Expressions
		pub mod expr;
		/// Keywords
		pub mod keyword;
		/// Operators
		pub mod op;
		/// Positions
		pub mod pos;
		/// Punctuators
		pub mod punc;
		/// Tokens
		pub mod token;
		/// An expression typer
		pub mod typer;
		/// Types
		pub mod types;
	}
	/// Parses a string stream into a sequence of tokens
	pub mod lexer;
	/// Parses a sequence of tokens into expressions
	pub mod parser;
}<commit_msg>Close *BOTH* doc delimeters<commit_after>#![crate_id = "github.com/TomBebbington/js.rs#js:0.1"]
#![comment = "Javascript parsing, compilation and execution using LibJIT"]
#![license = "MIT"]
#![crate_type = "lib"]
#![doc(
    html_favicon_url = "http://tombebbington.github.io/favicon.png"
  ))
#![experimental]
#![feature(phase, macro_rules, globs)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint,
	unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation,
	uppercase_variables, non_camel_case_types, unused_must_use)]
//! This is a library with seperate modules for Javascript parsing, the Javascript
//! standard library, and Javascript execution through LibJIT
extern crate collections;
extern crate jit;
#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate time;
extern crate url;
/// The backend-defining traits and the Javascript standard library
pub mod front {
	#[macro_escape]
	/// A macro which makes Javascript objects with pretty Rust syntax
	pub mod macro;
	/// Backend-defining traits
	pub mod run {
		/// For compiling Javascript values
		pub mod compiler;
		/// For executing the compiled Javascript values
		pub mod executor;
	}
	/// The Javascript standard library
	pub mod stdlib {
		/// The `Array` global object
		pub mod array;
		/// The `Boolean` global object
		pub mod boolean;
		/// The `console` global object
		pub mod console;
		/// The `Error` global objects
		pub mod error;
		/// The `Function` global object
		pub mod function;
		/// The `JSON` global object
		pub mod json;
		/// The `Math` global object
		pub mod math;
		/// The `Number` global object and related global methods
		pub mod number;
		/// The `Object` global object
		pub mod object;
		/// The `String` global object
		pub mod string;
		/// The global URI methods
		pub mod uri;
		/// An arbritary Javascript value
		pub mod value;
	}
}
/// The default backend implemented on top of LibJIT
pub mod back {
	/// The compiler, which transforms Javascript expressions to LibJIT IR
	pub mod compiler;
	/// The executor, which runs the LibJIT IR by compiling it then running it
	pub mod executor;
}
/// Javascript parsing and syntax
pub mod syntax {
	/// The Javascript Abstract Syntax Tree
	pub mod ast {
		/// Constants
		pub mod constant;
		/// Expressions
		pub mod expr;
		/// Keywords
		pub mod keyword;
		/// Operators
		pub mod op;
		/// Positions
		pub mod pos;
		/// Punctuators
		pub mod punc;
		/// Tokens
		pub mod token;
		/// An expression typer
		pub mod typer;
		/// Types
		pub mod types;
	}
	/// Parses a string stream into a sequence of tokens
	pub mod lexer;
	/// Parses a sequence of tokens into expressions
	pub mod parser;
}<|endoftext|>


<commit_before>use std::io::Read;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;
use std::thread;

use hyper::header::ContentType;
use hyper::method::Method;
use hyper::Result;
use hyper::server::{Handler, Listening, Request, Response, Server};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;

use command::{WebDriverMessage, WebDriverCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::{WebDriverHttpApi, WebDriverExtensionRoute, VoidWebDriverExtensionRoute};
use response::WebDriverResponse;

enum DispatchMessage<U: WebDriverExtensionRoute> {
    HandleWebDriver(WebDriverMessage<U>, Sender<WebDriverResult<WebDriverResponse>>),
    Quit
}

#[derive(PartialEq, Clone)]
pub struct Session {
    id: String
}

impl Session {
    fn new(id: String) -> Session {
        Session {
            id: id
        }
    }
}

pub trait WebDriverHandler<U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: WebDriverMessage<U>) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler<U>,
                  U: WebDriverExtensionRoute> {
    handler: T,
    session: Option<Session>,
    extension_type: PhantomData<U>,
}

impl <T: WebDriverHandler<U>,
      U: WebDriverExtensionRoute> Dispatcher<T,U> {
    fn new(handler: T) -> Dispatcher<T,U> {
        Dispatcher {
            handler: handler,
            session: None,
            extension_type: PhantomData
        }
    }

    fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
        loop {
            match msg_chan.recv() {
                Ok(DispatchMessage::HandleWebDriver(msg, resp_chan)) => {
                    let resp = match self.check_session(&msg) {
                        Ok(_) => self.handler.handle_command(&self.session, msg),
                        Err(e) => Err(e)
                    };

                    match resp {
                        Ok(WebDriverResponse::NewSession(ref new_session)) => {
                            self.session = Some(Session::new(new_session.sessionId.clone()));
                        },
                        Ok(WebDriverResponse::DeleteSession) => {
                            self.delete_session();
                        },
                        Err(ref x) if x.delete_session() => {
                            self.delete_session();
                        }
                        _ => {}
                    }

                    if resp_chan.send(resp).is_err() {
                        error!("Sending response to the main thread failed");
                    };
                },
                Ok(DispatchMessage::Quit) => {
                    break;
                },
                Err(_) => panic!("Error receiving message in handler")
            }
        }
    }

    fn delete_session(&mut self) {
        debug!("Deleting session");
        self.handler.delete_session(&self.session);
        self.session = None;
    }

    fn check_session(&self, msg: &WebDriverMessage<U>) -> WebDriverResult<()> {
        match msg.session_id {
            Some(ref msg_session_id) => {
                match self.session {
                    Some(ref existing_session) => {
                        if existing_session.id != *msg_session_id {
                            Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                format!("Got unexpected session id {} expected {}",
                                        msg_session_id,
                                        existing_session.id)))
                        } else {
                            Ok(())
                        }
                    },
                    None => Ok(())
                }
            },
            None => {
                match self.session {
                    Some(_) => {
                        match msg.command {
                            WebDriverCommand::NewSession(_) => {
                                Err(WebDriverError::new(
                                    ErrorStatus::SessionNotCreated,
                                    "Session is already started"))
                            },
                            _ => {
                                //This should be impossible
                                error!("Got a message with no session id");
                                Err(WebDriverError::new(
                                    ErrorStatus::UnknownError,
                                    "Got a command with no session?!"))
                            }
                        }
                    },
                    None => {
                        match msg.command {
                            WebDriverCommand::NewSession(_) => Ok(()),

                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

struct HttpHandler<U: WebDriverExtensionRoute> {
    chan: Mutex<Sender<DispatchMessage<U>>>,
    api: Mutex<WebDriverHttpApi<U>>
}

impl <U: WebDriverExtensionRoute> HttpHandler<U> {
    fn new(api: WebDriverHttpApi<U>, chan: Sender<DispatchMessage<U>>) -> HttpHandler<U> {
        HttpHandler {
            chan: Mutex::new(chan),
            api: Mutex::new(api)
        }
    }
}

impl <U: WebDriverExtensionRoute> Handler for HttpHandler<U> {
    fn handle(&self, req: Request, res: Response) {
        let mut req = req;
        let mut res = res;

        let mut body = String::new();
        if let Method::Post = req.method {
            req.read_to_string(&mut body).unwrap();
        }
        debug!("Got request {} {:?}", req.method, req.uri);
        match req.uri {
            AbsolutePath(path) => {
                let msg_result = {
                    // The fact that this locks for basically the whole request doesn't
                    // matter as long as we are only handling one request at a time.
                    match self.api.lock() {
                        Ok(ref api) => {
                            api.decode_request(req.method, &path[..], &body[..])
                        },
                        Err(_) => return
                    }
                };
                let (status, resp_body) = match msg_result {
                    Ok(message) => {
                        let (send_res, recv_res) = channel();
                        match self.chan.lock() {
                            Ok(ref c) => {
                                let res = c.send(DispatchMessage::HandleWebDriver(message,
                                                                                send_res));
                                match res {
                                    Ok(x) => x,
                                    Err(_) => {
                                        error!("Something terrible happened");
                                        return
                                    }
                                }
                            },
                            Err(_) => {
                                error!("Something terrible happened");
                                return
                            }
                        }
                        match recv_res.recv() {
                            Ok(data) => match data {
                                Ok(response) => (StatusCode::Ok, response.to_json_string()),
                                Err(err) => (err.http_status(), err.to_json_string()),
                            },
                            Err(e) => panic!("Error reading response: {:?}", e)
                        }
                    },
                    Err(err) => {
                        (err.http_status(), err.to_json_string())
                    }
                };
                debug!("Returning status {:?}", status);
                debug!("Returning body {}", resp_body);
                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut().set(ContentType::json());
                res.send(&resp_body.as_bytes()).unwrap();
            },
            _ => {}
        }
    }
}

pub fn start<T, U>(address: SocketAddr,
                   handler: T,
                   extension_routes: Vec<(Method, &str, U)>)
                   -> Result<Listening>
    where T: 'static + WebDriverHandler<U>,
          U: 'static + WebDriverExtensionRoute
{
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new(extension_routes);
    let http_handler = HttpHandler::new(api, msg_send);
    let mut server = try!(Server::http(address));
    server.keep_alive(None);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    try!(builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv);
    }));

    server.handle(http_handler)
}
<commit_msg>Allow command Status without session id<commit_after>use std::io::Read;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;
use std::thread;

use hyper::header::ContentType;
use hyper::method::Method;
use hyper::Result;
use hyper::server::{Handler, Listening, Request, Response, Server};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;

use command::{WebDriverMessage, WebDriverCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::{WebDriverHttpApi, WebDriverExtensionRoute, VoidWebDriverExtensionRoute};
use response::WebDriverResponse;

enum DispatchMessage<U: WebDriverExtensionRoute> {
    HandleWebDriver(WebDriverMessage<U>, Sender<WebDriverResult<WebDriverResponse>>),
    Quit
}

#[derive(PartialEq, Clone)]
pub struct Session {
    id: String
}

impl Session {
    fn new(id: String) -> Session {
        Session {
            id: id
        }
    }
}

pub trait WebDriverHandler<U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: WebDriverMessage<U>) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler<U>,
                  U: WebDriverExtensionRoute> {
    handler: T,
    session: Option<Session>,
    extension_type: PhantomData<U>,
}

impl <T: WebDriverHandler<U>,
      U: WebDriverExtensionRoute> Dispatcher<T,U> {
    fn new(handler: T) -> Dispatcher<T,U> {
        Dispatcher {
            handler: handler,
            session: None,
            extension_type: PhantomData
        }
    }

    fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
        loop {
            match msg_chan.recv() {
                Ok(DispatchMessage::HandleWebDriver(msg, resp_chan)) => {
                    let resp = match self.check_session(&msg) {
                        Ok(_) => self.handler.handle_command(&self.session, msg),
                        Err(e) => Err(e)
                    };

                    match resp {
                        Ok(WebDriverResponse::NewSession(ref new_session)) => {
                            self.session = Some(Session::new(new_session.sessionId.clone()));
                        },
                        Ok(WebDriverResponse::DeleteSession) => {
                            self.delete_session();
                        },
                        Err(ref x) if x.delete_session() => {
                            self.delete_session();
                        }
                        _ => {}
                    }

                    if resp_chan.send(resp).is_err() {
                        error!("Sending response to the main thread failed");
                    };
                },
                Ok(DispatchMessage::Quit) => {
                    break;
                },
                Err(_) => panic!("Error receiving message in handler")
            }
        }
    }

    fn delete_session(&mut self) {
        debug!("Deleting session");
        self.handler.delete_session(&self.session);
        self.session = None;
    }

    fn check_session(&self, msg: &WebDriverMessage<U>) -> WebDriverResult<()> {
        match msg.session_id {
            Some(ref msg_session_id) => {
                match self.session {
                    Some(ref existing_session) => {
                        if existing_session.id != *msg_session_id {
                            Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                format!("Got unexpected session id {} expected {}",
                                        msg_session_id,
                                        existing_session.id)))
                        } else {
                            Ok(())
                        }
                    },
                    None => Ok(())
                }
            },
            None => {
                match self.session {
                    Some(_) => {
                        match msg.command {
                            WebDriverCommand::Status => Ok(()),
                            WebDriverCommand::NewSession(_) => {
                                Err(WebDriverError::new(
                                    ErrorStatus::SessionNotCreated,
                                    "Session is already started"))
                            },
                            _ => {
                                //This should be impossible
                                error!("Got a message with no session id");
                                Err(WebDriverError::new(
                                    ErrorStatus::UnknownError,
                                    "Got a command with no session?!"))
                            }
                        }
                    },
                    None => {
                        match msg.command {
                            WebDriverCommand::NewSession(_) => Ok(()),

                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

struct HttpHandler<U: WebDriverExtensionRoute> {
    chan: Mutex<Sender<DispatchMessage<U>>>,
    api: Mutex<WebDriverHttpApi<U>>
}

impl <U: WebDriverExtensionRoute> HttpHandler<U> {
    fn new(api: WebDriverHttpApi<U>, chan: Sender<DispatchMessage<U>>) -> HttpHandler<U> {
        HttpHandler {
            chan: Mutex::new(chan),
            api: Mutex::new(api)
        }
    }
}

impl <U: WebDriverExtensionRoute> Handler for HttpHandler<U> {
    fn handle(&self, req: Request, res: Response) {
        let mut req = req;
        let mut res = res;

        let mut body = String::new();
        if let Method::Post = req.method {
            req.read_to_string(&mut body).unwrap();
        }
        debug!("Got request {} {:?}", req.method, req.uri);
        match req.uri {
            AbsolutePath(path) => {
                let msg_result = {
                    // The fact that this locks for basically the whole request doesn't
                    // matter as long as we are only handling one request at a time.
                    match self.api.lock() {
                        Ok(ref api) => {
                            api.decode_request(req.method, &path[..], &body[..])
                        },
                        Err(_) => return
                    }
                };
                let (status, resp_body) = match msg_result {
                    Ok(message) => {
                        let (send_res, recv_res) = channel();
                        match self.chan.lock() {
                            Ok(ref c) => {
                                let res = c.send(DispatchMessage::HandleWebDriver(message,
                                                                                send_res));
                                match res {
                                    Ok(x) => x,
                                    Err(_) => {
                                        error!("Something terrible happened");
                                        return
                                    }
                                }
                            },
                            Err(_) => {
                                error!("Something terrible happened");
                                return
                            }
                        }
                        match recv_res.recv() {
                            Ok(data) => match data {
                                Ok(response) => (StatusCode::Ok, response.to_json_string()),
                                Err(err) => (err.http_status(), err.to_json_string()),
                            },
                            Err(e) => panic!("Error reading response: {:?}", e)
                        }
                    },
                    Err(err) => {
                        (err.http_status(), err.to_json_string())
                    }
                };
                debug!("Returning status {:?}", status);
                debug!("Returning body {}", resp_body);
                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut().set(ContentType::json());
                res.send(&resp_body.as_bytes()).unwrap();
            },
            _ => {}
        }
    }
}

pub fn start<T, U>(address: SocketAddr,
                   handler: T,
                   extension_routes: Vec<(Method, &str, U)>)
                   -> Result<Listening>
    where T: 'static + WebDriverHandler<U>,
          U: 'static + WebDriverExtensionRoute
{
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new(extension_routes);
    let http_handler = HttpHandler::new(api, msg_send);
    let mut server = try!(Server::http(address));
    server.keep_alive(None);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    try!(builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv);
    }));

    server.handle(http_handler)
}
<|endoftext|>


<commit_before>//! Shapes in the game, like units (triangles) and buildings (squares).
extern crate graphics;
use self::graphics::types::Triangle;
use self::graphics::math;
use self::graphics::math::{sub, square_len};
use super::state;
use std::f64;

use common::Vec2;

pub trait Shape {
    fn get_shape(&self, size: f64) -> Triangle;

    fn is_hit(&self, size: f64, position: Vec2) -> bool;

    fn collision_detect(&self, other: &Self, size: f64) -> bool;
}

impl Shape for state::Unit {
    /// Return the base shape of the unit.
    fn get_shape(&self, radius: f64) -> Triangle {
        // calculate side length
        let a = radius * 3.0 / 3.0f64.sqrt();

        // <|
        let mut triangle: Triangle = [
            [-radius,        0.0], // Left
            [ radius*0.5,  a/2.0], // Top right
            [ radius*0.5, -a/2.0], // Bottom right
        ];

        // Transformations
        for point in triangle.iter_mut() {
            // Rotate
            let rotation_matrix = math::rotate_radians(self.angle);
            *point = math::transform_vec(rotation_matrix, *point);

            // Translate to effective position
            *point = math::add(*point, self.position.into());
        }

        triangle
    }

    /// Calculate whether or not this unit is hit by the point at the specified position.
    fn is_hit(&self, size: f64, position: Vec2) -> bool {
        let hitbox = self.get_shape(size);
        math::inside_triangle(hitbox, position.into())
    }

    fn collision_detect(&self, other: &Self, size: f64) -> bool {
        let dv = sub(self.position.into(), other.position.into());
        square_len(dv) <= (2.0 * size * 2.0 * size)
    }
}

#[cfg(test)]
mod test {
    use std::f64::consts::FRAC_PI_2;

    use super::{Shape, Vec2, state};

    #[test]
    fn test_hitbox() {
        // Create a unit at position (100,100) that has been rotated by 90° CW.
        //
        //    /\
        //   /__\
        //
        let mut unit = state::Unit::new(0, Vec2::new(0.0, 0.0));
        unit.angle = FRAC_PI_2;

        let epsilon = 0.001;
        let size = 1.0;
        let a = size * 3.0 / 3.0f64.sqrt();

        // The following points should be outside of the hitbox.
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, epsilon)), false);
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, epsilon)), false);

        // The following five points should be inside the hitbox.
        //      .
        //     /.\
        //   ./_._\.
        //
        assert_eq!(unit.is_hit(1.0, Vec2::new(0.0, 0.0)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new(0.0, -size + epsilon)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new(0.0, size / 2.0 - epsilon)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new(-a / 2.0 + epsilon, size / 2.0 - epsilon)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new( a / 2.0 - epsilon, size / 2.0 - epsilon)), true);

        // The following two points should be outside the hitbox.
        //
        //  . /\ .
        //   /__\
        //
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, 0.0)), false);
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, 0.0)), false);
    }

    #[test]
    fn test_collision_detect() {
        let unit_l = state::Unit::new(0, Vec2::new(0.0, 0.0));

        {
            let unit_r = state::Unit::new(0, Vec2::new(1.0, 0.0));
            assert!(unit_l.collision_detect(&unit_r, 0.5));
        }

        {
            let unit_r = state::Unit::new(0, Vec2::new(1.0, 0.0));
            assert!(unit_l.collision_detect(&unit_r, 0.5));
        }
    }
}
<commit_msg>Implement collision avoidance<commit_after>//! Shapes in the game, like units (triangles) and buildings (squares).
extern crate graphics;
use self::graphics::types::Triangle;
use self::graphics::math;
use self::graphics::math::{sub, square_len, mul_scalar};
use super::state;
use std::f64;

use common::Vec2;

pub trait Shape {
    fn get_shape(&self, size: f64) -> Triangle;

    fn is_hit(&self, size: f64, position: Vec2) -> bool;

    fn collision_detect(&self, other: &Self, size: f64) -> bool;

    fn collision_avoidance(&self, other: &Self) -> (Vec2, Vec2);
}

impl Shape for state::Unit {
    /// Return the base shape of the unit.
    fn get_shape(&self, radius: f64) -> Triangle {
        // calculate side length
        let a = radius * 3.0 / 3.0f64.sqrt();

        // <|
        let mut triangle: Triangle = [
            [-radius,        0.0], // Left
            [ radius*0.5,  a/2.0], // Top right
            [ radius*0.5, -a/2.0], // Bottom right
        ];

        // Transformations
        for point in triangle.iter_mut() {
            // Rotate
            let rotation_matrix = math::rotate_radians(self.angle);
            *point = math::transform_vec(rotation_matrix, *point);

            // Translate to effective position
            *point = math::add(*point, self.position.into());
        }

        triangle
    }

    /// Calculate whether or not this unit is hit by the point at the specified position.
    fn is_hit(&self, size: f64, position: Vec2) -> bool {
        let hitbox = self.get_shape(size);
        math::inside_triangle(hitbox, position.into())
    }

    fn collision_detect(&self, other: &Self, size: f64) -> bool {
        let dv = sub(self.position.into(), other.position.into());
        square_len(dv) <= (2.0 * size * 2.0 * size)
    }

    fn collision_avoidance(&self, other: &Self) -> (Vec2, Vec2) {
        let d = sub(self.position.into(), other.position.into());

        let xs: [f64; 2] = self.speed_vector.into();
        let xo: [f64; 2] = other.speed_vector.into();

        let foo = (xs[0] * d[0] + xs[1] * d[1]) / (d[0]*d[0] + d[1]*d[1]);
        let ys = if foo < 0.0 {
            let c = mul_scalar(d, foo);
            sub(xs, c)
        } else {
            xs
        };

        let foo = (xo[0] * d[0] + xo[1] * d[1]) / (d[0]*d[0] + d[1]*d[1]);
        let yo = if foo > 0.0 {
            let c = mul_scalar(d, foo);
            sub(xo, c)
        } else {
            xo
        };

        return (ys.into(), yo.into());
    }
}

#[cfg(test)]
mod test {
    use std::f64::consts::FRAC_PI_2;

    use super::{Shape, Vec2, state};

    #[test]
    fn test_hitbox() {
        // Create a unit at position (100,100) that has been rotated by 90° CW.
        //
        //    /\
        //   /__\
        //
        let mut unit = state::Unit::new(0, Vec2::new(0.0, 0.0));
        unit.angle = FRAC_PI_2;

        let epsilon = 0.001;
        let size = 1.0;
        let a = size * 3.0 / 3.0f64.sqrt();

        // The following points should be outside of the hitbox.
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, epsilon)), false);
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, epsilon)), false);

        // The following five points should be inside the hitbox.
        //      .
        //     /.\
        //   ./_._\.
        //
        assert_eq!(unit.is_hit(1.0, Vec2::new(0.0, 0.0)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new(0.0, -size + epsilon)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new(0.0, size / 2.0 - epsilon)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new(-a / 2.0 + epsilon, size / 2.0 - epsilon)), true);
        assert_eq!(unit.is_hit(1.0, Vec2::new( a / 2.0 - epsilon, size / 2.0 - epsilon)), true);

        // The following two points should be outside the hitbox.
        //
        //  . /\ .
        //   /__\
        //
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, 0.0)), false);
        assert_eq!(unit.is_hit(1.0, Vec2::new(a/2.0, 0.0)), false);
    }

    #[test]
    fn test_collision_detect() {
        let unit_l = state::Unit::new(0, Vec2::new(0.0, 0.0));

        {
            let unit_r = state::Unit::new(0, Vec2::new(1.0, 0.0));
            assert!(unit_l.collision_detect(&unit_r, 0.5));
        }

        {
            let unit_r = state::Unit::new(0, Vec2::new(1.0, 0.0));
            assert!(unit_l.collision_detect(&unit_r, 0.5));
        }
    }
}
<|endoftext|>


<commit_before>//! Signals are values that discretely change over time.

use crate::stream::Stream;
use crate::sync::Mutex;
use crate::types::{MaybeOwned, Storage};
use std::fmt;
use std::sync::{mpsc, Arc};

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `take` methods. They update lazily when someone reads them.
#[derive(Clone, Debug)]
pub struct Signal<T>(SigValue<T>);

/// The content source of a signal.
#[derive(Clone)]
enum SigValue<T> {
    /// A signal with constant value.
    Constant(T),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Arc<dyn Fn() -> T + Send + Sync>),
}

impl<T> Signal<T> {
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub const fn constant(val: T) -> Self {
        Signal(Constant(val))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
    where
        F: Fn() -> T + Send + Sync + 'static,
    {
        Signal(Dynamic(Arc::new(f)))
    }

    /// Creates a signal from shared storage.
    pub(crate) fn from_storage<S>(storage: Arc<Storage<T>>, source: S) -> Self
    where
        T: Clone + Send + 'static,
        S: Send + Sync + 'static,
    {
        Signal::from_fn(move || {
            let _keepalive = &source;
            storage.get()
        })
    }

    /// Samples the value of the signal.
    ///
    /// This will clone the value stored in the signal.
    pub fn sample(&self) -> T
    where
        T: Clone,
    {
        match self.0 {
            Constant(ref val) => T::clone(val),
            Dynamic(ref f) => f(),
        }
    }

    /// Maps a signal with the provided function.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
    where
        F: Fn(T) -> R + Send + Sync + 'static,
        T: Clone + 'static,
        R: Send + 'static,
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => Signal::constant(f(val.clone())),
            // dynamic signal: sample and apply f
            Dynamic(ref sf) => {
                let sf = sf.clone();
                Signal::from_fn(move || f(sf()))
            }
        }
    }

    /// Folds a signal using the provided function.
    ///
    /// The folding operation will occur every time the signal is sampled.
    pub fn fold(&self, initial: A, f: F) -> Signal
    where
        F: Fn(A, T) -> A + Send + Sync + 'static,
        T: Clone + Send + 'static,
        A: Clone + Send + 'static,
    {
        match self.0 {
            Constant(ref val) => {
                let source = Mutex::new(val.clone()); // need Sync for T
                let storage = Storage::new(initial);
                Signal::from_fn(move || {
                    let val = source.lock().clone();
                    storage.replace_with(|acc| f(acc, val));
                    storage.get()
                })
            }
            Dynamic(ref sf) => {
                let sf = sf.clone();
                let storage = Storage::new(initial);
                Signal::from_fn(move || {
                    let val = sf();
                    storage.replace_with(|acc| f(acc, val));
                    storage.get()
                })
            }
        }
    }
}

impl<T: Send + 'static> Signal<T> {
    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
    where
        F: Fn(T, MaybeOwned<'_, S>) -> R + Send + Sync + 'static,
        T: Clone,
        S: 'static,
        R: 'static,
    {
        match self.0 {
            Constant(ref val) => {
                let val = Mutex::new(val.clone()); // need Sync for T
                trigger.map(move |t| f(val.lock().clone(), t))
            }
            Dynamic(ref sf) => {
                let sf = sf.clone();
                trigger.map(move |t| f(sf(), t))
            }
        }
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using `try_recv`) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    where
        T: Clone,
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using `try_recv`) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
    where
        F: Fn(T, V) -> T + Send + Sync + 'static,
        T: Clone,
        V: Send + 'static,
    {
        let storage = Storage::new(initial);
        let rx = Mutex::new(rx);
        Signal::from_fn(move || {
            let source = rx.lock();
            if let Ok(first) = source.try_recv() {
                storage.replace_with(|old| {
                    let acc = f(old, first);
                    source.try_iter().fold(acc, &f)
                });
            }
            storage.get()
        })
    }
}

impl<T: Clone + 'static> Signal<Signal<T>> {
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T> {
        match self.0 {
            // constant signal: just extract the inner signal
            Constant(ref sig) => Signal::clone(sig),
            // dynamic signal: extract the inner signal and sample
            Dynamic(ref f) => {
                let f = f.clone();
                Signal::from_fn(move || f().sample())
            }
        }
    }
}

impl<T: Default> Default for Signal<T> {
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T> {
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self {
        Signal::constant(val)
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display + Clone> fmt::Display for Signal<T> {
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.sample(), f)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::RwLock;
    use std::time::Instant;

    #[test]
    fn signal_basic() {
        let signal = Signal::constant(42);
        let double = signal.map(|a| a * 2);
        let plusone = double.map(|a| a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
    }

    #[test]
    fn signal_dynamic() {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);

        let n = Arc::new(RwLock::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || *cloned.read().unwrap());
        let double = signal.map(|a| a * 2);
        let plusone = double.map(|a| a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        *n.write().unwrap() = 13;
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn signal_fold() {
        let sig1 = Signal::constant(1).fold(0, |a, n| a + n);
        let sig2 = Signal::from_fn(|| 1).fold(0, |a, n| a + n);

        assert_eq!(sig1.sample(), 1);
        assert_eq!(sig2.sample(), 1);

        assert_eq!(sig1.sample(), 2);
        assert_eq!(sig2.sample(), 2);
    }

    #[test]
    fn signal_const() {
        const THE_ANSWER: Signal<i32> = Signal::constant(42);

        assert_eq!(THE_ANSWER.sample(), 42);
    }
}
<commit_msg>reviewed Signal's trait bounds<commit_after>//! Signals are values that discretely change over time.

use crate::stream::Stream;
use crate::sync::Mutex;
use crate::types::{MaybeOwned, Storage};
use std::fmt;
use std::sync::{mpsc, Arc};

use self::SigValue::*;

/// Represents a discrete value that changes over time.
///
/// Signals are usually constructed by stream operations and can be read using the `sample` or
/// `take` methods. They update lazily when someone reads them.
#[derive(Clone, Debug)]
pub struct Signal<T>(SigValue<T>);

/// The content source of a signal.
#[derive(Clone)]
enum SigValue<T> {
    /// A signal with constant value.
    Constant(T),
    /// A signal that generates it's values from a function.
    ///
    /// This is produced by `Signal::from_fn`
    Dynamic(Arc<dyn Fn() -> T + Send + Sync>),
}

impl<T> Signal<T> {
    /// Creates a signal with constant value.
    ///
    /// The value is assumed to be constant, so changing it while it's stored on the
    /// signal is a logic error and will cause unexpected results.
    pub const fn constant(val: T) -> Self {
        Signal(Constant(val))
    }

    /// Creates a signal that samples it's values from an external source.
    ///
    /// The closure is meant to sample a continuous value from the real world,
    /// so the signal value is assumed to be always changing.
    pub fn from_fn<F>(f: F) -> Self
    where
        F: Fn() -> T + Send + Sync + 'static,
    {
        Signal(Dynamic(Arc::new(f)))
    }

    /// Creates a signal from shared storage.
    pub(crate) fn from_storage<S>(storage: Arc<Storage<T>>, source: S) -> Self
    where
        T: Clone + Send + 'static,
        S: Send + Sync + 'static,
    {
        Signal::from_fn(move || {
            let _keepalive = &source;
            storage.get()
        })
    }

    /// Samples the value of the signal.
    ///
    /// This will clone the value stored in the signal.
    pub fn sample(&self) -> T
    where
        T: Clone,
    {
        match self.0 {
            Constant(ref val) => T::clone(val),
            Dynamic(ref f) => f(),
        }
    }

    /// Maps a signal with the provided function.
    pub fn map<F, R>(&self, f: F) -> Signal<R>
    where
        F: Fn(T) -> R + Send + Sync + 'static,
        T: Clone + 'static,
    {
        match self.0 {
            // constant signal: apply f once to produce another constant signal
            Constant(ref val) => Signal::constant(f(val.clone())),
            // dynamic signal: sample and apply f
            Dynamic(ref sf) => {
                let sf = sf.clone();
                Signal::from_fn(move || f(sf()))
            }
        }
    }

    /// Folds a signal using the provided function.
    ///
    /// The folding operation will occur every time the signal is sampled.
    pub fn fold(&self, initial: A, f: F) -> Signal
    where
        F: Fn(A, T) -> A + Send + Sync + 'static,
        T: Clone + Send + Sync + 'static,
        A: Clone + Send + 'static,
    {
        match self.0 {
            Constant(ref val) => {
                let source = val.clone();
                let storage = Storage::new(initial);
                Signal::from_fn(move || {
                    let val = source.clone();
                    storage.replace_with(|acc| f(acc, val));
                    storage.get()
                })
            }
            Dynamic(ref sf) => {
                let sf = sf.clone();
                let storage = Storage::new(initial);
                Signal::from_fn(move || {
                    let val = sf();
                    storage.replace_with(|acc| f(acc, val));
                    storage.get()
                })
            }
        }
    }

    /// Samples the value of this signal every time the trigger stream fires.
    pub fn snapshot<S, F, R>(&self, trigger: &Stream<S>, f: F) -> Stream<R>
    where
        F: Fn(T, MaybeOwned<'_, S>) -> R + Send + Sync + 'static,
        T: Clone + Send + Sync + 'static,
        S: 'static,
        R: 'static,
    {
        match self.0 {
            Constant(ref val) => {
                let val = val.clone();
                trigger.map(move |t| f(val.clone(), t))
            }
            Dynamic(ref sf) => {
                let sf = sf.clone();
                trigger.map(move |t| f(sf(), t))
            }
        }
    }

    /// Stores the last value sent to a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using `try_recv`) and returns the last value seen.
    #[inline]
    pub fn from_channel(initial: T, rx: mpsc::Receiver<T>) -> Self
    where
        T: Clone + Send + 'static,
    {
        Self::fold_channel(initial, rx, |_, v| v)
    }

    /// Creates a signal that folds the values from a channel.
    ///
    /// When sampled, the resulting signal consumes all the current values on the channel
    /// (using `try_recv`) and folds them using the current signal value as the
    /// initial accumulator state.
    pub fn fold_channel<V, F>(initial: T, rx: mpsc::Receiver<V>, f: F) -> Self
    where
        F: Fn(T, V) -> T + Send + Sync + 'static,
        T: Clone + Send + 'static,
        V: Send + 'static,
    {
        let storage = Storage::new(initial);
        let rx = Mutex::new(rx);
        Signal::from_fn(move || {
            let source = rx.lock();
            if let Ok(first) = source.try_recv() {
                storage.replace_with(|old| {
                    let acc = f(old, first);
                    source.try_iter().fold(acc, &f)
                });
            }
            storage.get()
        })
    }
}

impl<T: Clone + 'static> Signal<Signal<T>> {
    /// Creates a new signal that samples the inner value of a nested signal.
    pub fn switch(&self) -> Signal<T> {
        match self.0 {
            // constant signal: just extract the inner signal
            Constant(ref sig) => Signal::clone(sig),
            // dynamic signal: extract the inner signal and sample
            Dynamic(ref f) => {
                let f = f.clone();
                Signal::from_fn(move || f().sample())
            }
        }
    }
}

impl<T: Default> Default for Signal<T> {
    /// Creates a constant signal with T's default value.
    #[inline]
    fn default() -> Self {
        Signal::constant(T::default())
    }
}

impl<T> From<T> for Signal<T> {
    /// Creates a constant signal from T.
    #[inline]
    fn from(val: T) -> Self {
        Signal::constant(val)
    }
}

impl<T: fmt::Debug> fmt::Debug for SigValue<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Constant(ref val) => write!(f, "Constant({:?})", val),
            Dynamic(ref rf) => write!(f, "Dynamic(Fn@{:p})", rf),
        }
    }
}

impl<T: fmt::Display + Clone> fmt::Display for Signal<T> {
    /// Samples the signal and formats the value.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.sample(), f)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::RwLock;
    use std::time::Instant;

    #[test]
    fn signal_basic() {
        let signal = Signal::constant(42);
        let double = signal.map(|a| a * 2);
        let plusone = double.map(|a| a + 1);
        assert_eq!(signal.sample(), 42);
        assert_eq!(double.sample(), 84);
        assert_eq!(plusone.sample(), 85);
    }

    #[test]
    fn signal_dynamic() {
        let t = Instant::now();
        let signal = Signal::from_fn(move || t);
        assert_eq!(signal.sample(), t);

        let n = Arc::new(RwLock::new(1));
        let cloned = n.clone();
        let signal = Signal::from_fn(move || *cloned.read().unwrap());
        let double = signal.map(|a| a * 2);
        let plusone = double.map(|a| a + 1);
        assert_eq!(signal.sample(), 1);
        assert_eq!(double.sample(), 2);
        assert_eq!(plusone.sample(), 3);
        *n.write().unwrap() = 13;
        assert_eq!(signal.sample(), 13);
        assert_eq!(double.sample(), 26);
        assert_eq!(plusone.sample(), 27);
    }

    #[test]
    fn signal_fold() {
        let sig1 = Signal::constant(1).fold(0, |a, n| a + n);
        let sig2 = Signal::from_fn(|| 1).fold(0, |a, n| a + n);

        assert_eq!(sig1.sample(), 1);
        assert_eq!(sig2.sample(), 1);

        assert_eq!(sig1.sample(), 2);
        assert_eq!(sig2.sample(), 2);
    }

    #[test]
    fn signal_const() {
        const THE_ANSWER: Signal<i32> = Signal::constant(42);

        assert_eq!(THE_ANSWER.sample(), 42);
    }
}
<|endoftext|>