<commit_before>extern crate time;

use time::{SteadyTime, Duration};
use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Debug;
use std::cmp::PartialEq;

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

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

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

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

    fn next(self) -> Task<Token> {
        Task {
            run_offset: self.run_offset + self.interval,
            .. self
        }
    }

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

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

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

pub struct SteadyTimeSource {
    offset: SteadyTime
}

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

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

type TimePoint = u64;

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

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

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

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

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

impl<Token> Scheduler<Token, SteadyTimeSource> where Token: Clone {
    //TODO: way to specify how many durations it is OK to consider task current
    pub fn new(time_point_interval: Duration) -> Scheduler<Token, SteadyTimeSource> {
        Scheduler::with_time_source(time_point_interval, SteadyTimeSource::new())
    }
}

impl<Token, TS> Scheduler<Token, TS> where TS: TimeSource, Token: Clone {
    pub fn with_time_source(time_point_interval: Duration, time_source: TS) -> Scheduler<Token, TS> {
        assert!(time_point_interval > Duration::seconds(0));
        Scheduler {
            time_point_interval: time_point_interval,
            tasks: BTreeMap::new(),
            time_source: time_source
        }
    }

    fn schedule(&mut self, task: Task<Token>) {
        let time_point = self.to_time_point(task.schedule());
        self.tasks.entry(time_point).or_insert(Vec::new()).push(task);
    }

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

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

    fn next_action(&self) -> SchedulerAction {
        let now = self.time_source.now();
        let current_time_point = self.to_time_point(now);

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

    pub fn next(&mut self) -> Option<Schedule<Token>> {
        match self.next_action() {
            SchedulerAction::None => None,
            SchedulerAction::Wait(duration) => {
                Some(Schedule::NextIn(duration))
            },
            SchedulerAction::Skip(time_points) => {
                let mut missed = Vec::new();

                missed.extend(self.consume(time_points));
                // collect all reschedules of consumed tasks if they end up missed already
                while let SchedulerAction::Skip(time_points) = self.next_action() {
                    missed.extend(self.consume(time_points));
                }
                Some(Schedule::Missed(missed))
            },
            SchedulerAction::Yield(time_point) => {
                Some(Schedule::Current(self.consume(vec![time_point])))
            }
        }
    }

    fn consume(&mut self, time_points: Vec<TimePoint>) -> Vec<Token> {
        let mut tasks: Vec<Task<Token>> = time_points.iter().flat_map(|time_point|
                self.tasks.remove(&time_point).unwrap()
            ).collect();

        tasks.sort_by(|a, b| a.run_offset.cmp(&b.run_offset));
        let tokens = tasks.iter().map(|ref task| task.token.clone()).collect();

        for task in tasks {
            match task.bond {
                TaskBond::Perpetual => self.schedule(task.next()),
                TaskBond::OneOff => ()
            };
        }
        tokens
    }

    fn to_time_point(&self, duration: Duration) -> TimePoint {
        let interval = self.time_point_interval.num_nanoseconds().expect("interval too large");
        let duration = duration.num_nanoseconds().expect("duration too large");
        assert!(duration >= 0);

        (duration / interval) as TimePoint
    }

    fn to_duration(&self, time_point: TimePoint) -> Duration {
        Duration::nanoseconds(self.time_point_interval.num_nanoseconds().expect("time point interval too large") * time_point as i64)
    }
}

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

#[cfg(test)]
mod test {
    use super::*;
    use super::{Task, TaskBond};
    use time::Duration;

    struct MockTimeSource {
        current_time: Duration
    }

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

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

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

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

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

    #[test]
    fn scheduler_to_time_point_limits() {
        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::nanoseconds(1));
        assert_eq!(scheduler.to_time_point(Duration::seconds(0)), 0);

        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::max_value() / 10);
        assert_eq!(scheduler.to_time_point(Duration::max_value() / 10), 0);
    }

    #[test]
    fn scheduler_to_duration() {
        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::seconds(1));
        assert_eq!(scheduler.to_duration(0), Duration::seconds(0));
        assert_eq!(scheduler.to_duration(1), Duration::seconds(1));
        assert_eq!(scheduler.to_duration(2), Duration::seconds(2));
    }

    #[test]
    fn scheduler_to_duration_limits() {
        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::nanoseconds(1));
        assert_eq!(scheduler.to_duration(0), Duration::nanoseconds(0));
        assert_eq!(scheduler.to_duration(1), Duration::nanoseconds(1));

        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::max_value() / 10);
        assert_eq!(scheduler.to_duration(0), Duration::seconds(0));
        assert_eq!(scheduler.to_duration(1), Duration::max_value() / 10);
    }

    #[test]
    fn scheduler_empty() {
        let mut scheduler: Scheduler<(), _> = Scheduler::new(Duration::seconds(1));
        assert_eq!(scheduler.next(), Option::None);
        assert_eq!(scheduler.next(), Option::None);
    }

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

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

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

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

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

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

        scheduler.fast_forward(Duration::milliseconds(600));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::milliseconds(400))));
        scheduler.fast_forward(Duration::milliseconds(500));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::milliseconds(900))));
    }

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

        scheduler.every(Duration::seconds(1), 1i32);
        scheduler.fast_forward(Duration::seconds(4));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Missed(vec![1, 1, 1])));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
    }

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

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

        scheduler.fast_forward(Duration::milliseconds(100));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::milliseconds(900))));

        let mut scheduler = Scheduler::with_time_source(Duration::max_value() / 10, MockTimeSource::new());

        scheduler.after(Duration::max_value() / 10, 1i32);
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::max_value() / 10)));
    }
}

