<commit_before>use std::collections::BinaryHeap;
use std::cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
use std::sync::{Arc, Mutex, Condvar};
use std::thread;
use time::Duration;
use time;

use thunk::Thunk;

enum JobType {
    Once(Thunk<'static>),
    FixedRate {
        f: Box<FnMut() + Send + 'static>,
        rate: Duration,
    },
}

struct Job {
    type_: JobType,
    time: u64,
}

impl PartialOrd for Job {
    fn partial_cmp(&self, other: &Job) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Job {
    fn cmp(&self, other: &Job) -> Ordering {
        // reverse because BinaryHeap's a max heap
        self.time.cmp(&other.time).reverse()
    }
}

impl PartialEq for Job {
    fn eq(&self, other: &Job) -> bool {
        self.time == other.time
    }
}

impl Eq for Job {}

struct InnerPool {
    queue: BinaryHeap<Job>,
    shutdown: bool,
}

struct SharedPool {
    inner: Mutex<InnerPool>,
    cvar: Condvar,
}

impl SharedPool {
    fn run(&self, job: Job) {
        let mut inner = self.inner.lock().unwrap();

        // Calls from the pool itself will never hit this, but calls from workers might
        if inner.shutdown {
            return;
        }

        match inner.queue.peek() {
            None => self.cvar.notify_all(),
            Some(e) if e.time > job.time => self.cvar.notify_all(),
            _ => {}
        };
        inner.queue.push(job);
    }
}

pub struct ScheduledThreadPool {
    shared: Arc<SharedPool>,
}

impl Drop for ScheduledThreadPool {
    fn drop(&mut self) {
        self.shared.inner.lock().unwrap().shutdown = true;
        self.shared.cvar.notify_all();
    }
}

impl ScheduledThreadPool {
    pub fn new(size: usize) -> ScheduledThreadPool {
        assert!(size > 0, "size must be positive");

        let inner = InnerPool {
            queue: BinaryHeap::new(),
            shutdown: false,
        };

        let shared = SharedPool {
            inner: Mutex::new(inner),
            cvar: Condvar::new(),
        };

        let pool = ScheduledThreadPool {
            shared: Arc::new(shared),
        };

        for i in 0..size {
            Worker::start(i, pool.shared.clone());
        }

        pool
    }

    #[allow(dead_code)]
    pub fn run<F>(&self, job: F) where F: FnOnce() + Send + 'static {
        self.run_after(Duration::zero(), job)
    }

    pub fn run_after<F>(&self, dur: Duration, job: F) where F: FnOnce() + Send + 'static {
        let job = Job {
            type_: JobType::Once(Thunk::new(job)),
            time: (time::precise_time_ns() as i64 + dur.num_nanoseconds().unwrap()) as u64,
        };
        self.shared.run(job)
    }

    pub fn run_at_fixed_rate<F>(&self, rate: Duration, f: F) where F: FnMut() + Send + 'static {
        let job = Job {
            type_: JobType::FixedRate { f: Box::new(f), rate: rate },
            time: (time::precise_time_ns() as i64 + rate.num_nanoseconds().unwrap()) as u64,
        };
        self.shared.run(job)
    }

    pub fn clear(&self) {
        self.shared.inner.lock().unwrap().queue.clear();
    }
}

struct Worker {
    i: usize,
    shared: Arc<SharedPool>,
}

impl Drop for Worker {
    fn drop(&mut self) {
        // Start up a new worker if this one's going away due to a panic from a job
        if thread::panicking() {
            Worker::start(self.i, self.shared.clone());
        }
    }
}

impl Worker {
    fn start(i: usize, shared: Arc<SharedPool>) {
        let mut worker = Worker {
            i: i,
            shared: shared,
        };
        thread::Builder::new()
            .name(format!("ScheduledThreadPool worker {}", i))
            .spawn(move || worker.run())
            .unwrap();
    }

    fn run(&mut self) {
        loop {
            match self.get_job() {
                Some(job) => self.run_job(job),
                None => break,
            }
        }
    }

    fn get_job(&self) -> Option<Job> {
        enum Need {
            Wait,
            WaitTimeout(Duration),
        }

        let mut inner = self.shared.inner.lock().unwrap();
        loop {
            let now = time::precise_time_ns();

            let need = match inner.queue.peek() {
                None if inner.shutdown => return None,
                None => Need::Wait,
                Some(e) if e.time <= now => break,
                Some(e) => Need::WaitTimeout(Duration::nanoseconds(e.time as i64 - now as i64)),
            };

            inner = match need {
                Need::Wait => self.shared.cvar.wait(inner).unwrap(),
                Need::WaitTimeout(t) => {
                    let mut timeout = t.num_milliseconds();
                    if timeout < 0 {
                        timeout = 0;
                    }
                    self.shared.cvar.wait_timeout_ms(inner, timeout as u32).unwrap().0
                },
            };
        }

        Some(inner.queue.pop().unwrap())
    }

    fn run_job(&self, job: Job) {
        match job.type_ {
            JobType::Once(f) => f.invoke(()),
            JobType::FixedRate { mut f, rate } => {
                f();
                let new_job = Job {
                    type_: JobType::FixedRate { f: f, rate: rate },
                    time: (job.time as i64 + rate.num_nanoseconds().unwrap()) as u64,
                };
                self.shared.run(new_job)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::channel;
    use std::sync::{Arc, Barrier};
    use time::Duration;

    use super::ScheduledThreadPool;

    const TEST_TASKS: usize = 4;

    #[test]
    fn test_works() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        let (tx, rx) = channel();
        for _ in 0..TEST_TASKS {
            let tx = tx.clone();
            pool.run(move|| {
                tx.send(1usize).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).fold(0, |a, b| a + b), TEST_TASKS);
    }

    #[test]
    #[should_panic(expected = "size must be positive")]
    fn test_zero_tasks_panic() {
        ScheduledThreadPool::new(0);
    }

    #[test]
    fn test_recovery_from_subtask_panic() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        // Panic all the existing threads.
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in 0..TEST_TASKS {
            let waiter = waiter.clone();
            pool.run(move || -> () {
                waiter.wait();
                panic!();
            });
        }

        // Ensure new threads were spawned to compensate.
        let (tx, rx) = channel();
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in 0..TEST_TASKS {
            let tx = tx.clone();
            let waiter = waiter.clone();
            pool.run(move || {
                waiter.wait();
                tx.send(1usize).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).fold(0, |a, b| a + b), TEST_TASKS);
    }

    #[test]
    fn test_run_after() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1usize).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2usize).unwrap());

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_jobs_complete_after_drop() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1usize).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2usize).unwrap());

        drop(pool);

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_fixed_delay_jobs_stop_after_drop() {
        let pool = Arc::new(ScheduledThreadPool::new(TEST_TASKS));
        let (tx, rx) = channel();
        let (tx2, rx2) = channel();

        let mut pool2 = Some(pool.clone());
        let mut i = 0i32;
        pool.run_at_fixed_rate(Duration::milliseconds(500), move || {
            i += 1;
            tx.send(i).unwrap();
            rx2.recv().unwrap();
            if i == 2 {
                drop(pool2.take().unwrap());
            }
        });
        drop(pool);

        assert_eq!(Ok(1), rx.recv());
        tx2.send(()).unwrap();
        assert_eq!(Ok(2), rx.recv());
        tx2.send(()).unwrap();
        assert!(rx.recv().is_err());
    }
}
<commit_msg>Use SteadyTime in thread pool<commit_after>use std::collections::BinaryHeap;
use std::cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
use std::sync::{Arc, Mutex, Condvar};
use std::thread;
use time::{SteadyTime, Duration};

use thunk::Thunk;

enum JobType {
    Once(Thunk<'static>),
    FixedRate {
        f: Box<FnMut() + Send + 'static>,
        rate: Duration,
    },
}

struct Job {
    type_: JobType,
    time: SteadyTime,
}

impl PartialOrd for Job {
    fn partial_cmp(&self, other: &Job) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Job {
    fn cmp(&self, other: &Job) -> Ordering {
        // reverse because BinaryHeap's a max heap
        self.time.cmp(&other.time).reverse()
    }
}

impl PartialEq for Job {
    fn eq(&self, other: &Job) -> bool {
        self.time == other.time
    }
}

impl Eq for Job {}

struct InnerPool {
    queue: BinaryHeap<Job>,
    shutdown: bool,
}

struct SharedPool {
    inner: Mutex<InnerPool>,
    cvar: Condvar,
}

impl SharedPool {
    fn run(&self, job: Job) {
        let mut inner = self.inner.lock().unwrap();

        // Calls from the pool itself will never hit this, but calls from workers might
        if inner.shutdown {
            return;
        }

        match inner.queue.peek() {
            None => self.cvar.notify_all(),
            Some(e) if e.time > job.time => self.cvar.notify_all(),
            _ => {}
        };
        inner.queue.push(job);
    }
}

pub struct ScheduledThreadPool {
    shared: Arc<SharedPool>,
}

impl Drop for ScheduledThreadPool {
    fn drop(&mut self) {
        self.shared.inner.lock().unwrap().shutdown = true;
        self.shared.cvar.notify_all();
    }
}

impl ScheduledThreadPool {
    pub fn new(size: usize) -> ScheduledThreadPool {
        assert!(size > 0, "size must be positive");

        let inner = InnerPool {
            queue: BinaryHeap::new(),
            shutdown: false,
        };

        let shared = SharedPool {
            inner: Mutex::new(inner),
            cvar: Condvar::new(),
        };

        let pool = ScheduledThreadPool {
            shared: Arc::new(shared),
        };

        for i in 0..size {
            Worker::start(i, pool.shared.clone());
        }

        pool
    }

    #[allow(dead_code)]
    pub fn run<F>(&self, job: F) where F: FnOnce() + Send + 'static {
        self.run_after(Duration::zero(), job)
    }

    pub fn run_after<F>(&self, dur: Duration, job: F) where F: FnOnce() + Send + 'static {
        let job = Job {
            type_: JobType::Once(Thunk::new(job)),
            time: SteadyTime::now() + dur,
        };
        self.shared.run(job)
    }

    pub fn run_at_fixed_rate<F>(&self, rate: Duration, f: F) where F: FnMut() + Send + 'static {
        let job = Job {
            type_: JobType::FixedRate { f: Box::new(f), rate: rate },
            time: SteadyTime::now() + rate,
        };
        self.shared.run(job)
    }

    pub fn clear(&self) {
        self.shared.inner.lock().unwrap().queue.clear();
    }
}

struct Worker {
    i: usize,
    shared: Arc<SharedPool>,
}

impl Drop for Worker {
    fn drop(&mut self) {
        // Start up a new worker if this one's going away due to a panic from a job
        if thread::panicking() {
            Worker::start(self.i, self.shared.clone());
        }
    }
}

impl Worker {
    fn start(i: usize, shared: Arc<SharedPool>) {
        let mut worker = Worker {
            i: i,
            shared: shared,
        };
        thread::Builder::new()
            .name(format!("ScheduledThreadPool worker {}", i))
            .spawn(move || worker.run())
            .unwrap();
    }

    fn run(&mut self) {
        loop {
            match self.get_job() {
                Some(job) => self.run_job(job),
                None => break,
            }
        }
    }

    fn get_job(&self) -> Option<Job> {
        enum Need {
            Wait,
            WaitTimeout(Duration),
        }

        let mut inner = self.shared.inner.lock().unwrap();
        loop {
            let now = SteadyTime::now();

            let need = match inner.queue.peek() {
                None if inner.shutdown => return None,
                None => Need::Wait,
                Some(e) if e.time <= now => break,
                Some(e) => Need::WaitTimeout(e.time - now),
            };

            inner = match need {
                Need::Wait => self.shared.cvar.wait(inner).unwrap(),
                Need::WaitTimeout(t) => {
                    let mut timeout = t.num_milliseconds();
                    if timeout < 0 {
                        timeout = 0;
                    }
                    self.shared.cvar.wait_timeout_ms(inner, timeout as u32).unwrap().0
                },
            };
        }

        Some(inner.queue.pop().unwrap())
    }

    fn run_job(&self, job: Job) {
        match job.type_ {
            JobType::Once(f) => f.invoke(()),
            JobType::FixedRate { mut f, rate } => {
                f();
                let new_job = Job {
                    type_: JobType::FixedRate { f: f, rate: rate },
                    time: job.time + rate,
                };
                self.shared.run(new_job)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::channel;
    use std::sync::{Arc, Barrier};
    use time::Duration;

    use super::ScheduledThreadPool;

    const TEST_TASKS: usize = 4;

    #[test]
    fn test_works() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        let (tx, rx) = channel();
        for _ in 0..TEST_TASKS {
            let tx = tx.clone();
            pool.run(move|| {
                tx.send(1usize).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).fold(0, |a, b| a + b), TEST_TASKS);
    }

    #[test]
    #[should_panic(expected = "size must be positive")]
    fn test_zero_tasks_panic() {
        ScheduledThreadPool::new(0);
    }

    #[test]
    fn test_recovery_from_subtask_panic() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);

        // Panic all the existing threads.
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in 0..TEST_TASKS {
            let waiter = waiter.clone();
            pool.run(move || -> () {
                waiter.wait();
                panic!();
            });
        }

        // Ensure new threads were spawned to compensate.
        let (tx, rx) = channel();
        let waiter = Arc::new(Barrier::new(TEST_TASKS as usize));
        for _ in 0..TEST_TASKS {
            let tx = tx.clone();
            let waiter = waiter.clone();
            pool.run(move || {
                waiter.wait();
                tx.send(1usize).unwrap();
            });
        }

        assert_eq!(rx.iter().take(TEST_TASKS).fold(0, |a, b| a + b), TEST_TASKS);
    }

    #[test]
    fn test_run_after() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1usize).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2usize).unwrap());

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_jobs_complete_after_drop() {
        let pool = ScheduledThreadPool::new(TEST_TASKS);
        let (tx, rx) = channel();

        let tx1 = tx.clone();
        pool.run_after(Duration::seconds(1), move || tx1.send(1usize).unwrap());
        pool.run_after(Duration::milliseconds(500), move || tx.send(2usize).unwrap());

        drop(pool);

        assert_eq!(2, rx.recv().unwrap());
        assert_eq!(1, rx.recv().unwrap());
    }

    #[test]
    fn test_fixed_delay_jobs_stop_after_drop() {
        let pool = Arc::new(ScheduledThreadPool::new(TEST_TASKS));
        let (tx, rx) = channel();
        let (tx2, rx2) = channel();

        let mut pool2 = Some(pool.clone());
        let mut i = 0i32;
        pool.run_at_fixed_rate(Duration::milliseconds(500), move || {
            i += 1;
            tx.send(i).unwrap();
            rx2.recv().unwrap();
            if i == 2 {
                drop(pool2.take().unwrap());
            }
        });
        drop(pool);

        assert_eq!(Ok(1), rx.recv());
        tx2.send(()).unwrap();
        assert_eq!(Ok(2), rx.recv());
        tx2.send(()).unwrap();
        assert!(rx.recv().is_err());
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use serde_json::value::Value;

use priority::TaskPriority;

pub type DateTime= String; // FIXME
pub type Project = String;
pub type Status  = String;
pub type Tag     = String;
pub type UUID    = String; // FIXME
pub type Urgency = f64;

#[derive(Debug, Clone)]
pub struct Task {
    id: u64,
    desc: String,
    entry: DateTime,
    modified: Option<DateTime>,
    priority: Option<TaskPriority>,
    project: Option<Project>,
    status: Status,
    tags: Vec<Tag>,
    uuid: UUID,
    urgency: Urgency,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(id: u64,
                desc: String,
                entry: DateTime,
                modified: Option<DateTime>,
                priority: Option<TaskPriority>,
                project: Option<Project>,
                status: Status,
                tags: Vec<Tag>,
                uuid: UUID,
                urgency: Urgency)
        -> Task
    {
        Task {
            id       : id,
            desc     : desc,
            entry    : entry,
            modified : modified,
            priority : priority,
            project  : project,
            status   : status,
            tags     : tags,
            uuid     : uuid,
            urgency  : urgency,
        }
    }

    pub fn from_value(v: Value) -> Option<Task> {
        if !v.is_object() {
            debug!("JSON Value is not an object, cannot parse into Task");
            return None;
        }

        let map = v.as_object().unwrap();

        Some(Task {
            id       : get_id(&map),
            desc     : get_desc(&map),
            entry    : get_entry(&map),
            modified : get_modified(&map),
            priority : get_priority(&map),
            project  : get_project(&map),
            status   : get_status(&map),
            tags     : get_tags(&map),
            uuid     : get_uuid(&map),
            urgency  : get_urgency(&map),
        })
    }

    pub fn id(&self) -> u64 {
        self.id
    }

    pub fn desc(&self) -> &String {
        &self.desc
    }

    pub fn entry(&self) -> &DateTime {
        &self.entry
    }

    pub fn modified(&self) -> Option<&DateTime> {
        self.modified.as_ref()
    }

    pub fn priority(&self) -> Option<&TaskPriority> {
        self.priority.as_ref()
    }

    pub fn project(&self) -> Option<&Project> {
        self.project.as_ref()
    }

    pub fn status(&self) -> &Status {
        &self.status
    }

    pub fn tags(&self) -> &Vec<Tag> {
        &self.tags
    }

    pub fn uuid(&self) -> &UUID {
        &self.uuid
    }

    pub fn urgency(&self) -> Urgency {
        self.urgency
    }

}

impl Into<Value> for Task {

    fn into(self) -> Value {
        let id       = Value::U64(self.id);
        let desc     = Value::String(self.desc);
        let entry    = Value::String(self.entry);
        let status   = Value::String(self.status);
        let tags     = Value::Array(self.tags
                                        .into_iter()
                                        .map(|s| Value::String(String::from(s)))
                                        .collect());
        let uuid     = Value::String(self.uuid);
        let urgency  = Value::F64(self.urgency);

        let mut map = BTreeMap::new();
        map.insert(String::from("id")       , id);
        map.insert(String::from("desc")     , desc);
        map.insert(String::from("entry")    , entry);
        if self.modified.is_some() {
            map.insert(String::from("modified") , Value::String(self.modified.unwrap()));
        }
        if self.priority.is_some() {
            map.insert(String::from("priority") , Value::String(self.priority.unwrap().into()));
        }
        if self.project.is_some() {
            map.insert(String::from("project"), Value::String(self.project.unwrap()));
        }
        map.insert(String::from("status")   , status);
        map.insert(String::from("tags")     , tags);
        map.insert(String::from("uuid")     , uuid);
        map.insert(String::from("urgency")  , urgency);

        Value::Object(map)
    }

}

fn get_id(map: &BTreeMap<String, Value>) -> u64 {
    map.get("id").unwrap().as_u64().unwrap()
}

fn get_desc(map: &BTreeMap<String, Value>) -> String {
    map.get("description").unwrap().as_string().map(String::from).unwrap()
}

fn get_entry(map: &BTreeMap<String, Value>) -> String {
    map.get("entry").unwrap().as_string().map(String::from).unwrap()
}

fn get_modified(map: &BTreeMap<String, Value>) -> Option<String> {
    map.get("modified")
        .map(|m| m.as_string().map(String::from).unwrap())
}

fn get_priority(map: &BTreeMap<String, Value>) -> Option<TaskPriority> {
    map.get("priority")
        .map(|m| m.as_string().map(String::from).unwrap())
        .map(|s| TaskPriority::from(&s[..]))
}

fn get_project(map: &BTreeMap<String, Value>) -> Option<String> {
    map.get("project")
        .map(|p| p.as_string().map(String::from).unwrap())
}

fn get_status(map: &BTreeMap<String, Value>) -> String {
    map.get("status").unwrap().as_string().map(String::from).unwrap()
}

fn get_tags(map: &BTreeMap<String, Value>) -> Vec<Tag> {
    map.get("tags")
        .unwrap()
        .as_array()
        .unwrap()
        .clone()
        .into_iter()
        .map(|item| item.as_string().map(String::from).unwrap())
        .collect()
}

fn get_uuid(map: &BTreeMap<String, Value>) -> String {
    map.get("uuid").unwrap().as_string().map(String::from).unwrap()
}

fn get_urgency(map: &BTreeMap<String, Value>) -> f64 {
    map.get("urgency").unwrap().as_f64().unwrap()
}

#[cfg(test)]
mod test {
    extern crate env_logger;

    use core::reader::Reader;
    use core::reader::JsonObjectReader;
    use super::Task;
    use priority::TaskPriority;
    use std::borrow::Borrow;

    #[test]
    fn test_from_json() {
        env_logger::init().unwrap();

        let json = String::from("{\"id\":1,\"description\":\"desc\",\"entry\":\"20150612T164806Z\",\"modified\":\"20160315T215656Z\",\"priority\":\"L\",\"project\":\"someproj\",\"status\":\"pending\",\"tags\":[\"test\",\"task\"],\"uuid\":\"93cfc5fa-2f0c-44e6-bede-c2b1ca7ceff3\",\"urgency\":1.0}");
        let bytes = json.into_bytes();
        let mut reader = JsonObjectReader::new(Reader::new(bytes.borrow()));

        let v = reader.next();
        assert!(v.is_some());
        let v = v.unwrap();

        let t = Task::from_value(v);
        assert!(t.is_some());
        let t = t.unwrap();

        debug!("Task created successfully!");

        assert_eq!(t.id(), 1);
        assert_eq!(t.desc().clone(), String::from("desc"));
        assert_eq!(t.entry().clone(), String::from("20150612T164806Z"));
        assert_eq!(t.modified().clone(), Some(&String::from("20160315T215656Z")));
        assert_eq!(t.priority(), Some(&TaskPriority::Low));
        assert_eq!(t.project().clone(), Some(&String::from("someproj")));
        assert_eq!(t.status().clone(), String::from("pending"));
        for n in ["test", "task"].iter() {
            assert!(t.tags().contains(&String::from(*n)));
        }
        assert_eq!(t.uuid().clone(), String::from("93cfc5fa-2f0c-44e6-bede-c2b1ca7ceff3"));
        assert_eq!(t.urgency() as u64, 1.0 as u64);
    }

}
<commit_msg>Use chrono for DateTime<UTC><commit_after>use std::collections::BTreeMap;

use chrono::DateTime;
use chrono::UTC;
use serde_json::value::Value;

use priority::TaskPriority;

pub type Project = String;
pub type Status  = String;
pub type Tag     = String;
pub type UUID    = String; // FIXME
pub type Urgency = f64;

#[derive(Debug, Clone)]
pub struct Task {
    id: u64,
    desc: String,
    entry: DateTime<UTC>,
    modified: Option<DateTime<UTC>>,
    priority: Option<TaskPriority>,
    project: Option<Project>,
    status: Status,
    tags: Vec<Tag>,
    uuid: UUID,
    urgency: Urgency,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(id: u64,
                desc: String,
                entry: DateTime<UTC>,
                modified: Option<DateTime<UTC>>,
                priority: Option<TaskPriority>,
                project: Option<Project>,
                status: Status,
                tags: Vec<Tag>,
                uuid: UUID,
                urgency: Urgency)
        -> Task
    {
        Task {
            id       : id,
            desc     : desc,
            entry    : entry,
            modified : modified,
            priority : priority,
            project  : project,
            status   : status,
            tags     : tags,
            uuid     : uuid,
            urgency  : urgency,
        }
    }

    pub fn from_value(v: Value) -> Option<Task> {
        if !v.is_object() {
            debug!("JSON Value is not an object, cannot parse into Task");
            return None;
        }

        let map = v.as_object().unwrap();

        let entry_dt = get_entry(&map);
        if entry_dt.is_none() {
            return None;
        }
        let entry_dt = entry_dt.unwrap();

        Some(Task {
            id       : get_id(&map),
            desc     : get_desc(&map),
            entry    : entry_dt,
            modified : get_modified(&map),
            priority : get_priority(&map),
            project  : get_project(&map),
            status   : get_status(&map),
            tags     : get_tags(&map),
            uuid     : get_uuid(&map),
            urgency  : get_urgency(&map),
        })
    }

    pub fn id(&self) -> u64 {
        self.id
    }

    pub fn desc(&self) -> &String {
        &self.desc
    }

    pub fn entry(&self) -> &DateTime<UTC> {
        &self.entry
    }

    pub fn modified(&self) -> Option<&DateTime<UTC>> {
        self.modified.as_ref()
    }

    pub fn priority(&self) -> Option<&TaskPriority> {
        self.priority.as_ref()
    }

    pub fn project(&self) -> Option<&Project> {
        self.project.as_ref()
    }

    pub fn status(&self) -> &Status {
        &self.status
    }

    pub fn tags(&self) -> &Vec<Tag> {
        &self.tags
    }

    pub fn uuid(&self) -> &UUID {
        &self.uuid
    }

    pub fn urgency(&self) -> Urgency {
        self.urgency
    }

}

impl Into<Value> for Task {

    fn into(self) -> Value {
        let id       = Value::U64(self.id);
        let desc     = Value::String(self.desc);
        let status   = Value::String(self.status);
        let tags     = Value::Array(self.tags
                                        .into_iter()
                                        .map(|s| Value::String(String::from(s)))
                                        .collect());
        let uuid     = Value::String(self.uuid);
        let urgency  = Value::F64(self.urgency);

        let mut map = BTreeMap::new();
        map.insert(String::from("id")       , id);
        map.insert(String::from("desc")     , desc);
        {
            let v = Value::String(format!("{:?}", self.entry));
            map.insert(String::from("entry"), v);
        }
        if self.modified.is_some() {
            let v = Value::String(format!("{:?}", self.modified.unwrap()));
            map.insert(String::from("modified"), v);
        }
        if self.priority.is_some() {
            map.insert(String::from("priority") , Value::String(self.priority.unwrap().into()));
        }
        if self.project.is_some() {
            map.insert(String::from("project"), Value::String(self.project.unwrap()));
        }
        map.insert(String::from("status")   , status);
        map.insert(String::from("tags")     , tags);
        map.insert(String::from("uuid")     , uuid);
        map.insert(String::from("urgency")  , urgency);

        Value::Object(map)
    }

}

fn get_id(map: &BTreeMap<String, Value>) -> u64 {
    map.get("id").unwrap().as_u64().unwrap()
}

fn get_desc(map: &BTreeMap<String, Value>) -> String {
    map.get("description").unwrap().as_string().map(String::from).unwrap()
}

fn get_entry(map: &BTreeMap<String, Value>) -> Option<DateTime<UTC>> {
    map.get("entry")
        .unwrap()
        .as_string()
        .and_then(|s| String::from(s).parse::<DateTime<UTC>>().ok())
}

fn get_modified(map: &BTreeMap<String, Value>) -> Option<DateTime<UTC>> {
    map.get("modified")
        .and_then(|m| m.as_string())
        .and_then(|s| String::from(s).parse::<DateTime<UTC>>().ok())
}

fn get_priority(map: &BTreeMap<String, Value>) -> Option<TaskPriority> {
    map.get("priority")
        .map(|m| m.as_string().map(String::from).unwrap())
        .map(|s| TaskPriority::from(&s[..]))
}

fn get_project(map: &BTreeMap<String, Value>) -> Option<String> {
    map.get("project")
        .map(|p| p.as_string().map(String::from).unwrap())
}

fn get_status(map: &BTreeMap<String, Value>) -> String {
    map.get("status").unwrap().as_string().map(String::from).unwrap()
}

fn get_tags(map: &BTreeMap<String, Value>) -> Vec<Tag> {
    map.get("tags")
        .unwrap()
        .as_array()
        .unwrap()
        .clone()
        .into_iter()
        .map(|item| item.as_string().map(String::from).unwrap())
        .collect()
}

fn get_uuid(map: &BTreeMap<String, Value>) -> String {
    map.get("uuid").unwrap().as_string().map(String::from).unwrap()
}

fn get_urgency(map: &BTreeMap<String, Value>) -> f64 {
    map.get("urgency").unwrap().as_f64().unwrap()
}

#[cfg(test)]
mod test {
    extern crate env_logger;

    use chrono::DateTime;
    use chrono::UTC;

    use core::reader::Reader;
    use core::reader::JsonObjectReader;
    use super::Task;
    use priority::TaskPriority;
    use std::borrow::Borrow;

    #[test]
    fn test_from_json() {
        env_logger::init().unwrap();

        let json = String::from("{\"id\":1,\"description\":\"desc\",\"entry\":\"20150612T164806Z\",\"modified\":\"20160315T215656Z\",\"priority\":\"L\",\"project\":\"someproj\",\"status\":\"pending\",\"tags\":[\"test\",\"task\"],\"uuid\":\"93cfc5fa-2f0c-44e6-bede-c2b1ca7ceff3\",\"urgency\":1.0}");
        let bytes = json.into_bytes();
        let mut reader = JsonObjectReader::new(Reader::new(bytes.borrow()));

        let v = reader.next();
        assert!(v.is_some());
        let v = v.unwrap();

        let t = Task::from_value(v);
        assert!(t.is_some());
        let t = t.unwrap();

        debug!("Task created successfully!");

        assert_eq!(t.id(), 1);
        assert_eq!(t.desc().clone(), String::from("desc"));
        assert_eq!(t.entry().clone(), String::from("20150612T164806Z").parse::<DateTime<UTC>>().unwrap());
        assert_eq!(t.modified().clone(), String::from("20160315T215656Z").parse::<DateTime<UTC>>().ok().as_ref());
        assert_eq!(t.priority(), Some(&TaskPriority::Low));
        assert_eq!(t.project().clone(), Some(&String::from("someproj")));
        assert_eq!(t.status().clone(), String::from("pending"));
        for n in ["test", "task"].iter() {
            assert!(t.tags().contains(&String::from(*n)));
        }
        assert_eq!(t.uuid().clone(), String::from("93cfc5fa-2f0c-44e6-bede-c2b1ca7ceff3"));
        assert_eq!(t.urgency() as u64, 1.0 as u64);
    }

}
<|endoftext|>


<commit_before>//! Test Various helpers for Actix applications to use during testing.
use std::str::FromStr;

use bytes::Bytes;
use cookie::Cookie;
use http::header::HeaderName;
use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};