<commit_msg>keeping limit of max 2**63 nanoseconds (299 years) - fixed tests<commit_after>extern crate time;

use time::{SteadyTime, Duration};
use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Debug;
use std::cmp::PartialEq;

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

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

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

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

    fn next(self) -> Task<Token> {
        Task {
            run_offset: self.run_offset + self.interval,
            .. self
        }
    }

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

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

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

pub struct SteadyTimeSource {
    offset: SteadyTime
}

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

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

type TimePoint = u64;

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

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

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

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

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

impl<Token> Scheduler<Token, SteadyTimeSource> where Token: Clone {
    //TODO: way to specify how many durations it is OK to consider task current
    pub fn new(time_point_interval: Duration) -> Scheduler<Token, SteadyTimeSource> {
        Scheduler::with_time_source(time_point_interval, SteadyTimeSource::new())
    }
}

impl<Token, TS> Scheduler<Token, TS> where TS: TimeSource, Token: Clone {
    pub fn with_time_source(time_point_interval: Duration, time_source: TS) -> Scheduler<Token, TS> {
        assert!(time_point_interval > Duration::seconds(0));
        Scheduler {
            time_point_interval: time_point_interval,
            tasks: BTreeMap::new(),
            time_source: time_source
        }
    }

    fn schedule(&mut self, task: Task<Token>) {
        let time_point = self.to_time_point(task.schedule());
        self.tasks.entry(time_point).or_insert(Vec::new()).push(task);
    }

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

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

    fn next_action(&self) -> SchedulerAction {
        let now = self.time_source.now();
        let current_time_point = self.to_time_point(now);

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

    pub fn next(&mut self) -> Option<Schedule<Token>> {
        match self.next_action() {
            SchedulerAction::None => None,
            SchedulerAction::Wait(duration) => {
                Some(Schedule::NextIn(duration))
            },
            SchedulerAction::Skip(time_points) => {
                let mut missed = Vec::new();

                missed.extend(self.consume(time_points));
                // collect all reschedules of consumed tasks if they end up missed already
                while let SchedulerAction::Skip(time_points) = self.next_action() {
                    missed.extend(self.consume(time_points));
                }
                Some(Schedule::Missed(missed))
            },
            SchedulerAction::Yield(time_point) => {
                Some(Schedule::Current(self.consume(vec![time_point])))
            }
        }
    }

    fn consume(&mut self, time_points: Vec<TimePoint>) -> Vec<Token> {
        let mut tasks: Vec<Task<Token>> = time_points.iter().flat_map(|time_point|
                self.tasks.remove(&time_point).unwrap()
            ).collect();

        tasks.sort_by(|a, b| a.run_offset.cmp(&b.run_offset));
        let tokens = tasks.iter().map(|ref task| task.token.clone()).collect();

        for task in tasks {
            match task.bond {
                TaskBond::Perpetual => self.schedule(task.next()),
                TaskBond::OneOff => ()
            };
        }
        tokens
    }

    fn to_time_point(&self, duration: Duration) -> TimePoint {
        // nanoseconds gives 15250 weeks or 299 years of duration max... should do?
        let interval = self.time_point_interval.num_nanoseconds().expect("interval too large");
        let duration = duration.num_nanoseconds().expect("duration too large");
        assert!(duration >= 0);

        (duration / interval) as TimePoint
    }

    fn to_duration(&self, time_point: TimePoint) -> Duration {
        Duration::nanoseconds(self.time_point_interval.num_nanoseconds().expect("time point interval too large") * time_point as i64)
    }
}

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

#[cfg(test)]
mod test {
    use super::*;
    use super::{Task, TaskBond};
    use time::Duration;

    struct MockTimeSource {
        current_time: Duration
    }

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

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

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

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

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