use crate::header::{Header, IntoHeaderValue};
use crate::payload::Payload;
use crate::Request;

/// Test `Request` builder
///
/// ```rust,ignore
/// # extern crate http;
/// # extern crate actix_web;
/// # use http::{header, StatusCode};
/// # use actix_web::*;
/// use actix_web::test::TestRequest;
///
/// fn index(req: &HttpRequest) -> Response {
///     if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
///         Response::Ok().into()
///     } else {
///         Response::BadRequest().into()
///     }
/// }
///
/// fn main() {
///     let resp = TestRequest::with_header("content-type", "text/plain")
///         .run(&index)
///         .unwrap();
///     assert_eq!(resp.status(), StatusCode::OK);
///
///     let resp = TestRequest::default().run(&index).unwrap();
///     assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// ```
pub struct TestRequest(Option<Inner>);

struct Inner {
    version: Version,
    method: Method,
    uri: Uri,
    headers: HeaderMap,
    _cookies: Option<Vec<Cookie<'static>>>,
    payload: Option<Payload>,
}

impl Default for TestRequest {
    fn default() -> TestRequest {
        TestRequest(Some(Inner {
            method: Method::GET,
            uri: Uri::from_str("/").unwrap(),
            version: Version::HTTP_11,
            headers: HeaderMap::new(),
            _cookies: None,
            payload: None,
        }))
    }
}

impl TestRequest {
    /// Create TestRequest and set request uri
    pub fn with_uri(path: &str) -> TestRequest {
        TestRequest::default().uri(path).take()
    }

    /// Create TestRequest and set header
    pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
        TestRequest::default().set(hdr).take()
    }

    /// Create TestRequest and set header
    pub fn with_header<K, V>(key: K, value: V) -> TestRequest
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        TestRequest::default().header(key, value).take()
    }

    /// Set HTTP version of this request
    pub fn version(&mut self, ver: Version) -> &mut Self {
        parts(&mut self.0).version = ver;
        self
    }

    /// Set HTTP method of this request
    pub fn method(&mut self, meth: Method) -> &mut Self {
        parts(&mut self.0).method = meth;
        self
    }

    /// Set HTTP Uri of this request
    pub fn uri(&mut self, path: &str) -> &mut Self {
        parts(&mut self.0).uri = Uri::from_str(path).unwrap();
        self
    }

    /// Set a header
    pub fn set<H: Header>(&mut self, hdr: H) -> &mut Self {
        if let Ok(value) = hdr.try_into() {
            parts(&mut self.0).headers.append(H::name(), value);
            return self;
        }
        panic!("Can not set header");
    }

    /// Set a header
    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        if let Ok(key) = HeaderName::try_from(key) {
            if let Ok(value) = value.try_into() {
                parts(&mut self.0).headers.append(key, value);
                return self;
            }
        }
        panic!("Can not create header");
    }

    /// Set request payload
    pub fn set_payload<B: Into<Bytes>>(&mut self, data: B) -> &mut Self {
        let mut payload = crate::h1::Payload::empty();
        payload.unread_data(data.into());
        parts(&mut self.0).payload = Some(payload.into());
        self
    }

    pub fn take(&mut self) -> TestRequest {
        TestRequest(self.0.take())
    }

    /// Complete request creation and generate `Request` instance
    pub fn finish(&mut self) -> Request {
        let Inner {
            method,
            uri,
            version,
            headers,
            payload,
            ..
        } = self.0.take().expect("cannot reuse test request builder");;

        let mut req = if let Some(pl) = payload {
            Request::with_payload(pl)
        } else {
            Request::with_payload(crate::h1::Payload::empty().into())
        };

        let head = req.head_mut();
        head.uri = uri;
        head.method = method;
        head.version = version;
        head.headers = headers;

        // req.set_cookies(cookies);
        req
    }

    // /// This method generates `HttpRequest` instance and runs handler
    // /// with generated request.
    // pub fn run<H: Handler<S>>(self, h: &H) -> Result<Response, Error> {
    //     let req = self.finish();
    //     let resp = h.handle(&req);

    //     match resp.respond_to(&req) {
    //         Ok(resp) => match resp.into().into() {
    //             AsyncResultItem::Ok(resp) => Ok(resp),
    //             AsyncResultItem::Err(err) => Err(err),
    //             AsyncResultItem::Future(fut) => {
    //                 let mut sys = System::new("test");
    //                 sys.block_on(fut)
    //             }
    //         },
    //         Err(err) => Err(err.into()),
    //     }
    // }

    // /// This method generates `HttpRequest` instance and runs handler
    // /// with generated request.
    // ///
    // /// This method panics is handler returns actor.
    // pub fn run_async<H, R, F, E>(self, h: H) -> Result<Response, E>
    // where
    //     H: Fn(HttpRequest<S>) -> F + 'static,
    //     F: Future<Item = R, Error = E> + 'static,
    //     R: Responder<Error = E> + 'static,
    //     E: Into<Error> + 'static,
    // {
    //     let req = self.finish();
    //     let fut = h(req.clone());

    //     let mut sys = System::new("test");
    //     match sys.block_on(fut) {
    //         Ok(r) => match r.respond_to(&req) {
    //             Ok(reply) => match reply.into().into() {
    //                 AsyncResultItem::Ok(resp) => Ok(resp),
    //                 _ => panic!("Nested async replies are not supported"),
    //             },
    //             Err(e) => Err(e),
    //         },
    //         Err(err) => Err(err),
    //     }
    // }

    // /// This method generates `HttpRequest` instance and executes handler
    // pub fn run_async_result<F, R, I, E>(self, f: F) -> Result<I, E>
    // where
    //     F: FnOnce(&HttpRequest<S>) -> R,
    //     R: Into<AsyncResult<I, E>>,
    // {
    //     let req = self.finish();
    //     let res = f(&req);

    //     match res.into().into() {
    //         AsyncResultItem::Ok(resp) => Ok(resp),
    //         AsyncResultItem::Err(err) => Err(err),
    //         AsyncResultItem::Future(fut) => {
    //             let mut sys = System::new("test");
    //             sys.block_on(fut)
    //         }
    //     }
    // }

    // /// This method generates `HttpRequest` instance and executes handler
    // pub fn execute<F, R>(self, f: F) -> Result<Response, Error>
    // where
    //     F: FnOnce(&HttpRequest<S>) -> R,
    //     R: Responder + 'static,
    // {
    //     let req = self.finish();
    //     let resp = f(&req);

    //     match resp.respond_to(&req) {
    //         Ok(resp) => match resp.into().into() {
    //             AsyncResultItem::Ok(resp) => Ok(resp),
    //             AsyncResultItem::Err(err) => Err(err),
    //             AsyncResultItem::Future(fut) => {
    //                 let mut sys = System::new("test");
    //                 sys.block_on(fut)
    //             }
    //         },
    //         Err(err) => Err(err.into()),
    //     }
    // }
}

#[inline]
fn parts<'a>(parts: &'a mut Option<Inner>) -> &'a mut Inner {
    parts.as_mut().expect("cannot reuse test request builder")
}
<commit_msg>support cookies in TestRequest<commit_after>//! Test Various helpers for Actix applications to use during testing.
use std::fmt::Write as FmtWrite;
use std::str::FromStr;

use bytes::Bytes;
use cookie::{Cookie, CookieJar};
use http::header::{self, HeaderName, HeaderValue};
use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};

use crate::header::{Header, IntoHeaderValue};
use crate::payload::Payload;
use crate::Request;

/// Test `Request` builder
///
/// ```rust,ignore
/// # extern crate http;
/// # extern crate actix_web;
/// # use http::{header, StatusCode};
/// # use actix_web::*;
/// use actix_web::test::TestRequest;
///
/// fn index(req: &HttpRequest) -> Response {
///     if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
///         Response::Ok().into()
///     } else {
///         Response::BadRequest().into()
///     }
/// }
///
/// fn main() {
///     let resp = TestRequest::with_header("content-type", "text/plain")
///         .run(&index)
///         .unwrap();
///     assert_eq!(resp.status(), StatusCode::OK);
///
///     let resp = TestRequest::default().run(&index).unwrap();
///     assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// ```
pub struct TestRequest(Option<Inner>);

struct Inner {
    version: Version,
    method: Method,
    uri: Uri,
    headers: HeaderMap,
    cookies: CookieJar,
    payload: Option<Payload>,
}

impl Default for TestRequest {
    fn default() -> TestRequest {
        TestRequest(Some(Inner {
            method: Method::GET,
            uri: Uri::from_str("/").unwrap(),
            version: Version::HTTP_11,
            headers: HeaderMap::new(),
            cookies: CookieJar::new(),
            payload: None,
        }))
    }
}

impl TestRequest {
    /// Create TestRequest and set request uri
    pub fn with_uri(path: &str) -> TestRequest {
        TestRequest::default().uri(path).take()
    }

    /// Create TestRequest and set header
    pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
        TestRequest::default().set(hdr).take()
    }

    /// Create TestRequest and set header
    pub fn with_header<K, V>(key: K, value: V) -> TestRequest
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        TestRequest::default().header(key, value).take()
    }

    /// Set HTTP version of this request
    pub fn version(&mut self, ver: Version) -> &mut Self {
        parts(&mut self.0).version = ver;
        self
    }

    /// Set HTTP method of this request
    pub fn method(&mut self, meth: Method) -> &mut Self {
        parts(&mut self.0).method = meth;
        self
    }

    /// Set HTTP Uri of this request
    pub fn uri(&mut self, path: &str) -> &mut Self {
        parts(&mut self.0).uri = Uri::from_str(path).unwrap();
        self
    }

    /// Set a header
    pub fn set<H: Header>(&mut self, hdr: H) -> &mut Self {
        if let Ok(value) = hdr.try_into() {
            parts(&mut self.0).headers.append(H::name(), value);
            return self;
        }
        panic!("Can not set header");
    }

    /// Set a header
    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
    where
        HeaderName: HttpTryFrom<K>,
        V: IntoHeaderValue,
    {
        if let Ok(key) = HeaderName::try_from(key) {
            if let Ok(value) = value.try_into() {
                parts(&mut self.0).headers.append(key, value);
                return self;
            }
        }
        panic!("Can not create header");
    }

    /// Set cookie for this request
    pub fn cookie<'a>(mut self, cookie: Cookie<'a>) -> Self {
        parts(&mut self.0).cookies.add(cookie.into_owned());
        self
    }

    /// Set request payload
    pub fn set_payload<B: Into<Bytes>>(&mut self, data: B) -> &mut Self {
        let mut payload = crate::h1::Payload::empty();
        payload.unread_data(data.into());
        parts(&mut self.0).payload = Some(payload.into());
        self
    }

    pub fn take(&mut self) -> TestRequest {
        TestRequest(self.0.take())
    }

    /// Complete request creation and generate `Request` instance
    pub fn finish(&mut self) -> Request {
        let Inner {
            method,
            uri,
            version,
            headers,
            payload,
            cookies,
        } = self.0.take().expect("cannot reuse test request builder");;

        let mut req = if let Some(pl) = payload {
            Request::with_payload(pl)
        } else {
            Request::with_payload(crate::h1::Payload::empty().into())
        };

        let head = req.head_mut();
        head.uri = uri;
        head.method = method;
        head.version = version;
        head.headers = headers;

        let mut cookie = String::new();
        for c in cookies.delta() {
            let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
            let value = percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
            let _ = write!(&mut cookie, "; {}={}", name, value);
        }
        head.headers.insert(
            header::COOKIE,
            HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
        );

        req
    }
}

#[inline]
fn parts<'a>(parts: &'a mut Option<Inner>) -> &'a mut Inner {
    parts.as_mut().expect("cannot reuse test request builder")
}
<|endoftext|>


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

// ignore-tidy-linelength

// We specify -Z incremental here because we want to test the partitioning for
// incremental compilation
// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const
// compile-flags:-Zinline-in-all-cgus

// This test case makes sure, that references made through constants are
// recorded properly in the InliningMap.

#![feature(start)]

mod mod1 {
    pub trait Trait1 {
        fn do_something(&self) {}
        fn do_something_else(&self) {}
    }

    impl Trait1 for u32 {}

    pub trait Trait1Gen<T> {
        fn do_something(&self, x: T) -> T;
        fn do_something_else(&self, x: T) -> T;
    }