    #[test]
    fn scheduler_to_time_point_limits() {
        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::nanoseconds(1));
        assert_eq!(scheduler.to_time_point(Duration::seconds(0)), 0);

        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::weeks(15250) / 2);
        assert_eq!(scheduler.to_time_point(Duration::weeks(0)), 0);
        assert_eq!(scheduler.to_time_point(Duration::weeks(15250) / 2), 1);
        assert_eq!(scheduler.to_time_point(Duration::weeks(15250)), 2);
    }

    #[test]
    fn scheduler_to_duration() {
        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::seconds(1));
        assert_eq!(scheduler.to_duration(0), Duration::seconds(0));
        assert_eq!(scheduler.to_duration(1), Duration::seconds(1));
        assert_eq!(scheduler.to_duration(2), Duration::seconds(2));
    }

    #[test]
    fn scheduler_to_duration_limits() {
        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::nanoseconds(1));
        assert_eq!(scheduler.to_duration(0), Duration::nanoseconds(0));
        assert_eq!(scheduler.to_duration(1), Duration::nanoseconds(1));

        let scheduler: Scheduler<(), _> = Scheduler::new(Duration::weeks(15250) / 2);
        assert_eq!(scheduler.to_duration(0), Duration::seconds(0));
        assert_eq!(scheduler.to_duration(1), Duration::weeks(15250) / 2);
        assert_eq!(scheduler.to_duration(2), Duration::weeks(15250));
    }

    #[test]
    fn scheduler_empty() {
        let mut scheduler: Scheduler<(), _> = Scheduler::new(Duration::seconds(1));
        assert_eq!(scheduler.next(), Option::None);
        assert_eq!(scheduler.next(), Option::None);
    }

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

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

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

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

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

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

        scheduler.fast_forward(Duration::milliseconds(600));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::milliseconds(400))));
        scheduler.fast_forward(Duration::milliseconds(500));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::milliseconds(900))));
    }

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

        scheduler.every(Duration::seconds(1), 1i32);
        scheduler.fast_forward(Duration::seconds(4));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Missed(vec![1, 1, 1])));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
    }

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

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

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

        scheduler.after(Duration::weeks(15250), 2);
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::weeks(15250))));

        scheduler.fast_forward(Duration::weeks(15250));
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![2])));

        let mut scheduler = Scheduler::with_time_source(Duration::weeks(15250) / 2, MockTimeSource::new());

        scheduler.after(Duration::weeks(15250) / 2, 1);
        assert_eq!(scheduler.next(), Option::Some(Schedule::NextIn(Duration::weeks(15250) / 2)));

        scheduler.fast_forward(Duration::weeks(15250) / 2);
        assert_eq!(scheduler.next(), Option::Some(Schedule::Current(vec![1])));
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! simple_slab provides a fast, minimal, slab allocator.
//! ## Usage
//!
//! ```no_run
//! extern crate simple_slab;
//!
//! use simple_slab::Slab;
//!
//! fn main() {
//!     const MAX_ELEMS: usize = 100000;
//!
//!     let mut slab = Slab::<u32>::new(MAX_ELEMS);
//!
//!     // Insertion
//!     for num in 0..MAX_ELEMS {
//!         slab.insert(num as u32);
//!     }
//!
//!     // Traversal
//!     for offset in 0..slab.len() {
//!         match slab[offset] {
//!             Some(num) => {
//!                 // Stuff...
//!             }
//!             None => {
//!                 // Stuff...
//!             }
//!         }
//!     }
//!
//!     // Iteration
//!     for num in slab.iter() {
//!         // Stuff...
//!     }
//!
//!     // Removal
//!     for offset in 0..slab.len() {
//!         let num = slab.remove(offset).unwrap();
//!     }
//! }
//! ```

use std::{mem, ops};
use std::iter::{Iterator, IntoIterator};

#[derive(Clone)]
/// Pre-allocated chunk of memory sized specifically for `T`
pub struct Slab<T> {
    num_elems: usize,
    buf: Vec<Option<T>>
}

impl<T> Slab<T> {
    /// Creates a new Slab with initial room without re-allocation for `capacity` num elements.
    pub fn new(capacity: usize) -> Slab<T> {
        let mut buf = Vec::<Option<T>>::with_capacity(capacity);
        for _ in 0..capacity {
            buf.push(None);
        }

        Slab {
            num_elems: 0,
            buf: buf
        }
    }

    /// Inserts a new element into the slab, re-allocating if neccessary.
    ///
    /// # Panics
    /// Panics if re-allocation overflows `usize`.
    #[inline]
    pub fn insert(&mut self, elem: T) {
        if self.num_elems == self.buf.len() {
            let extra_mem = self.num_elems * 2;
            self.allocate_exact(extra_mem);
        }

        self.buf[self.num_elems] = Some(elem);

        // Update counts
        self.num_elems += 1;
    }

    /// Remove the element at `offset`.
    ///
    /// # Panics
    /// Panics if `offset` is out of bounds.
    #[inline]
    pub fn remove(&mut self, offset: usize) -> Option<T> {
        self.num_elems -= 1;

        // Removal of only element
        if self.num_elems == 0 {
            return mem::replace(&mut self.buf[0], None);
        }

        // Removal of last element in buf
        if offset == self.num_elems {
            return mem::replace(&mut self.buf[self.num_elems], None);
        }

        // Removal of any other element
        self.buf.swap(offset, self.num_elems);
        mem::replace(&mut self.buf[self.num_elems], None)
    }

    /// Returns the number of elements in the slab.
    #[inline]
    pub fn len(&self) -> usize {
        self.num_elems
    }

    /// Returns an iterator over the slab.
    #[inline]
    pub fn iter(&self) -> SlabIter<T>  {
        SlabIter {
            slab: self,
            current_offset: 0
        }
    }

    /// Returns a mutable iterator over the slab
    #[inline]
    pub fn iter_mut(&mut self) -> SlabMutIter<T> {
        SlabMutIter {
            iter: self.iter()
        }
    }

    #[inline]
    fn allocate_exact(&mut self, size: usize) {
        // Allocate extra space inside buffer
        self.buf.reserve_exact(size);

        // Fill the extra space with tombstones
        for _ in 0..size {
            self.buf.push(None);
        }
    }
}

impl<T> ops::Index<usize> for Slab<T> {
    type Output = Option<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &(self.buf[index])
    }
}

impl<T> ops::IndexMut<usize> for Slab<T> {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Option<T> {
        &mut (self.buf[index])
    }
}

pub struct SlabIter<'a, T: 'a> {
    current_offset: usize,
    slab: &'a Slab<T>
}

pub struct SlabMutIter<'a, T: 'a> {
    iter: SlabIter<'a, T>
}

impl<'a, T> Iterator for SlabIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        while self.current_offset < self.slab.len() {
            match self.slab.buf[self.current_offset] {
                Some(ref elem) => {
                    self.current_offset += 1;
                    return Some(elem);
                }
                None => self.current_offset += 1
            }
        }

        None
    }
}

impl<'a, T> Iterator for SlabMutIter<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<&'a mut T> {
        unsafe { mem::transmute(self.iter.next()) }
    }
}

impl<'a, T> IntoIterator for &'a Slab<T> {
    type Item = &'a T;
    type IntoIter = SlabIter<'a, T>;
    fn into_iter(self) -> SlabIter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Slab<T> {
    type Item = &'a mut T;
    type IntoIter = SlabMutIter<'a, T>;
    fn into_iter(self) -> SlabMutIter<'a, T> {
        self.iter_mut()
    }
}

unsafe impl<T: Send> Send for Slab<T> {}
unsafe impl<T: Sync> Sync for Slab<T> {}
<commit_msg>Travis trigger<commit_after>// Copyright 2016 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! simple_slab provides a fast, minimal, slab allocator.
//! ## Usage
//!
//! ```no_run
//! extern crate simple_slab;
//!
//! use simple_slab::Slab;
//!
//! fn main() {
//!     const MAX_ELEMS: usize = 100000;
//!
//!     let mut slab = Slab::<u32>::new(MAX_ELEMS);
//!
//!     // Insertion
//!     for num in 0..MAX_ELEMS {
//!         slab.insert(num as u32);
//!     }
//!
//!     // Traversal
//!     for offset in 0..slab.len() {
//!         match slab[offset] {
//!             Some(num) => {
//!                 // Stuff...
//!             }
//!             None => {
//!                 // Stuff...
//!             }
//!         }
//!     }
//!
//!     // Iteration
//!     for num in slab.iter() {
//!         // Stuff...
//!     }
//!
//!     // Removal
//!     for offset in 0..slab.len() {
//!         let num = slab.remove(offset).unwrap();
//!     }
//! }
//! ```

use std::{mem, ops};
use std::iter::{Iterator, IntoIterator};

#[derive(Clone)]
/// Pre-allocated chunk of memory sized specifically for `T`
pub struct Slab<T> {
    num_elems: usize,
    buf: Vec<Option<T>>
}

impl<T> Slab<T> {
    /// Creates a new Slab with initial room without re-allocation for `capacity` num elements.
    pub fn new(capacity: usize) -> Slab<T> {
        let mut buf = Vec::<Option<T>>::with_capacity(capacity);
        for _ in 0..capacity {
            buf.push(None);
        }

        Slab {
            num_elems: 0,
            buf: buf
        }
    }

    /// Inserts a new element into the slab, re-allocating if neccessary.
    ///
    /// # Panics
    /// Panics if re-allocation overflows `usize`.
    #[inline]
    pub fn insert(&mut self, elem: T) {
        if self.num_elems == self.buf.len() {
            let extra_mem = self.num_elems * 2;
            self.allocate_exact(extra_mem);
        }

        // Add new element
        self.buf[self.num_elems] = Some(elem);

        // Update counts
        self.num_elems += 1;
    }

    /// Remove the element at `offset`.
    ///
    /// # Panics
    /// Panics if `offset` is out of bounds.
    #[inline]
    pub fn remove(&mut self, offset: usize) -> Option<T> {
        self.num_elems -= 1;

        // Removal of only element
        if self.num_elems == 0 {
            return mem::replace(&mut self.buf[0], None);
        }

        // Removal of last element in buf
        if offset == self.num_elems {
            return mem::replace(&mut self.buf[self.num_elems], None);
        }

        // Removal of any other element
        self.buf.swap(offset, self.num_elems);
        mem::replace(&mut self.buf[self.num_elems], None)
    }

    /// Returns the number of elements in the slab.
    #[inline]
    pub fn len(&self) -> usize {
        self.num_elems
    }

    /// Returns an iterator over the slab.
    #[inline]
    pub fn iter(&self) -> SlabIter<T>  {
        SlabIter {
            slab: self,
            current_offset: 0
        }
    }

    /// Returns a mutable iterator over the slab
    #[inline]
    pub fn iter_mut(&mut self) -> SlabMutIter<T> {
        SlabMutIter {
            iter: self.iter()
        }
    }

    #[inline]
    fn allocate_exact(&mut self, size: usize) {
        // Allocate extra space inside buffer
        self.buf.reserve_exact(size);

        // Fill the extra space with tombstones
        for _ in 0..size {
            self.buf.push(None);
        }
    }
}

impl<T> ops::Index<usize> for Slab<T> {
    type Output = Option<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &(self.buf[index])
    }
}

impl<T> ops::IndexMut<usize> for Slab<T> {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Option<T> {
        &mut (self.buf[index])
    }
}

pub struct SlabIter<'a, T: 'a> {
    current_offset: usize,
    slab: &'a Slab<T>
}

pub struct SlabMutIter<'a, T: 'a> {
    iter: SlabIter<'a, T>
}

impl<'a, T> Iterator for SlabIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        while self.current_offset < self.slab.len() {
            match self.slab.buf[self.current_offset] {
                Some(ref elem) => {
                    self.current_offset += 1;
                    return Some(elem);
                }
                None => self.current_offset += 1
            }
        }

        None
    }
}

impl<'a, T> Iterator for SlabMutIter<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<&'a mut T> {
        unsafe { mem::transmute(self.iter.next()) }
    }
}

impl<'a, T> IntoIterator for &'a Slab<T> {
    type Item = &'a T;
    type IntoIter = SlabIter<'a, T>;
    fn into_iter(self) -> SlabIter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Slab<T> {
    type Item = &'a mut T;
    type IntoIter = SlabMutIter<'a, T>;
    fn into_iter(self) -> SlabMutIter<'a, T> {
        self.iter_mut()
    }
}

unsafe impl<T: Send> Send for Slab<T> {}
unsafe impl<T: Sync> Sync for Slab<T> {}
<|endoftext|>