    impl<T> Trait1Gen<T> for u32 {
        fn do_something(&self, x: T) -> T { x }
        fn do_something_else(&self, x: T) -> T { x }
    }

    fn id<T>(x: T) -> T { x }

    // These are referenced, so they produce mono-items (see start())
    pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1;
    pub const TRAIT1_GEN_REF: &'static Trait1Gen<u8> = &0u32 as &Trait1Gen<u8>;
    pub const ID_CHAR: fn(char) -> char = id::<char>;

    pub trait Trait2 {
        fn do_something(&self) {}
        fn do_something_else(&self) {}
    }

    impl Trait2 for u32 {}

    pub trait Trait2Gen<T> {
        fn do_something(&self, x: T) -> T;
        fn do_something_else(&self, x: T) -> T;
    }

    impl<T> Trait2Gen<T> for u32 {
        fn do_something(&self, x: T) -> T { x }
        fn do_something_else(&self, x: T) -> T { x }
    }

    // These are not referenced, so they do not produce mono-items
    pub const TRAIT2_REF: &'static Trait2 = &0u32 as &Trait2;
    pub const TRAIT2_GEN_REF: &'static Trait2Gen<u8> = &0u32 as &Trait2Gen<u8>;
    pub const ID_I64: fn(i64) -> i64 = id::<i64>;
}

//~ MONO_ITEM fn vtable_through_const::start[0]
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ vtable_through_const[Internal]

    // Since Trait1::do_something() is instantiated via its default implementation,
    // it is considered a generic and is instantiated here only because it is
    // referenced in this module.
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0]<u32> @@ vtable_through_const-mod1.volatile[External]

    // Although it is never used, Trait1::do_something_else() has to be
    // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable
    // could not be fully constructed.
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0]<u32> @@ vtable_through_const-mod1.volatile[External]
    mod1::TRAIT1_REF.do_something();

    // Same as above
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0]<u8> @@ vtable_through_const-mod1.volatile[External]
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0]<u8> @@ vtable_through_const-mod1.volatile[External]
    mod1::TRAIT1_GEN_REF.do_something(0u8);

    //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0]<char> @@ vtable_through_const-mod1.volatile[External]
    mod1::ID_CHAR('x');

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

// ignore-tidy-linelength

// We specify -Z incremental here because we want to test the partitioning for
// incremental compilation
// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const
// compile-flags:-Zinline-in-all-cgus

// This test case makes sure, that references made through constants are
// recorded properly in the InliningMap.

#![feature(start)]

mod mod1 {
    pub trait Trait1 {
        fn do_something(&self) {}
        fn do_something_else(&self) {}
    }

    impl Trait1 for u32 {}

    pub trait Trait1Gen<T> {
        fn do_something(&self, x: T) -> T;
        fn do_something_else(&self, x: T) -> T;
    }

    impl<T> Trait1Gen<T> for u32 {
        fn do_something(&self, x: T) -> T { x }
        fn do_something_else(&self, x: T) -> T { x }
    }

    //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0]<i64> @@ vtable_through_const-mod1.volatile[Internal]
    fn id<T>(x: T) -> T { x }

    // These are referenced, so they produce mono-items (see start())
    pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1;
    pub const TRAIT1_GEN_REF: &'static Trait1Gen<u8> = &0u32 as &Trait1Gen<u8>;
    pub const ID_CHAR: fn(char) -> char = id::<char>;

    pub trait Trait2 {
        fn do_something(&self) {}
        fn do_something_else(&self) {}
    }

    //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait2[0]::do_something[0]<u32> @@ vtable_through_const-mod1.volatile[Internal]
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait2[0]::do_something_else[0]<u32> @@ vtable_through_const-mod1.volatile[Internal]
    impl Trait2 for u32 {}

    pub trait Trait2Gen<T> {
        fn do_something(&self, x: T) -> T;
        fn do_something_else(&self, x: T) -> T;
    }

    impl<T> Trait2Gen<T> for u32 {
        fn do_something(&self, x: T) -> T { x }
        fn do_something_else(&self, x: T) -> T { x }
    }

    // These are not referenced, so they do not produce mono-items
    pub const TRAIT2_REF: &'static Trait2 = &0u32 as &Trait2;
    pub const TRAIT2_GEN_REF: &'static Trait2Gen<u8> = &0u32 as &Trait2Gen<u8>;
    pub const ID_I64: fn(i64) -> i64 = id::<i64>;
}

//~ MONO_ITEM fn vtable_through_const::start[0]
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ vtable_through_const[Internal]

    // Since Trait1::do_something() is instantiated via its default implementation,
    // it is considered a generic and is instantiated here only because it is
    // referenced in this module.
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0]<u32> @@ vtable_through_const-mod1.volatile[External]

    // Although it is never used, Trait1::do_something_else() has to be
    // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable
    // could not be fully constructed.
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0]<u32> @@ vtable_through_const-mod1.volatile[External]
    mod1::TRAIT1_REF.do_something();

    // Same as above
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0]<u8> @@ vtable_through_const-mod1.volatile[External]
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0]<u8> @@ vtable_through_const-mod1.volatile[External]
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[3]::do_something[0]<u8> @@ vtable_through_const-mod1.volatile[Internal]
    //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[3]::do_something_else[0]<u8> @@ vtable_through_const-mod1.volatile[Internal]
    mod1::TRAIT1_GEN_REF.do_something(0u8);

    //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0]<char> @@ vtable_through_const-mod1.volatile[External]
    mod1::ID_CHAR('x');

    0
}
<|endoftext|>


<commit_before>use super::RW;
use super::evented::{RcEventSource, Evented, EventedImpl, MioAdapter};
use std::io;
use std::path::Path;
use std::os::unix::io::RawFd;
use mio_orig;

/// Unix pipe reader
pub type PipeReader = MioAdapter<mio_orig::unix::PipeReader>;

/// Unix pipe writer
pub type PipeWriter = MioAdapter<mio_orig::unix::PipeWriter>;

/// Unix listener
pub struct UnixListener(RcEventSource<mio_orig::unix::UnixListener>);

impl EventedImpl for UnixListener {
    type Raw = mio_orig::unix::UnixListener;

    fn shared(&self) -> &RcEventSource<Self::Raw> {
        &self.0
    }
}

impl UnixListener {
    /// Bind to a port
    pub fn bind<P: AsRef<Path> + ?Sized>(addr: &P) -> io::Result<Self> {
        mio_orig::unix::UnixListener::bind(addr).map(|t| UnixListener(RcEventSource::new(t)))
    }

    /// Try cloning the socket descriptor.
    pub fn try_clone(&self) -> io::Result<Self> {
        self.shared().io_ref().try_clone().map(|t| UnixListener(RcEventSource::new(t)))
    }
}

/// Unix socket
pub type UnixSocket = MioAdapter<mio_orig::unix::UnixSocket>;

impl UnixSocket {
    /// Returns a new, unbound, Unix domain socket
    pub fn stream() -> io::Result<UnixSocket> {
        mio_orig::unix::UnixSocket::stream().map(MioAdapter::new)
    }

    /// Connect the socket to the specified address
    pub fn connect<P: AsRef<Path> + ?Sized>(self, addr: &P) -> io::Result<(UnixStream, bool)> {
        self.shared()
            .io_ref()
            .try_clone()
            .and_then(|t| mio_orig::unix::UnixSocket::connect(t, addr))
            .map(|(t, b)| (MioAdapter::new(t), b))
    }

    /// Bind the socket to the specified address
    pub fn bind<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
        self.shared().io_ref().bind(addr)
    }

    /// Clone
    pub fn try_clone(&self) -> io::Result<Self> {
        self.shared().io_ref().try_clone().map(MioAdapter::new)
    }
}

/// Unix stream
pub type UnixStream = MioAdapter<mio_orig::unix::UnixStream>;

impl UnixStream {
    /// Connect UnixStream to `path`
    pub fn connect<P: AsRef<Path> + ?Sized>(path: &P) -> io::Result<UnixStream> {
        mio_orig::unix::UnixStream::connect(path).map(MioAdapter::new)
    }

    /// Clone
    pub fn try_clone(&self) -> io::Result<Self> {
        self.shared().io_ref().try_clone().map(MioAdapter::new)
    }

    /// Try reading data into a buffer.
    ///
    /// This will not block.
    pub fn try_read_recv_fd(&mut self,
                            buf: &mut [u8])
                            -> io::Result<Option<(usize, Option<RawFd>)>> {
        self.shared().io_mut().try_read_recv_fd(buf)
    }

    /// Block on read.
    pub fn read_recv_fd(&mut self, buf: &mut [u8]) -> io::Result<(usize, Option<RawFd>)> {
        loop {
            let res = self.try_read_recv_fd(buf);

            match res {
                Ok(None) => self.block_on(RW::read()),
                Ok(Some(r)) => {
                    return Ok(r);
                }
                Err(e) => return Err(e),
            }
        }
    }

    /// Try writing a data from the buffer.
    ///
    /// This will not block.
    pub fn try_write_send_fd(&self, buf: &[u8], fd: RawFd) -> io::Result<Option<usize>> {
        self.shared().io_mut().try_write_send_fd(buf, fd)
    }

    /// Block on write
    pub fn write_send_fd(&mut self, buf: &[u8], fd: RawFd) -> io::Result<usize> {
        loop {
            let res = self.try_write_send_fd(buf, fd);

            match res {
                Ok(None) => self.block_on(RW::write()),
                Ok(Some(r)) => {
                    return Ok(r);
                }
                Err(e) => return Err(e),
            }
        }
    }
}

/// Create a pair of unix pipe (reader and writer)
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
    let (raw_reader, raw_writer) = try!(mio_orig::unix::pipe());

    Ok((MioAdapter::new(raw_reader), MioAdapter::new(raw_writer)))

}
<commit_msg>Make UnixListener usable, fixes #135<commit_after>use super::RW;
use super::evented::{Evented, EventedImpl, MioAdapter};
use std::io;
use std::path::Path;
use std::os::unix::io::RawFd;
use mio_orig;

/// Unix pipe reader
pub type PipeReader = MioAdapter<mio_orig::unix::PipeReader>;

/// Unix pipe writer
pub type PipeWriter = MioAdapter<mio_orig::unix::PipeWriter>;

/// Unix listener
pub type UnixListener = MioAdapter<mio_orig::unix::UnixListener>;

impl UnixListener {
    /// Bind to a port
    pub fn bind<P: AsRef<Path> + ?Sized>(addr: &P) -> io::Result<Self> {
        mio_orig::unix::UnixListener::bind(addr).map(MioAdapter::new)
    }