<commit_before>#![warn(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`)
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(missing_docs)]
    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(missing_docs)]
    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    #[allow(missing_docs)]
    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[allow(missing_docs)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    #[allow(missing_docs)]
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    #[allow(missing_docs)]
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    #[allow(missing_docs)]
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        //input_rebind.keymap = self.keymap.btn_map.
        //input_rebind.keymap = self.keymap.btn_map.drain().map(|(k, v)| (v, k)).collect();
        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

<commit_msg>Remove unnecessary newline<commit_after>#![warn(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`)
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(missing_docs)]
    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(missing_docs)]
    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    #[allow(missing_docs)]
    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[allow(missing_docs)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    #[allow(missing_docs)]
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    #[allow(missing_docs)]
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    #[allow(missing_docs)]
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        //input_rebind.keymap = self.keymap.btn_map.
        //input_rebind.keymap = self.keymap.btn_map.drain().map(|(k, v)| (v, k)).collect();
        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

<|endoftext|>


<commit_before>#![feature(alloc_system)]

extern crate alloc_system;
extern crate libc;
extern crate rustbox;

mod cmd;
mod tui;
mod utils;
pub mod msg;
pub mod msg_area;
pub mod text_field;

use std::borrow::Borrow;
use std::error::Error;
use std::ffi::CString;
use std::io::Read;
use std::io::Write;
use std::io;
use std::mem;
use std::net::TcpStream;
use std::os::unix::io::AsRawFd;
use std::str;
use std::time::Duration;

use cmd::Cmd;
use tui::{TUI, TUIRet};
use utils::find_byte;

pub struct Tiny {
    /// Buffer used to read bytes from the socket.
    read_buf : [u8; 512],

    /// _Partial_ messages collected here until they make a complete message.
    msg_buf  : Vec<u8>,

    /// TCP stream to the IRC server.
    stream   : Option<TcpStream>,
}

#[derive(PartialEq, Eq)]
enum LoopRet { Abort, Continue, Disconnected }

impl Tiny {
    pub fn new() -> Tiny {
        Tiny {
            read_buf: [0; 512],
            msg_buf: Vec::new(),
            stream: None,
        }
    }

    pub fn mainloop(&mut self) {
        let mut tui = TUI::new();

        loop {
            match self.stream {
                None => {
                    if self.mainloop_no_stream(&mut tui) == LoopRet::Abort { break; }
                },
                Some(_) => {
                    if self.mainloop_stream(&mut tui) == LoopRet::Abort { break; }
                }
            }
        }
    }

    fn mainloop_no_stream(&mut self, tui : &mut TUI) -> LoopRet {
        // I want my tail calls back
        loop {
            match tui.idle_loop() {
                TUIRet::SendMsg(cmd) => {
                    if cmd[0] == '/' {
                        // a command attempt
                        match Cmd::parse(&cmd) {
                            Ok(Cmd::Connect(server)) => {
                                writeln!(io::stderr(), "trying to connect: {}", server).unwrap();
                                match TcpStream::connect::<&str>(server.borrow()) {
                                    Err(err) => {
                                        tui.show_conn_error(err.description());
                                    },
                                    Ok(stream) => {
                                        self.stream = Some(stream);
                                        return LoopRet::Continue;
                                    }
                                }
                            },
                            // Ok(_) => {
                            //     tui.show_conn_error("Not connected.");
                            // },
                            Err(err_msg) => {
                                tui.show_user_error(err_msg.borrow());
                            }
                        }
                    } else {
                        // Trying to send a message - not going to happen
                        tui.show_user_error("Can't send message - not connected to a server.");
                    }
                },
                TUIRet::Abort => { return LoopRet::Abort; },
                ret => {
                    panic!("TUI.idle_loop() returned unexpected ret value: {:?}", ret);
                }
            }
        }
    }

    fn mainloop_stream(&mut self, tui : &mut TUI) -> LoopRet {

        ////////////////////
        // Set up the socket

        // Why can't disable the timeout?
        self.stream.as_ref().unwrap().set_read_timeout(Some(Duration::from_millis(1))).unwrap();
        self.stream.as_ref().unwrap().set_write_timeout(None).unwrap();
        self.stream.as_ref().unwrap().set_nodelay(true).unwrap();

        //////////////////////////////////////
        // Set up the descriptors for select()

        let stream_fd = self.stream.as_ref().unwrap().as_raw_fd();

        let mut fd_set : libc::fd_set = unsafe { mem::zeroed() };
        unsafe {
            // 0 is stdin
            libc::FD_SET(0, &mut fd_set);
            libc::FD_SET(stream_fd, &mut fd_set);
        }

        let nfds = stream_fd + 1;

        /////////////////
        // Start the loop

        self.mainloop_stream_(tui, fd_set, stream_fd, nfds)
    }

    fn mainloop_stream_(&mut self, tui : &mut TUI,
                        fd_set    : libc::fd_set,
                        stream_fd : libc::c_int,
                        nfds      : libc::c_int) -> LoopRet {
        loop {
            tui.draw();

            let mut fd_set_ = fd_set.clone();
            let ret =
                unsafe {
                    libc::select(nfds,
                                 &mut fd_set_,           // read fds
                                 std::ptr::null_mut(),   // write fds
                                 std::ptr::null_mut(),   // error fds
                                 std::ptr::null_mut())   // timeval
                };

            if ret == -1 {
                let err_c_msg =
                    unsafe { CString::from_raw(libc::strerror(*libc::__errno_location())) };

                tui.show_conn_error(
                    format!("Internal error: select() failed: {}",
                            err_c_msg.to_str().unwrap()).borrow());
            }

            // stdin is ready
            else if unsafe { libc::FD_ISSET(0, &mut fd_set_) } {
                if self.handle_stdin(tui) == LoopRet::Abort { return LoopRet::Abort; }
            }

            // Socket is ready
            else if unsafe { libc::FD_ISSET(stream_fd, &mut fd_set_) } {
                // TODO: Handle disconnects
                match self.handle_socket(tui) {
                    LoopRet::Abort => { return LoopRet::Abort; },
                    LoopRet::Disconnected => {
                        self.reset_state();
                        return LoopRet::Disconnected;
                    },
                    LoopRet::Continue => {}
                }
                if self.handle_socket(tui) == LoopRet::Abort { return LoopRet::Abort; }
            }
        }
    }

    fn handle_stdin(&mut self, tui : &mut TUI) -> LoopRet {
        match tui.keypressed() {
            TUIRet::Abort => LoopRet::Abort,
            TUIRet::EventIgnored(_) => {
                // TODO: What to do here?
                LoopRet::Continue
            },
            TUIRet::SendMsg(mut msg) => {
                // Add CR-LF and send
                msg.push('\r');
                msg.push('\n');
                {
                    let msg_str : String = msg.iter().cloned().collect();
                    self.stream.as_ref()
                               .unwrap()
                               .write_all(msg_str.as_bytes()).unwrap();
                }

                // Use another version without CR-LF to show the message
                {
                    let msg_slice : &[char] = msg.borrow();
                    let msg_slice : &[char] = &msg_slice[ 0 .. msg.len() - 2]; // Drop CRLF
                    let msg_str : String = msg_slice.iter().cloned().collect();
                    let msg_slice : &str = msg_str.borrow();
                    writeln!(io::stderr(), "sending msg: {}", msg_slice).unwrap();
                    tui.show_outgoing_msg(msg_slice);
                }

                LoopRet::Continue
            },
            _ => LoopRet::Continue
        }
    }

    fn handle_socket(&mut self, tui : &mut TUI) -> LoopRet {
        // Handle disconnects
        match self.stream.as_ref().unwrap().read(&mut self.read_buf) {
            Err(_) => {
                // TODO: I don't understand why this happens. I'm randomly
                // getting "temporarily unavailable" errors.
                // tui.show_conn_error(format!("Connection lost: {}", err).borrow());
                // return LoopRet::Disconnected;
            },
            Ok(bytes_read) => {
                if bytes_read == 0 {
                    tui.show_conn_error("Connection lost");
                    return LoopRet::Disconnected;
                }
            }
        }

        // Have we read any CRLFs? In that case just process the message and
        // update the buffers. Otherwise just push the partial message to the
        // buffer.
        {
            // (Creating a new scope for read_buf_)
            let mut read_buf_ : &[u8] = &self.read_buf;
            loop {
                match find_byte(read_buf_, b'\r') {
                    None => {
                        // Push the partial message to the message buffer, keep
                        // reading until a complete message is read.
                        match find_byte(read_buf_, 0) {
                            None => {
                                self.msg_buf.extend_from_slice(read_buf_);
                            },
                            Some(slice_end) => {
                                self.msg_buf.extend_from_slice(&read_buf_[ 0 .. slice_end ]);
                            }
                        };
                        break;
                    },
                    Some(cr_idx) => {
                        self.msg_buf.extend_from_slice(&read_buf_[ 0 .. cr_idx ]);
                        match str::from_utf8(self.msg_buf.borrow()) {
                            Err(err) =>
                                tui.show_conn_error(
                                    format!("Can't parse incoming message: {}", err).borrow()),
                            Ok(str) => tui.show_incoming_msg(str),
                        }

                        self.msg_buf.clear();

                        // Next char should be NL, skip that.
                        read_buf_ = &read_buf_[ cr_idx + 2 .. ];
                    }
                }
            }
        }

        self.read_buf = unsafe { mem::zeroed() };

        LoopRet::Continue
    }

    fn reset_state(&mut self) {
        self.stream = None;
        self.msg_buf.clear();
    }
}
<commit_msg>a bug when we only read() CR without LF<commit_after>#![feature(alloc_system)]

extern crate alloc_system;
extern crate libc;
extern crate rustbox;

mod cmd;
mod tui;
mod utils;
pub mod msg;
pub mod msg_area;
pub mod text_field;

use std::borrow::Borrow;
use std::error::Error;
use std::ffi::CString;
use std::io::Read;
use std::io::Write;
use std::io;
use std::mem;
use std::net::TcpStream;
use std::os::unix::io::AsRawFd;
use std::str;
use std::time::Duration;

use cmd::Cmd;
use tui::{TUI, TUIRet};
use utils::find_byte;

pub struct Tiny {
    /// Buffer used to read bytes from the socket.
    read_buf : [u8; 512],

    /// _Partial_ messages collected here until they make a complete message.
    msg_buf  : Vec<u8>,

    /// TCP stream to the IRC server.
    stream   : Option<TcpStream>,
}

#[derive(PartialEq, Eq)]
enum LoopRet { Abort, Continue, Disconnected }

impl Tiny {
    pub fn new() -> Tiny {
        Tiny {
            read_buf: [0; 512],
            msg_buf: Vec::new(),
            stream: None,
        }
    }

    pub fn mainloop(&mut self) {
        let mut tui = TUI::new();

        loop {
            match self.stream {
                None => {
                    if self.mainloop_no_stream(&mut tui) == LoopRet::Abort { break; }
                },
                Some(_) => {
                    if self.mainloop_stream(&mut tui) == LoopRet::Abort { break; }
                }
            }
        }
    }

    fn mainloop_no_stream(&mut self, tui : &mut TUI) -> LoopRet {
        // I want my tail calls back
        loop {
            match tui.idle_loop() {
                TUIRet::SendMsg(cmd) => {
                    if cmd[0] == '/' {
                        // a command attempt
                        match Cmd::parse(&cmd) {
                            Ok(Cmd::Connect(server)) => {
                                writeln!(io::stderr(), "trying to connect: {}", server).unwrap();
                                match TcpStream::connect::<&str>(server.borrow()) {
                                    Err(err) => {
                                        tui.show_conn_error(err.description());
                                    },
                                    Ok(stream) => {
                                        self.stream = Some(stream);
                                        return LoopRet::Continue;
                                    }
                                }
                            },
                            // Ok(_) => {
                            //     tui.show_conn_error("Not connected.");
                            // },
                            Err(err_msg) => {
                                tui.show_user_error(err_msg.borrow());
                            }
                        }
                    } else {
                        // Trying to send a message - not going to happen
                        tui.show_user_error("Can't send message - not connected to a server.");
                    }
                },
                TUIRet::Abort => { return LoopRet::Abort; },
                ret => {
                    panic!("TUI.idle_loop() returned unexpected ret value: {:?}", ret);
                }
            }
        }
    }

    fn mainloop_stream(&mut self, tui : &mut TUI) -> LoopRet {

        ////////////////////
        // Set up the socket

        // Why can't disable the timeout?
        self.stream.as_ref().unwrap().set_read_timeout(Some(Duration::from_millis(1))).unwrap();
        self.stream.as_ref().unwrap().set_write_timeout(None).unwrap();
        self.stream.as_ref().unwrap().set_nodelay(true).unwrap();

        //////////////////////////////////////
        // Set up the descriptors for select()

        let stream_fd = self.stream.as_ref().unwrap().as_raw_fd();

        let mut fd_set : libc::fd_set = unsafe { mem::zeroed() };
        unsafe {
            // 0 is stdin
            libc::FD_SET(0, &mut fd_set);
            libc::FD_SET(stream_fd, &mut fd_set);
        }

        let nfds = stream_fd + 1;

        /////////////////
        // Start the loop

        self.mainloop_stream_(tui, fd_set, stream_fd, nfds)
    }

    fn mainloop_stream_(&mut self, tui : &mut TUI,
                        fd_set    : libc::fd_set,
                        stream_fd : libc::c_int,
                        nfds      : libc::c_int) -> LoopRet {
        loop {
            tui.draw();

            let mut fd_set_ = fd_set.clone();
            let ret =
                unsafe {
                    libc::select(nfds,
                                 &mut fd_set_,           // read fds
                                 std::ptr::null_mut(),   // write fds
                                 std::ptr::null_mut(),   // error fds
                                 std::ptr::null_mut())   // timeval
                };

            if ret == -1 {
                let err_c_msg =
                    unsafe { CString::from_raw(libc::strerror(*libc::__errno_location())) };

                tui.show_conn_error(
                    format!("Internal error: select() failed: {}",
                            err_c_msg.to_str().unwrap()).borrow());
            }

            // stdin is ready
            else if unsafe { libc::FD_ISSET(0, &mut fd_set_) } {
                if self.handle_stdin(tui) == LoopRet::Abort { return LoopRet::Abort; }
            }

            // Socket is ready
            else if unsafe { libc::FD_ISSET(stream_fd, &mut fd_set_) } {
                // TODO: Handle disconnects
                match self.handle_socket(tui) {
                    LoopRet::Abort => { return LoopRet::Abort; },
                    LoopRet::Disconnected => {
                        self.reset_state();
                        return LoopRet::Disconnected;
                    },
                    LoopRet::Continue => {}
                }
                if self.handle_socket(tui) == LoopRet::Abort { return LoopRet::Abort; }
            }
        }
    }

    fn handle_stdin(&mut self, tui : &mut TUI) -> LoopRet {
        match tui.keypressed() {
            TUIRet::Abort => LoopRet::Abort,
            TUIRet::EventIgnored(_) => {
                // TODO: What to do here?
                LoopRet::Continue
            },
            TUIRet::SendMsg(mut msg) => {
                // Add CR-LF and send
                msg.push('\r');
                msg.push('\n');
                {
                    let msg_str : String = msg.iter().cloned().collect();
                    self.stream.as_ref()
                               .unwrap()
                               .write_all(msg_str.as_bytes()).unwrap();
                }

                // Use another version without CR-LF to show the message
                {
                    let msg_slice : &[char] = msg.borrow();
                    let msg_slice : &[char] = &msg_slice[ 0 .. msg.len() - 2]; // Drop CRLF
                    let msg_str : String = msg_slice.iter().cloned().collect();
                    let msg_slice : &str = msg_str.borrow();
                    writeln!(io::stderr(), "sending msg: {}", msg_slice).unwrap();
                    tui.show_outgoing_msg(msg_slice);
                }

                LoopRet::Continue
            },
            _ => LoopRet::Continue
        }
    }

    fn handle_socket(&mut self, tui : &mut TUI) -> LoopRet {
        // Handle disconnects
        match self.stream.as_ref().unwrap().read(&mut self.read_buf) {
            Err(_) => {
                // TODO: I don't understand why this happens. I'm randomly
                // getting "temporarily unavailable" errors.
                // tui.show_conn_error(format!("Connection lost: {}", err).borrow());
                // return LoopRet::Disconnected;
            },
            Ok(bytes_read) => {
                if bytes_read == 0 {
                    tui.show_conn_error("Connection lost");
                    return LoopRet::Disconnected;
                }
            }
        }

        // Have we read any CRLFs? In that case just process the message and
        // update the buffers. Otherwise just push the partial message to the
        // buffer.
        {
            // (Creating a new scope for read_buf_)
            let mut read_buf_ : &[u8] = &self.read_buf;
            loop {
                match find_byte(read_buf_, b'\r') {
                    None => {
                        // Push the partial message to the message buffer, keep
                        // reading until a complete message is read.
                        match find_byte(read_buf_, 0) {
                            None => {
                                self.msg_buf.extend_from_slice(read_buf_);
                            },
                            Some(slice_end) => {
                                self.msg_buf.extend_from_slice(&read_buf_[ 0 .. slice_end ]);
                            }
                        };
                        break;
                    },
                    Some(cr_idx) => {
                        // We have a CR, however, we don't have any guarantees
                        // that a single read() will read both CR and LF. So if
                        // we have a CR, but that's the last byte, we should
                        // just push the whole thing to the msg_buf so that when
                        // we read NL in the next read() we get a whole mssage.
                        if cr_idx == read_buf_.len() - 1 {
                            self.msg_buf.extend_from_slice(read_buf_);
                            break;
                        } else {
                            self.msg_buf.extend_from_slice(&read_buf_[ 0 .. cr_idx ]);
                            match str::from_utf8(self.msg_buf.borrow()) {
                                Err(err) =>
                                    tui.show_conn_error(
                                        format!("Can't parse incoming message: {}", err).borrow()),
                                        Ok(str) => tui.show_incoming_msg(str),
                            }

                            self.msg_buf.clear();

                            // Next char is NL, drop that too.
                            read_buf_ = &read_buf_[ cr_idx + 2 .. ];
                        }
                    }
                }
            }
        }

        self.read_buf = unsafe { mem::zeroed() };

        LoopRet::Continue
    }

    fn reset_state(&mut self) {
        self.stream = None;
        self.msg_buf.clear();
    }
}
<|endoftext|>


<commit_before>extern crate regex;
use std::fmt::{Debug, Formatter, Result};
macro_rules! pp {
    ($msg:expr) => {{
        println!("{:?}", $msg);
    }};
}

mod Warc{
    use std::collections::HashMap;
    pub fn parse(data: &String) -> Vec<Record>{
        let mut header = HashMap::new();
        let mut attr = HashMap::new();
        let mut records: Vec<Record> = Vec::new();
        let mut current_record: Option<Record> = None;
        let mut data_chars: Vec<char> = data.chars().collect();
        let mut next_new_line = 0;
        let mut ended = false;
        'outer: loop{
            pp!(data_chars);
            loop {
                match data_chars.get(next_new_line) {
                    Some(n) => {
                        next_new_line = next_new_line+1;
                        if n.eq(&'\n'){
                            break;
                        }
                    },
                    None => {
                        ended = true;
                        break;
                    }
                }
            }
            pp!(next_new_line);
            pp!(ended);
            let (s, data_chars) =data_chars.split_at(next_new_line);
            pp!(s);
            pp!(data_chars);
            if ended{ break;}
        }
        return vec![Record::new(attr,  Header::new(header), "".to_string())]
    }

    pub struct Record{
        attributes: HashMap<String, String>,
        header: Header,
        content: String,
    }
    impl Record{
        fn new(attributes: HashMap<String, String>, header: Header, content: String) -> Record {
            Record{header: header, content: content, attributes: attributes}
        }
    }

    pub struct Header{
        fields: HashMap<String, String>,
    }
    impl Header{
        fn new(fields: HashMap<String, String>) -> Header {
            Header{fields: fields}
        }
    }
}