    /// Try cloning the socket descriptor.
    pub fn try_clone(&self) -> io::Result<Self> {
        self.shared().io_ref().try_clone().map(MioAdapter::new)
    }
}

/// Unix socket
pub type UnixSocket = MioAdapter<mio_orig::unix::UnixSocket>;

impl UnixSocket {
    /// Returns a new, unbound, Unix domain socket
    pub fn stream() -> io::Result<UnixSocket> {
        mio_orig::unix::UnixSocket::stream().map(MioAdapter::new)
    }

    /// Connect the socket to the specified address
    pub fn connect<P: AsRef<Path> + ?Sized>(self, addr: &P) -> io::Result<(UnixStream, bool)> {
        self.shared()
            .io_ref()
            .try_clone()
            .and_then(|t| mio_orig::unix::UnixSocket::connect(t, addr))
            .map(|(t, b)| (MioAdapter::new(t), b))
    }

    /// Bind the socket to the specified address
    pub fn bind<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
        self.shared().io_ref().bind(addr)
    }

    /// Clone
    pub fn try_clone(&self) -> io::Result<Self> {
        self.shared().io_ref().try_clone().map(MioAdapter::new)
    }
}

/// Unix stream
pub type UnixStream = MioAdapter<mio_orig::unix::UnixStream>;

impl UnixStream {
    /// Connect UnixStream to `path`
    pub fn connect<P: AsRef<Path> + ?Sized>(path: &P) -> io::Result<UnixStream> {
        mio_orig::unix::UnixStream::connect(path).map(MioAdapter::new)
    }

    /// Clone
    pub fn try_clone(&self) -> io::Result<Self> {
        self.shared().io_ref().try_clone().map(MioAdapter::new)
    }

    /// Try reading data into a buffer.
    ///
    /// This will not block.
    pub fn try_read_recv_fd(&mut self,
                            buf: &mut [u8])
                            -> io::Result<Option<(usize, Option<RawFd>)>> {
        self.shared().io_mut().try_read_recv_fd(buf)
    }

    /// Block on read.
    pub fn read_recv_fd(&mut self, buf: &mut [u8]) -> io::Result<(usize, Option<RawFd>)> {
        loop {
            let res = self.try_read_recv_fd(buf);

            match res {
                Ok(None) => self.block_on(RW::read()),
                Ok(Some(r)) => {
                    return Ok(r);
                }
                Err(e) => return Err(e),
            }
        }
    }

    /// Try writing a data from the buffer.
    ///
    /// This will not block.
    pub fn try_write_send_fd(&self, buf: &[u8], fd: RawFd) -> io::Result<Option<usize>> {
        self.shared().io_mut().try_write_send_fd(buf, fd)
    }

    /// Block on write
    pub fn write_send_fd(&mut self, buf: &[u8], fd: RawFd) -> io::Result<usize> {
        loop {
            let res = self.try_write_send_fd(buf, fd);

            match res {
                Ok(None) => self.block_on(RW::write()),
                Ok(Some(r)) => {
                    return Ok(r);
                }
                Err(e) => return Err(e),
            }
        }
    }
}

/// Create a pair of unix pipe (reader and writer)
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
    let (raw_reader, raw_writer) = try!(mio_orig::unix::pipe());

    Ok((MioAdapter::new(raw_reader), MioAdapter::new(raw_writer)))

}
<|endoftext|>


<commit_before>use cursor::Direction;
use buffer::Buffer;
use cursor::Cursor;

use utils;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer<'v>,
    pub top_line_num: uint,
    pub cursor: Cursor<'v>,
}

impl<'v> View<'v> {
    pub fn new(path: &Path) -> View<'v> {
        let buffer = Buffer::new_from_file(path);
        let mut cursor = Cursor::new();
        cursor.set_line(Some(&buffer.lines[0]));

        View {
            buffer: buffer,
            top_line_num: 0,
            cursor: cursor,
        }
    }

    /// Get the height of the view in which content can be drawn
    ///
    /// Excludes the status bar height
    pub fn get_internal_height(&self) -> uint {
        let term_height = utils::get_term_height();

        term_height - 2
    }

    pub fn draw(&self) {
        let height = self.get_internal_height();

        let num_lines = self.buffer.lines.len();
        let lines_to_draw = self.buffer.lines.slice(self.top_line_num, num_lines);

        for (index, line) in lines_to_draw.iter().enumerate() {
            if index <= height {
                let ln = line.borrow();
                utils::draw(index, ln.data.clone());
            }
        }
    }

    pub fn draw_status(&self) {
        let buffer_status = self.buffer.get_status_text();
        let cursor_status = self.cursor.get_status_text();
        let term_height = utils::get_term_height();

        let status_text = format!("{} {}", buffer_status, cursor_status);

        utils::draw(term_height-1, status_text);
    }

    pub fn draw_cursor(&self) {
        let offset = self.cursor.get_offset();
        let linenum = self.cursor.get_linenum();

        utils::draw_cursor(offset, linenum-self.top_line_num);
    }

    pub fn move_cursor(&mut self, direction: Direction) {
        match direction {
            Direction::Up    => { self.move_cursor_up(); },
            Direction::Down  => { self.move_cursor_down(); },
            Direction::Right => { self.cursor.move_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    // TODO(greg): refactor this method with move_cursor_down
    pub fn move_cursor_up(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let prev_linenum = cursor_linenum - 1;

        let num_lines = self.buffer.lines.len() - 1;
        if prev_linenum > num_lines { return }

        {
            let line = &self.buffer.lines[prev_linenum];
            self.cursor.set_line(Some(line));
        }

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;

        // TODO(greg) move this value
        let threshold: int = 5;

        if cursor_offset < threshold {
            self.move_top_line_n_times(cursor_offset - threshold);
        }

    }

    // TODO(greg): refactor this method with move_cursor_up
    pub fn move_cursor_down(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let next_linenum = cursor_linenum + 1;

        let num_lines = self.buffer.lines.len() - 1;
        if next_linenum > num_lines { return }

        {
            let line = &self.buffer.lines[next_linenum];
            self.cursor.set_line(Some(line));
        }

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;
        let height = self.get_internal_height() as int;

        // TODO(greg) move this value
        let threshold = 5;

        if cursor_offset >= (height - threshold) {
            let times = cursor_offset - (height - threshold) + 1;
            self.move_top_line_n_times(times);
        }
    }

    fn move_top_line_n_times(&mut self, mut num_times: int) {
        if num_times == 0 { return }

        // moving down
        if num_times > 0 {
            while num_times > 0 {
                self.top_line_num += 1;
                num_times -= 1;
            }
            return
        }

        // moving up
        if num_times < 0 {
            while num_times < 0 {
                if self.top_line_num == 0 { return }
                self.top_line_num -= 1;
                num_times += 1;
            }
            return
        }
    }

    pub fn delete_char(&mut self, direction: Direction) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 && direction.is_left() {
            let offset = self.buffer.join_line_with_previous(offset, line_num);
            self.move_cursor_up();
            self.cursor.set_offset(offset);
            return
        }

        let line_len = self.cursor.get_line_length();
        if offset == line_len && direction.is_right() {
            self.buffer.join_line_with_previous(offset, line_num+1);
            return
        }

        match direction {
            Direction::Left  => self.cursor.delete_backward_char(),
            Direction::Right => self.cursor.delete_forward_char(),
            _                => {}
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, line_num) = self.cursor.get_position();
        self.buffer.insert_line(offset, line_num);

        self.move_cursor_down();
        self.cursor.set_offset(0);
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use buffer::{Line, Buffer};
    use cursor::{Cursor, Direction};
    use view::View;
    use utils;

    fn setup_view<'v>() -> View<'v> {
        let mut view = View {
            buffer: Buffer::new(),
            top_line_num: 0,
            cursor: Cursor::new(),
        };

        let first_line = RefCell::new(Line::new("test".to_string(), 0));
        let second_line = RefCell::new(Line::new("second".to_string(), 1));

        view.buffer.lines = vec!(first_line, second_line);
        view.cursor.set_line(Some(&view.buffer.lines[0]));

        return view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view();
        view.move_cursor_down();

        assert_eq!(view.cursor.get_linenum(), 1);
        assert_eq!(view.cursor.get_line().borrow().data, "second".to_string());
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.move_cursor_up();
        assert_eq!(view.cursor.get_linenum(), 0);
        assert_eq!(view.cursor.get_line().borrow().data, "test".to_string());
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.insert_line();

        assert_eq!(view.buffer.lines.len(), 3);
        assert_eq!(view.cursor.get_offset(), 0);
        assert_eq!(view.cursor.get_line().borrow().linenum, 1);
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view();
        view.insert_char('t');

        assert_eq!(view.cursor.get_line().borrow().data, "ttest".to_string());
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view();
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, "est".to_string());
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, "est".to_string());
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, "testsecond".to_string());
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view();
        view.cursor.set_offset(4);
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, "testsecond".to_string());
    }

    #[test]
    fn test_get_internal_height() {
        let view = setup_view();
        let term_height = utils::get_term_height();
        assert_eq!(view.get_internal_height(), term_height - 2);
    }
}
<commit_msg>Added threshold to View module<commit_after>use cursor::Direction;
use buffer::Buffer;
use cursor::Cursor;

use utils;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer<'v>,
    pub top_line_num: uint,
    pub cursor: Cursor<'v>,

    threshold: int,
}

impl<'v> View<'v> {
    pub fn new(path: &Path) -> View<'v> {
        let buffer = Buffer::new_from_file(path);
        let mut cursor = Cursor::new();
        cursor.set_line(Some(&buffer.lines[0]));