#[test]
fn it_debugs() {
    let s= "s
    s".to_string();
    let warc = Warc::parse(&s);
}
<commit_msg>IRC talchas explained how it should work<commit_after>extern crate regex;
use std::fmt::{Debug, Formatter, Result};
macro_rules! pp {
    ($msg:expr) => {{
        println!("{:?}", $msg);
    }};
}

mod Warc{
    use std::collections::HashMap;
    pub fn parse(data: &String) -> Vec<Record>{
        let mut header = HashMap::new();
        let mut attr = HashMap::new();
        let mut records: Vec<Record> = Vec::new();
        let mut current_record: Option<Record> = None;
        let mut data_chars_: Vec<char> = data.chars().collect();
        let mut data_chars = &data_chars_[..];
        let mut next_new_line = 0;
        let mut ended = false;
        'outer: loop{
            pp!(data_chars);
            loop {
                match data_chars.get(next_new_line) {
                    Some(n) => {
                        next_new_line = next_new_line+1;
                        if n.eq(&'\n'){
                            break;
                        }
                    },
                    None => {
                        ended = true;
                        break;
                    }
                }
            }
            pp!(next_new_line);
            pp!(ended);
            let (s, rest) =data_chars.split_at(next_new_line);
            pp!(s);
            pp!(rest);
            data_chars = rest;
            if ended{ break;}
        }
        return vec![Record::new(attr,  Header::new(header), "".to_string())]
    }

    pub struct Record{
        attributes: HashMap<String, String>,
        header: Header,
        content: String,
    }
    impl Record{
        fn new(attributes: HashMap<String, String>, header: Header, content: String) -> Record {
            Record{header: header, content: content, attributes: attributes}
        }
    }

    pub struct Header{
        fields: HashMap<String, String>,
    }
    impl Header{
        fn new(fields: HashMap<String, String>) -> Header {
            Header{fields: fields}
        }
    }
}

#[test]
fn it_debugs() {
    let s= "s
    s".to_string();
    let warc = Warc::parse(&s);
}
<|endoftext|>