        View {
            buffer: buffer,
            top_line_num: 0,
            cursor: cursor,
            threshold: 5,
        }
    }

    /// Get the height of the view in which content can be drawn
    ///
    /// Excludes the status bar height
    pub fn get_internal_height(&self) -> uint {
        let term_height = utils::get_term_height();

        term_height - 2
    }

    pub fn draw(&self) {
        let height = self.get_internal_height();

        let num_lines = self.buffer.lines.len();
        let lines_to_draw = self.buffer.lines.slice(self.top_line_num, num_lines);

        for (index, line) in lines_to_draw.iter().enumerate() {
            if index <= height {
                let ln = line.borrow();
                utils::draw(index, ln.data.clone());
            }
        }
    }

    pub fn draw_status(&self) {
        let buffer_status = self.buffer.get_status_text();
        let cursor_status = self.cursor.get_status_text();
        let term_height = utils::get_term_height();

        let status_text = format!("{} {}", buffer_status, cursor_status);

        utils::draw(term_height-1, status_text);
    }

    pub fn draw_cursor(&self) {
        let offset = self.cursor.get_offset();
        let linenum = self.cursor.get_linenum();

        utils::draw_cursor(offset, linenum-self.top_line_num);
    }

    pub fn move_cursor(&mut self, direction: Direction) {
        match direction {
            Direction::Up    => { self.move_cursor_up(); },
            Direction::Down  => { self.move_cursor_down(); },
            Direction::Right => { self.cursor.move_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    // TODO(greg): refactor this method with move_cursor_down
    pub fn move_cursor_up(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let prev_linenum = cursor_linenum - 1;

        let num_lines = self.buffer.lines.len() - 1;
        if prev_linenum > num_lines { return }

        {
            let line = &self.buffer.lines[prev_linenum];
            self.cursor.set_line(Some(line));
        }

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;

        if cursor_offset < self.threshold {
            let times = cursor_offset - self.threshold;
            self.move_top_line_n_times(times);
        }

    }

    // TODO(greg): refactor this method with move_cursor_up
    pub fn move_cursor_down(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let next_linenum = cursor_linenum + 1;

        let num_lines = self.buffer.lines.len() - 1;
        if next_linenum > num_lines { return }

        {
            let line = &self.buffer.lines[next_linenum];
            self.cursor.set_line(Some(line));
        }

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;
        let height = self.get_internal_height() as int;

        // TODO(greg) move this value
        // let threshold: int = 5;

        if cursor_offset >= (height - self.threshold) {
            let times = cursor_offset - (height - self.threshold) + 1;
            self.move_top_line_n_times(times);
        }
    }

    fn move_top_line_n_times(&mut self, mut num_times: int) {
        if num_times == 0 { return }

        // moving down
        if num_times > 0 {
            while num_times > 0 {
                self.top_line_num += 1;
                num_times -= 1;
            }
            return
        }

        // moving up
        if num_times < 0 {
            while num_times < 0 {
                if self.top_line_num == 0 { return }
                self.top_line_num -= 1;
                num_times += 1;
            }
            return
        }
    }

    pub fn delete_char(&mut self, direction: Direction) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 && direction.is_left() {
            let offset = self.buffer.join_line_with_previous(offset, line_num);
            self.move_cursor_up();
            self.cursor.set_offset(offset);
            return
        }

        let line_len = self.cursor.get_line_length();
        if offset == line_len && direction.is_right() {
            self.buffer.join_line_with_previous(offset, line_num+1);
            return
        }

        match direction {
            Direction::Left  => self.cursor.delete_backward_char(),
            Direction::Right => self.cursor.delete_forward_char(),
            _                => {}
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, line_num) = self.cursor.get_position();
        self.buffer.insert_line(offset, line_num);

        self.move_cursor_down();
        self.cursor.set_offset(0);
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use buffer::{Line, Buffer};
    use cursor::{Cursor, Direction};
    use view::View;
    use utils;

    fn setup_view<'v>() -> View<'v> {
        let mut view = View {
            buffer: Buffer::new(),
            top_line_num: 0,
            cursor: Cursor::new(),
            threshold: 5,
        };

        let first_line = RefCell::new(Line::new("test".to_string(), 0));
        let second_line = RefCell::new(Line::new("second".to_string(), 1));

        view.buffer.lines = vec!(first_line, second_line);
        view.cursor.set_line(Some(&view.buffer.lines[0]));

        return view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view();
        view.move_cursor_down();

        assert_eq!(view.cursor.get_linenum(), 1);
        assert_eq!(view.cursor.get_line().borrow().data, "second".to_string());
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.move_cursor_up();
        assert_eq!(view.cursor.get_linenum(), 0);
        assert_eq!(view.cursor.get_line().borrow().data, "test".to_string());
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.insert_line();

        assert_eq!(view.buffer.lines.len(), 3);
        assert_eq!(view.cursor.get_offset(), 0);
        assert_eq!(view.cursor.get_line().borrow().linenum, 1);
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view();
        view.insert_char('t');

        assert_eq!(view.cursor.get_line().borrow().data, "ttest".to_string());
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view();
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, "est".to_string());
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, "est".to_string());
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, "testsecond".to_string());
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view();
        view.cursor.set_offset(4);
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, "testsecond".to_string());
    }

    #[test]
    fn test_get_internal_height() {
        let view = setup_view();
        let term_height = utils::get_term_height();
        assert_eq!(view.get_internal_height(), term_height - 2);
    }
}
<|endoftext|>


<commit_before>//! A collection of waveform generating functions.
//!
//! Given a time `t` and `frequency`, returns the amplitude of the waveform
//! at the given time.
//!
//! `frequency` is in hertz (`44_100.0f64`)
//! `t` is in seconds; sample_rate is handled during synthesis
//!
//! Amplitude is in the range [-1, 1] and will be quantized or scaled to target bit depth
//!
//! See the short! source for each generator for exact details on what they do.

use std::collections::VecDeque;
use std::f64::consts::PI;

use crate::filter::envelope;

pub fn sine_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| (t * frequency * 2.0 * PI).sin()
}

pub fn square_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let sin_wave = sine_wave(frequency);
        if sin_wave(t).is_sign_positive() {
            1.0
        } else {
            -1.0
        }
    }
}

pub fn sawtooth_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let t_factor = t * frequency;
        t_factor - t_factor.floor() - 0.5
    }
}

pub fn triangle_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let sawtooth_wave = sawtooth_wave(frequency);
        (sawtooth_wave(t).abs() - 0.25) * 4.0
    }
}

pub fn tangent_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        (((t * frequency * PI) - 0.5).tan() / 4.0)
            .max(-1.0)
            .min(1.0)
    }
}

pub fn bell(frequency: f64, attack: f64, decay: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        // TODO: lazy-static this table
        // Frequency, amplitude, decay
        let harmonics_table: [(f64, f64, f64); 9] = [
            (0.56, 1.5, 1.0),
            (0.92, 0.5, 2.0),
            (1.19, 0.25, 4.0),
            (1.71, 0.125, 6.0),
            (2.00, 0.0625, 8.4),
            (2.74, 0.03125, 10.8),
            (3.00, 0.015625, 13.6),
            (3.76, 0.0078125, 16.4),
            (4.07, 0.00390625, 19.6),
        ];

        harmonics_table.iter().fold(0.0, |acc, h| {
            acc + sine_wave(frequency * h.0)(t) * h.1 * envelope(t, attack, decay * h.2)
        }) / 2.0
    }
}

pub fn organ(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let frequency_2 = (frequency / 2.0) * 3.0;
        sine_wave(frequency)(t) + 0.2 * sine_wave(frequency_2)(t)
    }
}

/// Bastardised and butchered generic Karplus-Strong synthesis.
/// Try a Sawtooth, or even a Bell wave.
///
/// This is an example of a generator function using another generator function.
/// In this case, `karplus_strong` wraps around a generator function and
/// applies a poor emulation of a real-world object over it.
///
/// `attack` in seconds
/// `decay` in seconds
/// `sharpness` 0-1 is decent
/// `sample_rate` in hertz (eg, `44_100.0`)
///
/// ```
/// use synthrs::wave;
///
/// let karplus_sawtooth_generator =
///     |frequency: f64| {
///         wave::karplus_strong(wave::sawtooth_wave(frequency), 0.01, 1.0, 0.9, 44_100.0)
///     };
/// ```
pub fn karplus_strong<F: Fn(f64) -> f64>(
    generator: F,
    attack: f64,
    decay: f64,
    sharpness: f64,
    sample_rate: f64,
) -> impl Fn(f64) -> f64 {
    move |t| {
        let tick = 1.0 / sample_rate;

        // Instead of using delay_line_generator we manually unroll the loop here
        (0..10usize).fold(0.0, |acc, i| {
            acc + generator(t - tick * i as f64)
                * envelope(tick * i as f64, attack, decay)
                * sharpness.powf(i as f64)
        })
    }
}

pub fn noise() -> impl Fn(f64) -> f64 {
    |_t| rand::random::<f64>()
}

/// `sampler` creates a a generator function given a bunch of samples. Different frequencies are
/// generated using a simple pitch shift.
///
/// `frequency`: The frequency passed in to the generator
/// `sample`: The sample to be used. This is a `&'static Vec<f64>` and can be done during runtime with `lazy_static!`.
/// `sample_frequency`: The frequency of the sample provided. This is used to calculate how much to shift the pitch.
/// `sample_rate`: The sample rate of the given sample
/// ```compile_fail
/// use synthrs::sampler;
/// use synthrs::wave;
///
/// lazy_static! {
///    static ref SAMPLE: Vec<f64> =
///         sampler::samples_from_wave_file("test/assets/sine.wav").unwrap();
/// }
///
/// let frequency_to_generate = 110.0;
/// let sampler = wave::sampler(frequency_to_generate, &SAMPLE, 440.0, 44_100.0);
/// ```
pub fn sampler(
    frequency: f64,
    sample: &'static Vec<f64>,
    sample_frequency: f64,
    sample_rate: f64,
) -> impl Fn(f64) -> f64 {
    move |t| {
        let multiplier = frequency / sample_frequency;
        let original_index = sample_rate * t;
        let adjusted_index = (multiplier * original_index).round() as usize;

        if adjusted_index >= sample.len() {
            0.0
        } else {
            sample[adjusted_index]
        }
    }
}

/// Wwraps a generator function, delaying its output by `delay_length_samples` number of samples.
/// This isn't very useful in most cases because generator will likely change due to frequency changes.alloc
/// Look at `::crate::filter::DelayLine` for a more stateful filter that works on generated samples instead for most use cases.
///
/// `generator`: The generator to delay
/// `delay_length`: Seconds to delay by
/// `sample_rate`: The sample rate of the given sample
///
/// ```
/// use synthrs::sampler;
/// use synthrs::wave;
///
/// // This creates a sine wave that's delayed by 1 second
/// let generator = wave::sine_wave(440.0);
/// let delayed_sine = wave::delay_line_generator(generator, 1.0, 44_100);
/// ```
pub fn delay_line_generator<F: Fn(f64) -> f64>(
    generator: F,
    delay_length: f64,
    sample_rate: usize,
) -> impl Fn(f64) -> f64 {
    let delay_length_samples = (delay_length * sample_rate as f64).floor() as usize;
    let buf: VecDeque<f64> = VecDeque::with_capacity(delay_length_samples + 1);
    let cell = std::cell::RefCell::new(buf);

    move |t| {
        let mut buf = cell.borrow_mut();
        let current_sample = generator(t);

        let output = if buf.len() < delay_length_samples {
            0.0f64
        } else {
            buf.pop_front().unwrap_or(0.0f64)
        };

        buf.push_back(current_sample);
        output
    }
}

/// `rising_linear` is a stateful generator function.
/// Starting from `start_frequency`, it increases the output frequency by `increment_per_sample`
/// each time it is called, and loops back to `start_frequency` when it is above `end_frequency`.
///
/// This is mainly an example on how to do stateful generator functions.
/// This is achieved using interior mutability. See the source for details on how this is achieved.
pub fn rising_linear(
    start_frequency: f64,
    end_frequency: f64,
    increment_per_sample: f64,
) -> impl Fn(f64) -> f64 {
    // Our state! You can use a `RefCell` or a `Cell` for a start.
    // This example uses a `RefCell`, but a `Cell` will be simpler and
    // suffice for this simple state. An example using `Cell` is provided below.
    let cell = std::cell::RefCell::new(start_frequency);

    move |t| {
        let mut current_frequency = cell.borrow_mut();

        *current_frequency += increment_per_sample;

        if *current_frequency > end_frequency {
            *current_frequency = start_frequency;
        }

        sine_wave(*current_frequency)(t)
    }

    // The below is an example using `Cell` instead of `RefCell`.
    //
    // ```
    // let mut cell = std::cell::Cell::new(start_frequency);
    //
    // move |t| {
    //     let current_frequency = cell.get();
    //
    //     let new_frequency = if current_frequency > end_frequency {
    //         start_frequency
    //     } else {
    //         current_frequency + increment_per_sample
    //     };
    //
    //     cell.set(new_frequency);
    //
    //     sine_wave(new_frequency)(t)
    // }
    // ```
}

mod tests {
    #[allow(unused_imports)]
    use super::*;

    #[test]
    fn test_delay_line() {
        let identity = |t| t;
        let delayed = delay_line_generator(identity, 3.0, 1);

        assert_eq!(delayed(1.0), 0.0);
        assert_eq!(delayed(3.0), 0.0);
        assert_eq!(delayed(5.0), 0.0);
        assert_eq!(delayed(7.0), 1.0);
        assert_eq!(delayed(11.0), 3.0);
        assert_eq!(delayed(13.0), 5.0);
        assert_eq!(delayed(17.0), 7.0);
        assert_eq!(delayed(19.0), 11.0);
    }
}
<commit_msg>Use a RefCell for wave::Sampler<commit_after>//! A collection of waveform generating functions.
//!
//! Given a time `t` and `frequency`, returns the amplitude of the waveform
//! at the given time.
//!
//! `frequency` is in hertz (`44_100.0f64`)
//! `t` is in seconds; sample_rate is handled during synthesis
//!
//! Amplitude is in the range [-1, 1] and will be quantized or scaled to target bit depth
//!
//! See the short! source for each generator for exact details on what they do.

use std::collections::VecDeque;
use std::f64::consts::PI;
use std::cell::RefCell;

use crate::filter::envelope;

pub fn sine_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| (t * frequency * 2.0 * PI).sin()
}

pub fn square_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let sin_wave = sine_wave(frequency);
        if sin_wave(t).is_sign_positive() {
            1.0
        } else {
            -1.0
        }
    }
}

pub fn sawtooth_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let t_factor = t * frequency;
        t_factor - t_factor.floor() - 0.5
    }
}

pub fn triangle_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let sawtooth_wave = sawtooth_wave(frequency);
        (sawtooth_wave(t).abs() - 0.25) * 4.0
    }
}

pub fn tangent_wave(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        (((t * frequency * PI) - 0.5).tan() / 4.0)
            .max(-1.0)
            .min(1.0)
    }
}

pub fn bell(frequency: f64, attack: f64, decay: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        // TODO: lazy-static this table
        // Frequency, amplitude, decay
        let harmonics_table: [(f64, f64, f64); 9] = [
            (0.56, 1.5, 1.0),
            (0.92, 0.5, 2.0),
            (1.19, 0.25, 4.0),
            (1.71, 0.125, 6.0),
            (2.00, 0.0625, 8.4),
            (2.74, 0.03125, 10.8),
            (3.00, 0.015625, 13.6),
            (3.76, 0.0078125, 16.4),
            (4.07, 0.00390625, 19.6),
        ];

        harmonics_table.iter().fold(0.0, |acc, h| {
            acc + sine_wave(frequency * h.0)(t) * h.1 * envelope(t, attack, decay * h.2)
        }) / 2.0
    }
}

pub fn organ(frequency: f64) -> impl Fn(f64) -> f64 {
    move |t| {
        let frequency_2 = (frequency / 2.0) * 3.0;
        sine_wave(frequency)(t) + 0.2 * sine_wave(frequency_2)(t)
    }
}

/// Bastardised and butchered generic Karplus-Strong synthesis.
/// Try a Sawtooth, or even a Bell wave.
///
/// This is an example of a generator function using another generator function.
/// In this case, `karplus_strong` wraps around a generator function and
/// applies a poor emulation of a real-world object over it.
///
/// `attack` in seconds
/// `decay` in seconds
/// `sharpness` 0-1 is decent
/// `sample_rate` in hertz (eg, `44_100.0`)
///
/// ```
/// use synthrs::wave;
///
/// let karplus_sawtooth_generator =
///     |frequency: f64| {
///         wave::karplus_strong(wave::sawtooth_wave(frequency), 0.01, 1.0, 0.9, 44_100.0)
///     };
/// ```
pub fn karplus_strong<F: Fn(f64) -> f64>(
    generator: F,
    attack: f64,
    decay: f64,
    sharpness: f64,
    sample_rate: f64,
) -> impl Fn(f64) -> f64 {
    move |t| {
        let tick = 1.0 / sample_rate;

        // Instead of using delay_line_generator we manually unroll the loop here
        (0..10usize).fold(0.0, |acc, i| {
            acc + generator(t - tick * i as f64)
                * envelope(tick * i as f64, attack, decay)
                * sharpness.powf(i as f64)
        })
    }
}

pub fn noise() -> impl Fn(f64) -> f64 {
    |_t| rand::random::<f64>()
}

/// `sampler` creates a a generator function given a bunch of samples. Different frequencies are
/// generated using a simple pitch shift.
///
/// `frequency`: The frequency passed in to the generator
/// `sample`: The sample to be used. This is a `&'static Vec<f64>` and can be done during runtime with `lazy_static!`.
/// `sample_frequency`: The frequency of the sample provided. This is used to calculate how much to shift the pitch.
/// `sample_rate`: The sample rate of the given sample
/// ```compile_fail
/// use synthrs::sampler;
/// use synthrs::wave;
///
/// lazy_static! {
///    static ref SAMPLE: Vec<f64> =
///         sampler::samples_from_wave_file("test/assets/sine.wav").unwrap();
/// }
///
/// let frequency_to_generate = 110.0;
/// let sampler = wave::sampler(frequency_to_generate, &SAMPLE, 440.0, 44_100.0);
/// ```
pub fn sampler(
    frequency: f64,
    sample: &'static Vec<f64>,
    sample_frequency: f64,
    sample_rate: f64,
) -> impl Fn(f64) -> f64 {
    let cell = RefCell::new(sample);

    move |t| {
        let multiplier = frequency / sample_frequency;
        let original_index = sample_rate * t;
        let adjusted_index = (multiplier * original_index).round() as usize;

        let sample_borrow = cell.borrow_mut();

        if adjusted_index >= sample_borrow.len() {
            0.0
        } else {
            sample_borrow[adjusted_index]
        }
    }
}

/// Wwraps a generator function, delaying its output by `delay_length_samples` number of samples.
/// This isn't very useful in most cases because generator will likely change due to frequency changes.alloc
/// Look at `::crate::filter::DelayLine` for a more stateful filter that works on generated samples instead for most use cases.
///
/// `generator`: The generator to delay
/// `delay_length`: Seconds to delay by
/// `sample_rate`: The sample rate of the given sample
///
/// ```
/// use synthrs::sampler;
/// use synthrs::wave;
///
/// // This creates a sine wave that's delayed by 1 second
/// let generator = wave::sine_wave(440.0);
/// let delayed_sine = wave::delay_line_generator(generator, 1.0, 44_100);
/// ```
pub fn delay_line_generator<F: Fn(f64) -> f64>(
    generator: F,
    delay_length: f64,
    sample_rate: usize,
) -> impl Fn(f64) -> f64 {
    let delay_length_samples = (delay_length * sample_rate as f64).floor() as usize;
    let buf: VecDeque<f64> = VecDeque::with_capacity(delay_length_samples + 1);
    let cell = std::cell::RefCell::new(buf);

    move |t| {
        let mut buf = cell.borrow_mut();
        let current_sample = generator(t);

        let output = if buf.len() < delay_length_samples {
            0.0f64
        } else {
            buf.pop_front().unwrap_or(0.0f64)
        };

        buf.push_back(current_sample);
        output
    }
}

/// `rising_linear` is a stateful generator function.
/// Starting from `start_frequency`, it increases the output frequency by `increment_per_sample`
/// each time it is called, and loops back to `start_frequency` when it is above `end_frequency`.
///
/// This is mainly an example on how to do stateful generator functions.
/// This is achieved using interior mutability. See the source for details on how this is achieved.
pub fn rising_linear(
    start_frequency: f64,
    end_frequency: f64,
    increment_per_sample: f64,
) -> impl Fn(f64) -> f64 {
    // Our state! You can use a `RefCell` or a `Cell` for a start.
    // This example uses a `RefCell`, but a `Cell` will be simpler and
    // suffice for this simple state. An example using `Cell` is provided below.
    let cell = std::cell::RefCell::new(start_frequency);

    move |t| {
        let mut current_frequency = cell.borrow_mut();

        *current_frequency += increment_per_sample;

        if *current_frequency > end_frequency {
            *current_frequency = start_frequency;
        }

        sine_wave(*current_frequency)(t)
    }

    // The below is an example using `Cell` instead of `RefCell`.
    //
    // ```
    // let mut cell = std::cell::Cell::new(start_frequency);
    //
    // move |t| {
    //     let current_frequency = cell.get();
    //
    //     let new_frequency = if current_frequency > end_frequency {
    //         start_frequency
    //     } else {
    //         current_frequency + increment_per_sample
    //     };
    //
    //     cell.set(new_frequency);
    //
    //     sine_wave(new_frequency)(t)
    // }
    // ```
}

mod tests {
    #[allow(unused_imports)]
    use super::*;

    #[test]
    fn test_delay_line() {
        let identity = |t| t;
        let delayed = delay_line_generator(identity, 3.0, 1);

        assert_eq!(delayed(1.0), 0.0);
        assert_eq!(delayed(3.0), 0.0);
        assert_eq!(delayed(5.0), 0.0);
        assert_eq!(delayed(7.0), 1.0);
        assert_eq!(delayed(11.0), 3.0);
        assert_eq!(delayed(13.0), 5.0);
        assert_eq!(delayed(17.0), 7.0);
        assert_eq!(delayed(19.0), 11.0);
    }
}
<|endoftext|>