<commit_before>//! A simple timer, used to enqueue operations meant to be executed at
//! a given time or after a given delay.

extern crate chrono;

use std::cmp::Ordering;
use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender};
use std::collections::BinaryHeap;

use chrono::{Duration, DateTime, UTC};

/// An item scheduled for delayed execution.
struct Schedule {
    /// The instant at which to execute.
    date: DateTime<UTC>,

    /// The callback to execute.
    cb: Box<Fn() + Send>
}
impl Ord for Schedule {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date).reverse()
    }
}
impl PartialOrd for Schedule {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date).map(|ord| ord.reverse())
    }
}
impl Eq for Schedule {
}
impl PartialEq for Schedule {
    fn eq(&self, other: &Self) -> bool {
        self.date.eq(&other.date)
    }
}

/// An operation to be sent across threads.
enum Op {
    /// Schedule a new item for execution.
    Schedule(Schedule),

    /// Stop the thread.
    Stop
}

/// A mutex-based kind-of-channel used to communicate between the
/// Communication thread and the Scheuler thread.
struct WaiterChannel {
    /// Pending messages.
    messages: Mutex<Vec<Op>>,
    /// A condition variable used for waiting.
    condvar: Condvar,
}
impl WaiterChannel {
    fn with_capacity(cap: usize) -> Self {
        WaiterChannel {
            messages: Mutex::new(Vec::with_capacity(cap)),
            condvar: Condvar::new(),
        }
    }
}

struct Scheduler {
    waiter: Arc<WaiterChannel>,
    heap: BinaryHeap<Schedule>,
}

impl Scheduler {
    fn with_capacity(waiter: Arc<WaiterChannel>, capacity: usize) -> Self {
        Scheduler {
            waiter: waiter,
            heap: BinaryHeap::with_capacity(capacity),
        }
    }
    fn run(&mut self) {
        let ref waiter = *self.waiter;
        loop {
            let mut lock = waiter.messages.lock().unwrap();

            // Pop all messages.
            for msg in lock.drain(..) {
                match msg {
                    Op::Stop => {
                        return;
                    }
                    Op::Schedule(sched) => self.heap.push(sched),
                }
            }

            // Pop all the callbacks that are ready.
            let mut delay = None;
            loop {
                let now = UTC::now();
                if let Some(sched) = self.heap.peek() {
                    if sched.date > now {
                        // First item is not ready yet, so nothing is ready.
                        // We assume that `sched.date > now` is still true.
                        delay = Some(sched.date - now);
                        break;
                    }
                } else {
                    // No item at all.
                    break;
                }
                let sched = self.heap.pop().unwrap(); // We just checked that the heap is not empty.
                (sched.cb)();
            }

            match delay {
                None => {
                    let _ = waiter.condvar.wait(lock);
                },
                Some(delay) => {
                    let sec = delay.num_seconds();
                    let ns = (delay - Duration::seconds(sec)).num_nanoseconds().unwrap(); // This `unwrap()` asserts that the number of ns is not > 1_000_000_000. Since we just substracted the number of seconds, the assertion should always pass.
                    let duration = std::time::Duration::new(sec as u64, ns as u32);
                    let _ = waiter.condvar.wait_timeout(lock, duration);
                }
            }
        }
    }
}

/// A timer, used to schedule execution of callbacks at a later date.
///
/// In the current implementation, each timer is executed as two
/// threads. The _Scheduler_ thread is in charge of maintaining the
/// queue of callbacks to execute and of actually executing them. The
/// _Communication_ thread is in charge of communicating with the
/// _Scheduler_ thread (which requires acquiring a possibly-long-held
/// Mutex) without blocking the caller thread.
pub struct Timer {
    /// Sender used to communicate with the _Communication_ thread. In
    /// turn, this thread will send
    tx: Sender<Op>
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.tx.send(Op::Stop).unwrap();
    }
}

impl Timer {
    /// Create a timer.
    ///
    /// This immediatey launches two threads, which will remain
    /// launched until the timer is dropped. As expected, the threads
    /// spend most of their life waiting for instructions.
    pub fn new() -> Self {
        Self::with_capacity(32)
    }

    /// As `new()`, but with a manually specified initial capaicty.
    pub fn with_capacity(capacity: usize) -> Self {
        let waiter_send = Arc::new(WaiterChannel::with_capacity(capacity));
        let waiter_recv = waiter_send.clone();

        // Spawn a first thread, whose sole role is to dispatch
        // messages to the second thread without having to wait too
        // long for the mutex.
        let (tx, rx) = channel();
        thread::spawn(move || {
            use Op::*;
            let ref waiter = *waiter_send;
            for msg in rx.iter() {
                let mut vec = waiter.messages.lock().unwrap();
                match msg {
                    Schedule(sched) => {
                        vec.push(Schedule(sched));
                        waiter.condvar.notify_one();
                    }
                    Stop => {
                        vec.clear();
                        vec.push(Op::Stop);
                        waiter.condvar.notify_one();
                        return;
                    }
                }
            }
        });

        // Spawn a second thread, in charge of scheduling.
        thread::Builder::new().name("Timer thread".to_owned()).spawn(move || {
            let mut scheduler = Scheduler::with_capacity(waiter_recv, capacity);
            scheduler.run()
        }).unwrap();
        Timer {
            tx: tx
        }
    }

    /// Schedule a callback for execution after a delay.
    ///
    /// Callbacks are guaranteed to never be called before the
    /// delay. However, it is possible that they will be called a
    /// little after the delay.
    ///
    /// If the delay is negative, the callback is executed as soon as
    /// possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate timer;
    /// extern crate chrono;
    /// use std::sync::mpsc::channel;
    ///
    /// let timer = timer::Timer::new();
    /// let (tx, rx) = channel();
    ///
    /// timer.schedule_with_delay(chrono::Duration::seconds(3), move || {
    ///   // This closure is executed on the scheduler thread,
    ///   // so we want to move it away asap.
    ///
    ///   let _ignored = tx.send(()); // Avoid unwrapping here.
    /// });
    ///
    /// rx.recv().unwrap();
    /// println!("This code has been executed after 3 seconds");
    /// ```
    pub fn schedule_with_delay<F>(&self, delay: Duration, cb: F)
        where F: 'static + Fn() + Send {
        self.schedule_with_date(UTC::now() + delay, cb)
    }

    /// Schedule a callback for execution at a given date.
    ///
    /// Callbacks are guaranteed to never be called before their
    /// date. However, it is possible that they will be called a
    /// little after it.
    ///
    /// If the date is in the past, the callback is executed as soon
    /// as possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    pub fn schedule_with_date<F>(&self, date: DateTime<UTC>, cb: F)
        where F: 'static + Fn() + Send {
        self.tx.send(Op::Schedule(Schedule {
            date: date,
            cb: Box::new(cb)
        })).unwrap();
    }
}

#[test]
fn test_schedule_with_delay() {
    let timer = Timer::new();
    let (tx, rx) = channel();

    // Schedule a number of callbacks in an arbitrary order, make sure
    // that they are executed in the right order.
    let mut delays = vec![1, 5, 3, -1];
    let start = UTC::now();
    for i in delays.clone() {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    delays.sort();
    for (i, msg) in (0..delays.len()).zip(rx.iter()) {
        let elapsed = (UTC::now() - start).num_seconds();
        println!("Received message {} after {} seconds", msg, elapsed);
        assert_eq!(msg, delays[i]);
        assert!(delays[i] <= elapsed && elapsed <= delays[i] + 3, "We have waited {} seconds, expecting [{}, {}]", elapsed, delays[i], delays[i] + 3);
    }

    // Now make sure that callbacks that are designed to be executed
    // immediately are executed quickly.
    let start = UTC::now();
    for i in vec![10, 0] {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    assert_eq!(rx.recv().unwrap(), 0);
    assert!(UTC::now() - start <= Duration::seconds(1));
}
<commit_msg>Fn => FnMut<commit_after>//! A simple timer, used to enqueue operations meant to be executed at
//! a given time or after a given delay.

extern crate chrono;

use std::cmp::Ordering;
use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender};
use std::collections::BinaryHeap;

use chrono::{Duration, DateTime, UTC};

/// An item scheduled for delayed execution.
struct Schedule {
    /// The instant at which to execute.
    date: DateTime<UTC>,

    /// The callback to execute.
    cb: Box<FnMut() + Send>
}
impl Ord for Schedule {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date).reverse()
    }
}
impl PartialOrd for Schedule {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date).map(|ord| ord.reverse())
    }
}
impl Eq for Schedule {
}
impl PartialEq for Schedule {
    fn eq(&self, other: &Self) -> bool {
        self.date.eq(&other.date)
    }
}

/// An operation to be sent across threads.
enum Op {
    /// Schedule a new item for execution.
    Schedule(Schedule),

    /// Stop the thread.
    Stop
}

/// A mutex-based kind-of-channel used to communicate between the
/// Communication thread and the Scheuler thread.
struct WaiterChannel {
    /// Pending messages.
    messages: Mutex<Vec<Op>>,
    /// A condition variable used for waiting.
    condvar: Condvar,
}
impl WaiterChannel {
    fn with_capacity(cap: usize) -> Self {
        WaiterChannel {
            messages: Mutex::new(Vec::with_capacity(cap)),
            condvar: Condvar::new(),
        }
    }
}

struct Scheduler {
    waiter: Arc<WaiterChannel>,
    heap: BinaryHeap<Schedule>,
}

impl Scheduler {
    fn with_capacity(waiter: Arc<WaiterChannel>, capacity: usize) -> Self {
        Scheduler {
            waiter: waiter,
            heap: BinaryHeap::with_capacity(capacity),
        }
    }
    fn run(&mut self) {
        let ref waiter = *self.waiter;
        loop {
            let mut lock = waiter.messages.lock().unwrap();

            // Pop all messages.
            for msg in lock.drain(..) {
                match msg {
                    Op::Stop => {
                        return;
                    }
                    Op::Schedule(sched) => self.heap.push(sched),
                }
            }

            // Pop all the callbacks that are ready.
            let mut delay = None;
            loop {
                let now = UTC::now();
                if let Some(sched) = self.heap.peek() {
                    if sched.date > now {
                        // First item is not ready yet, so nothing is ready.
                        // We assume that `sched.date > now` is still true.
                        delay = Some(sched.date - now);
                        break;
                    }
                } else {
                    // No item at all.
                    break;
                }
                let mut sched = self.heap.pop().unwrap(); // We just checked that the heap is not empty.
                (sched.cb)();
            }

            match delay {
                None => {
                    let _ = waiter.condvar.wait(lock);
                },
                Some(delay) => {
                    let sec = delay.num_seconds();
                    let ns = (delay - Duration::seconds(sec)).num_nanoseconds().unwrap(); // This `unwrap()` asserts that the number of ns is not > 1_000_000_000. Since we just substracted the number of seconds, the assertion should always pass.
                    let duration = std::time::Duration::new(sec as u64, ns as u32);
                    let _ = waiter.condvar.wait_timeout(lock, duration);
                }
            }
        }
    }
}

/// A timer, used to schedule execution of callbacks at a later date.
///
/// In the current implementation, each timer is executed as two
/// threads. The _Scheduler_ thread is in charge of maintaining the
/// queue of callbacks to execute and of actually executing them. The
/// _Communication_ thread is in charge of communicating with the
/// _Scheduler_ thread (which requires acquiring a possibly-long-held
/// Mutex) without blocking the caller thread.
pub struct Timer {
    /// Sender used to communicate with the _Communication_ thread. In
    /// turn, this thread will send
    tx: Sender<Op>
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.tx.send(Op::Stop).unwrap();
    }
}

impl Timer {
    /// Create a timer.
    ///
    /// This immediatey launches two threads, which will remain
    /// launched until the timer is dropped. As expected, the threads
    /// spend most of their life waiting for instructions.
    pub fn new() -> Self {
        Self::with_capacity(32)
    }

    /// As `new()`, but with a manually specified initial capaicty.
    pub fn with_capacity(capacity: usize) -> Self {
        let waiter_send = Arc::new(WaiterChannel::with_capacity(capacity));
        let waiter_recv = waiter_send.clone();

        // Spawn a first thread, whose sole role is to dispatch
        // messages to the second thread without having to wait too
        // long for the mutex.
        let (tx, rx) = channel();
        thread::spawn(move || {
            use Op::*;
            let ref waiter = *waiter_send;
            for msg in rx.iter() {
                let mut vec = waiter.messages.lock().unwrap();
                match msg {
                    Schedule(sched) => {
                        vec.push(Schedule(sched));
                        waiter.condvar.notify_one();
                    }
                    Stop => {
                        vec.clear();
                        vec.push(Op::Stop);
                        waiter.condvar.notify_one();
                        return;
                    }
                }
            }
        });

        // Spawn a second thread, in charge of scheduling.
        thread::Builder::new().name("Timer thread".to_owned()).spawn(move || {
            let mut scheduler = Scheduler::with_capacity(waiter_recv, capacity);
            scheduler.run()
        }).unwrap();
        Timer {
            tx: tx
        }
    }

    /// Schedule a callback for execution after a delay.
    ///
    /// Callbacks are guaranteed to never be called before the
    /// delay. However, it is possible that they will be called a
    /// little after the delay.
    ///
    /// If the delay is negative, the callback is executed as soon as
    /// possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate timer;
    /// extern crate chrono;
    /// use std::sync::mpsc::channel;
    ///
    /// let timer = timer::Timer::new();
    /// let (tx, rx) = channel();
    ///
    /// timer.schedule_with_delay(chrono::Duration::seconds(3), move || {
    ///   // This closure is executed on the scheduler thread,
    ///   // so we want to move it away asap.
    ///
    ///   let _ignored = tx.send(()); // Avoid unwrapping here.
    /// });
    ///
    /// rx.recv().unwrap();
    /// println!("This code has been executed after 3 seconds");
    /// ```
    pub fn schedule_with_delay<F>(&self, delay: Duration, cb: F)
        where F: 'static + FnMut() + Send {
        self.schedule_with_date(UTC::now() + delay, cb)
    }

    /// Schedule a callback for execution at a given date.
    ///
    /// Callbacks are guaranteed to never be called before their
    /// date. However, it is possible that they will be called a
    /// little after it.
    ///
    /// If the date is in the past, the callback is executed as soon
    /// as possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    pub fn schedule_with_date<F>(&self, date: DateTime<UTC>, cb: F)
        where F: 'static + FnMut() + Send {
        self.tx.send(Op::Schedule(Schedule {
            date: date,
            cb: Box::new(cb)
        })).unwrap();
    }
}

#[test]
fn test_schedule_with_delay() {
    let timer = Timer::new();
    let (tx, rx) = channel();

    // Schedule a number of callbacks in an arbitrary order, make sure
    // that they are executed in the right order.
    let mut delays = vec![1, 5, 3, -1];
    let start = UTC::now();
    for i in delays.clone() {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    delays.sort();
    for (i, msg) in (0..delays.len()).zip(rx.iter()) {
        let elapsed = (UTC::now() - start).num_seconds();
        println!("Received message {} after {} seconds", msg, elapsed);
        assert_eq!(msg, delays[i]);
        assert!(delays[i] <= elapsed && elapsed <= delays[i] + 3, "We have waited {} seconds, expecting [{}, {}]", elapsed, delays[i], delays[i] + 3);
    }

    // Now make sure that callbacks that are designed to be executed
    // immediately are executed quickly.
    let start = UTC::now();
    for i in vec![10, 0] {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    assert_eq!(rx.recv().unwrap(), 0);
    assert!(UTC::now() - start <= Duration::seconds(1));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * TODO: the widget names should start with __relm_field_.
 *
 * TODO: for the #[widget] attribute allow pattern matching by creating a function update(&mut
 * self, Quit: Msg, model: &mut Model) so that we can separate the update function in multiple
 * functions.
 *
 * TODO: reset widget name counters when creating new widget?
 *
 * TODO: refactor the code.
 *
 * TODO: chat client/server example.
 *
 * TODO: err if trying to use the SimpleMsg custom derive on stable.
 *
 * TODO: add Cargo travis/appveyor badges.
 *
 * TODO: add default type of () for Model in Widget when it is stable.
 * TODO: optionnaly multi-threaded.
 * TODO: convert GTK+ callback to Stream (does not seem worth it, nor convenient since it will
 * still need to use USFC for the callback method).
 *
 * These probably won't be needed anymore when switching to futures-glib (single-threaded model).
 * TODO: use weak pointers to avoid leaking.
 * TODO: try to avoid having two update() functions by adding the futures to a struct that's
 * returned from the update() function and these futures will then be added to the tokio loop (that
 * probably requires boxing the futures, which we want to avoid).
 * TODO: should have a free function to delete the stream in connect_recv.
 * TODO: automatically create the update_command() function from the events present in the view (or by splitting the update() fucntion).
 * TODO: try tk-easyloop in another branch.
 */

#![feature(conservative_impl_trait)]

extern crate futures;
extern crate glib;
extern crate glib_itc;
extern crate gobject_sys;
extern crate gtk;
extern crate gtk_sys;
#[macro_use]
extern crate log;
extern crate relm_core;

pub mod gtk_ext;
mod macros;
mod stream;
mod widget;

use std::error;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::sync::{Arc, Mutex};
use std::time::SystemTime;

use futures::{Future, Stream};
use glib::Continue;
pub use glib::object::Downcast;
pub use glib::translate::{FromGlibPtrNone, ToGlib};
use glib_itc::{Receiver, channel};
pub use gobject_sys::{GObject, g_object_new};
use gtk::{ContainerExt, IsA, Object, WidgetExt};
use relm_core::Core;
pub use relm_core::{EventStream, Handle, Remote};

pub use self::Error::*;
use self::stream::ToStream;
pub use self::widget::*;

#[must_use]
#[derive(Clone)]
pub struct Component<MODEL, MSG: Clone + DisplayVariant, WIDGET> {
    model: Arc<Mutex<MODEL>>,
    _receiver: Arc<Receiver>,
    stream: EventStream<MSG>,
    widget: WIDGET,
}

impl<MODEL, MSG: Clone + DisplayVariant, WIDGET> Component<MODEL, MSG, WIDGET> {
    pub fn stream(&self) -> &EventStream<MSG> {
        &self.stream
    }
}

impl<MODEL, MSG: Clone + DisplayVariant, WIDGET> Drop for Component<MODEL, MSG, WIDGET> {
    fn drop(&mut self) {
        self.stream.close().ok();
    }
}

#[derive(Debug)]
pub enum Error {
    GtkInit,
    Io(io::Error),
}

impl Display for Error {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        match *self {
            GtkInit => write!(formatter, "Cannot init GTK+"),
            Io(ref error) => write!(formatter, "IO error: {}", error),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            GtkInit => "Cannot init GTK+",
            Io(ref error) => error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            GtkInit => None,
            Io(ref error) => Some(error),
        }
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Io(error)
    }
}

impl From<()> for Error {
    fn from((): ()) -> Error {
        GtkInit
    }
}

pub struct Relm<MSG: Clone + DisplayVariant> {
    handle: Handle,
    stream: EventStream<MSG>,
}

impl<MSG: Clone + DisplayVariant + Send + 'static> Relm<MSG> {
    pub fn connect<CALLBACK, FAILCALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, success_callback: CALLBACK, failure_callback: FAILCALLBACK) -> impl Future<Item=(), Error=()>
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              FAILCALLBACK: Fn(STREAM::Error) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        let event_stream = self.stream.clone();
        let fail_event_stream = self.stream.clone();
        let stream = to_stream.to_stream();
        stream.map_err(move |error| {
            fail_event_stream.emit(failure_callback(error));
            ()
        })
            .for_each(move |result| {
                event_stream.emit(success_callback(result));
                Ok::<(), STREAM::Error>(())
            }
            .map_err(|_| ()))
    }

    pub fn connect_ignore_err<CALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, success_callback: CALLBACK) -> impl Future<Item=(), Error=()>
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        let event_stream = self.stream.clone();
        let stream = to_stream.to_stream();
        stream.map_err(|_| ())
            .for_each(move |result| {
                event_stream.emit(success_callback(result));
                Ok::<(), STREAM::Error>(())
            }
            .map_err(|_| ()))
    }

    pub fn connect_exec<CALLBACK, FAILCALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, callback: CALLBACK, failure_callback: FAILCALLBACK)
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              FAILCALLBACK: Fn(STREAM::Error) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        self.exec(self.connect(to_stream, callback, failure_callback));
    }

    pub fn connect_exec_ignore_err<CALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, callback: CALLBACK)
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        self.exec(self.connect_ignore_err(to_stream, callback));
    }

    pub fn exec<FUTURE: Future<Item=(), Error=()> + 'static>(&self, future: FUTURE) {
        self.handle.spawn(future);
    }

    pub fn handle(&self) -> &Handle {
        &self.handle
    }

    pub fn run<WIDGET>() -> Result<(), Error>
        where WIDGET: Widget<MSG> + 'static,
              WIDGET::Model: Send,
    {
        let _component = init::<WIDGET, MSG>()?;
        gtk::main();
        Ok(())
    }

    pub fn stream(&self) -> &EventStream<MSG> {
        &self.stream
    }
}

pub struct RemoteRelm<MSG: Clone + DisplayVariant> {
    remote: Remote,
    stream: EventStream<MSG>,
}

impl<'a, MSG: Clone + DisplayVariant> RemoteRelm<MSG> {
    pub fn stream(&self) -> &EventStream<MSG> {
        &self.stream
    }
}

fn create_widget_test<WIDGET, MSG>(remote: &Remote) -> (Component<WIDGET::Model, MSG, WIDGET::Container>, WIDGET)
    where WIDGET: Widget<MSG> + Clone + 'static,
          MSG: Clone + DisplayVariant + 'static,
{
    let (sender, mut receiver) = channel();
    let stream = EventStream::new(Arc::new(sender));

    let (widget, model) = {
        let relm = RemoteRelm {
            remote: remote.clone(),
            stream: stream.clone(),
        };
        let model = WIDGET::model();
        (WIDGET::view(relm, &model), model)
    };

    let container = widget.container().clone();
    let model = Arc::new(Mutex::new(model));

    {
        let mut widget = widget.clone();
        let stream = stream.clone();
        let model = model.clone();
        receiver.connect_recv(move || {
            if let Some(event) = stream.pop_ui_events() {
                let mut model = model.lock().unwrap();
                update_widget(&mut widget, event, &mut *model);
            }
            Continue(true)
        });
    }

    let component = Component {
        model: model,
        _receiver: Arc::new(receiver),
        stream: stream,
        widget: container,
    };

    (component, widget)
}

fn create_widget<WIDGET, MSG>(remote: &Remote) -> Component<WIDGET::Model, MSG, WIDGET::Container>
    where WIDGET: Widget<MSG> + 'static,
          MSG: Clone + DisplayVariant + 'static,
{
    let (sender, mut receiver) = channel();
    let stream = EventStream::new(Arc::new(sender));

    let (mut widget, model) = {
        let relm = RemoteRelm {
            remote: remote.clone(),
            stream: stream.clone(),
        };
        let model = WIDGET::model();
        (WIDGET::view(relm, &model), model)
    };

    let container = widget.container().clone();
    let model = Arc::new(Mutex::new(model));

    {
        let stream = stream.clone();
        let model = model.clone();
        receiver.connect_recv(move || {
            if let Some(event) = stream.pop_ui_events() {
                let mut model = model.lock().unwrap();
                update_widget(&mut widget, event, &mut *model);
            }
            Continue(true)
        });
    }

    Component {
        model: model,
        _receiver: Arc::new(receiver),
        stream: stream,
        widget: container,
    }
}

// TODO: remove this workaround.
fn init_gtk() {
    let mut argc = 0;
    unsafe {
        gtk_sys::gtk_init(&mut argc, std::ptr::null_mut());
        gtk::set_initialized();
    }
}

pub fn init_test<WIDGET, MSG: Clone + DisplayVariant + Send + 'static>() -> Result<(Component<WIDGET::Model, MSG, WIDGET::Container>, WIDGET), Error>
    where WIDGET: Widget<MSG> + Clone + 'static,
          WIDGET::Model: Send,
{
    init_gtk();

    let remote = Core::run();
    let (component, widgets) = create_widget_test::<WIDGET, MSG>(&remote);
    init_component::<WIDGET, MSG>(&component, &remote);
    Ok((component, widgets))
}

fn init<WIDGET, MSG: Clone + DisplayVariant + Send + 'static>() -> Result<Component<WIDGET::Model, MSG, WIDGET::Container>, Error>
    where WIDGET: Widget<MSG> + 'static,
          WIDGET::Model: Send,
    {
    gtk::init()?;

    let remote = Core::run();
    let component = create_widget::<WIDGET, MSG>(&remote);
    init_component::<WIDGET, MSG>(&component, &remote);
    Ok(component)
}

fn init_component<WIDGET, MSG>(component: &Component<WIDGET::Model, MSG, WIDGET::Container>, remote: &Remote)
    where WIDGET: Widget<MSG> + 'static,
          WIDGET::Model: Send,
          MSG: Clone + DisplayVariant + Send + 'static,
{
    let stream = component.stream.clone();
    let model = component.model.clone();
    remote.spawn(move |handle| {
        let relm = Relm {
            handle: handle.clone(),
            stream: stream.clone(),
        };
        WIDGET::subscriptions(&relm);
        let event_future = stream.for_each(move |event| {
            let mut model = model.lock().unwrap();
            WIDGET::update_command(&relm, event, &mut *model);
            Ok(())
        });
        handle.spawn(event_future);
        Ok(())
    });
}

fn update_widget<MSG, WIDGET>(widget: &mut WIDGET, event: MSG, model: &mut WIDGET::Model)
    where MSG: Clone + DisplayVariant,
          WIDGET: Widget<MSG>,
{
    if cfg!(debug_assertions) {
        let time = SystemTime::now();
        let debug = event.display_variant();
        let debug =
            if debug.len() > 100 {
                format!("{}…", &debug[..100])
            }
            else {
                debug.to_string()
            };
        widget.update(event, model);
        if let Ok(duration) = time.elapsed() {
            let ms = duration.subsec_nanos() as u64 / 1_000_000 + duration.as_secs() * 1000;
            if ms >= 200 {
                warn!("The update function was slow to execute for message {}: {}ms", debug, ms);
            }
        }
    }
    else {
        widget.update(event, model)
    }
}

pub trait ContainerWidget
    where Self: ContainerExt
{
    /**
     * Add a widget `WIDGET` to the current widget.
     *
     * # Note
     *
     * The returned `Component` must be stored in a `Widget`. If it is not stored, a communication
     * receiver will be droped which will cause events to be ignored for this widget.
     */
    fn add_widget<WIDGET, MSG, WIDGETMSG>(&self, relm: &RemoteRelm<MSG>) -> Component<WIDGET::Model, WIDGETMSG, WIDGET::Container>
        where MSG: Clone + DisplayVariant + Send + 'static,
              WIDGET: Widget<WIDGETMSG> + 'static,
              WIDGET::Container: IsA<Object> + WidgetExt,
              WIDGET::Model: Send,
              WIDGETMSG: Clone + DisplayVariant + Send + 'static,
    {
        let component = create_widget::<WIDGET, WIDGETMSG>(&relm.remote);
        self.add(&component.widget);
        component.widget.show_all();
        init_component::<WIDGET, WIDGETMSG>(&component, &relm.remote);
        component
    }

    fn remove_widget<MODEL, MSG: Clone + DisplayVariant + 'static, WIDGET>(&self, component: Component<MODEL, MSG, WIDGET>)
        where WIDGET: IsA<gtk::Widget>,
    {
        self.remove(&component.widget);
    }
}

impl<W: ContainerExt> ContainerWidget for W { }

pub trait DisplayVariant {
    fn display_variant(&self) -> &'static str;
}
<commit_msg>Start documentation<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

// Asynchronous GUI library based on GTK+ and futures/tokio.
//
// This library provides a `Widget` trait that you can use to create asynchronous GUI components.

/*
 * TODO: the widget names should start with __relm_field_.
 *
 * TODO: for the #[widget] attribute allow pattern matching by creating a function update(&mut
 * self, Quit: Msg, model: &mut Model) so that we can separate the update function in multiple
 * functions.
 *
 * TODO: reset widget name counters when creating new widget?
 *
 * TODO: refactor the code.
 *
 * TODO: chat client/server example.
 *
 * TODO: err if trying to use the SimpleMsg custom derive on stable.
 *
 * TODO: add Cargo travis/appveyor badges.
 *
 * TODO: add default type of () for Model in Widget when it is stable.
 * TODO: optionnaly multi-threaded.
 * TODO: convert GTK+ callback to Stream (does not seem worth it, nor convenient since it will
 * still need to use USFC for the callback method).
 *
 * These probably won't be needed anymore when switching to futures-glib (single-threaded model).
 * TODO: use weak pointers to avoid leaking.
 * TODO: try to avoid having two update() functions by adding the futures to a struct that's
 * returned from the update() function and these futures will then be added to the tokio loop (that
 * probably requires boxing the futures, which we want to avoid).
 * TODO: should have a free function to delete the stream in connect_recv.
 * TODO: automatically create the update_command() function from the events present in the view (or by splitting the update() fucntion).
 * TODO: try tk-easyloop in another branch.
 */

#![feature(conservative_impl_trait)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces, unused_qualifications, unused_results)]

extern crate futures;
extern crate glib;
extern crate glib_itc;
extern crate gobject_sys;
extern crate gtk;
extern crate gtk_sys;
#[macro_use]
extern crate log;
extern crate relm_core;

pub mod gtk_ext;
mod macros;
mod stream;
mod widget;

use std::error;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::sync::{Arc, Mutex};
use std::time::SystemTime;

use futures::{Future, Stream};
use glib::Continue;
pub use glib::object::Downcast;
pub use glib::translate::{FromGlibPtrNone, ToGlib};
use glib_itc::{Receiver, channel};
pub use gobject_sys::{GObject, g_object_new};
use gtk::{ContainerExt, IsA, Object, WidgetExt};
use relm_core::Core;
pub use relm_core::{EventStream, Handle, Remote};

pub use self::Error::*;
use self::stream::ToStream;
pub use self::widget::*;

#[must_use]
#[derive(Clone)]
pub struct Component<MODEL, MSG: Clone + DisplayVariant, WIDGET> {
    model: Arc<Mutex<MODEL>>,
    _receiver: Arc<Receiver>,
    stream: EventStream<MSG>,
    widget: WIDGET,
}

impl<MODEL, MSG: Clone + DisplayVariant, WIDGET> Component<MODEL, MSG, WIDGET> {
    pub fn stream(&self) -> &EventStream<MSG> {
        &self.stream
    }
}

impl<MODEL, MSG: Clone + DisplayVariant, WIDGET> Drop for Component<MODEL, MSG, WIDGET> {
    fn drop(&mut self) {
        self.stream.close().ok();
    }
}

#[derive(Debug)]
pub enum Error {
    GtkInit,
    Io(io::Error),
}

impl Display for Error {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        match *self {
            GtkInit => write!(formatter, "Cannot init GTK+"),
            Io(ref error) => write!(formatter, "IO error: {}", error),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            GtkInit => "Cannot init GTK+",
            Io(ref error) => error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            GtkInit => None,
            Io(ref error) => Some(error),
        }
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Io(error)
    }
}

impl From<()> for Error {
    fn from((): ()) -> Error {
        GtkInit
    }
}

pub struct Relm<MSG: Clone + DisplayVariant> {
    handle: Handle,
    stream: EventStream<MSG>,
}

impl<MSG: Clone + DisplayVariant + Send + 'static> Relm<MSG> {
    pub fn connect<CALLBACK, FAILCALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, success_callback: CALLBACK, failure_callback: FAILCALLBACK) -> impl Future<Item=(), Error=()>
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              FAILCALLBACK: Fn(STREAM::Error) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        let event_stream = self.stream.clone();
        let fail_event_stream = self.stream.clone();
        let stream = to_stream.to_stream();
        stream.map_err(move |error| {
            fail_event_stream.emit(failure_callback(error));
            ()
        })
            .for_each(move |result| {
                event_stream.emit(success_callback(result));
                Ok::<(), STREAM::Error>(())
            }
            .map_err(|_| ()))
    }

    pub fn connect_ignore_err<CALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, success_callback: CALLBACK) -> impl Future<Item=(), Error=()>
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        let event_stream = self.stream.clone();
        let stream = to_stream.to_stream();
        stream.map_err(|_| ())
            .for_each(move |result| {
                event_stream.emit(success_callback(result));
                Ok::<(), STREAM::Error>(())
            }
            .map_err(|_| ()))
    }

    pub fn connect_exec<CALLBACK, FAILCALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, callback: CALLBACK, failure_callback: FAILCALLBACK)
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              FAILCALLBACK: Fn(STREAM::Error) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        self.exec(self.connect(to_stream, callback, failure_callback));
    }

    pub fn connect_exec_ignore_err<CALLBACK, STREAM, TOSTREAM>(&self, to_stream: TOSTREAM, callback: CALLBACK)
        where CALLBACK: Fn(STREAM::Item) -> MSG + 'static,
              STREAM: Stream + 'static,
              TOSTREAM: ToStream<STREAM, Item=STREAM::Item, Error=STREAM::Error> + 'static,
    {
        self.exec(self.connect_ignore_err(to_stream, callback));
    }

    pub fn exec<FUTURE: Future<Item=(), Error=()> + 'static>(&self, future: FUTURE) {
        self.handle.spawn(future);
    }

    pub fn handle(&self) -> &Handle {
        &self.handle
    }

    pub fn run<WIDGET>() -> Result<(), Error>
        where WIDGET: Widget<MSG> + 'static,
              WIDGET::Model: Send,
    {
        let _component = init::<WIDGET, MSG>()?;
        gtk::main();
        Ok(())
    }

    pub fn stream(&self) -> &EventStream<MSG> {
        &self.stream
    }
}

pub struct RemoteRelm<MSG: Clone + DisplayVariant> {
    remote: Remote,
    stream: EventStream<MSG>,
}

impl<'a, MSG: Clone + DisplayVariant> RemoteRelm<MSG> {
    pub fn stream(&self) -> &EventStream<MSG> {
        &self.stream
    }
}

fn create_widget_test<WIDGET, MSG>(remote: &Remote) -> (Component<WIDGET::Model, MSG, WIDGET::Container>, WIDGET)
    where WIDGET: Widget<MSG> + Clone + 'static,
          MSG: Clone + DisplayVariant + 'static,
{
    let (sender, mut receiver) = channel();
    let stream = EventStream::new(Arc::new(sender));

    let (widget, model) = {
        let relm = RemoteRelm {
            remote: remote.clone(),
            stream: stream.clone(),
        };
        let model = WIDGET::model();
        (WIDGET::view(relm, &model), model)
    };

    let container = widget.container().clone();
    let model = Arc::new(Mutex::new(model));

    {
        let mut widget = widget.clone();
        let stream = stream.clone();
        let model = model.clone();
        receiver.connect_recv(move || {
            if let Some(event) = stream.pop_ui_events() {
                let mut model = model.lock().unwrap();
                update_widget(&mut widget, event, &mut *model);
            }
            Continue(true)
        });
    }

    let component = Component {
        model: model,
        _receiver: Arc::new(receiver),
        stream: stream,
        widget: container,
    };

    (component, widget)
}

fn create_widget<WIDGET, MSG>(remote: &Remote) -> Component<WIDGET::Model, MSG, WIDGET::Container>
    where WIDGET: Widget<MSG> + 'static,
          MSG: Clone + DisplayVariant + 'static,
{
    let (sender, mut receiver) = channel();
    let stream = EventStream::new(Arc::new(sender));

    let (mut widget, model) = {
        let relm = RemoteRelm {
            remote: remote.clone(),
            stream: stream.clone(),
        };
        let model = WIDGET::model();
        (WIDGET::view(relm, &model), model)
    };

    let container = widget.container().clone();
    let model = Arc::new(Mutex::new(model));

    {
        let stream = stream.clone();
        let model = model.clone();
        receiver.connect_recv(move || {
            if let Some(event) = stream.pop_ui_events() {
                let mut model = model.lock().unwrap();
                update_widget(&mut widget, event, &mut *model);
            }
            Continue(true)
        });
    }

    Component {
        model: model,
        _receiver: Arc::new(receiver),
        stream: stream,
        widget: container,
    }
}

// TODO: remove this workaround.
fn init_gtk() {
    let mut argc = 0;
    unsafe {
        gtk_sys::gtk_init(&mut argc, std::ptr::null_mut());
        gtk::set_initialized();
    }
}

pub fn init_test<WIDGET, MSG: Clone + DisplayVariant + Send + 'static>() -> Result<(Component<WIDGET::Model, MSG, WIDGET::Container>, WIDGET), Error>
    where WIDGET: Widget<MSG> + Clone + 'static,
          WIDGET::Model: Send,
{
    init_gtk();

    let remote = Core::run();
    let (component, widgets) = create_widget_test::<WIDGET, MSG>(&remote);
    init_component::<WIDGET, MSG>(&component, &remote);
    Ok((component, widgets))
}

fn init<WIDGET, MSG: Clone + DisplayVariant + Send + 'static>() -> Result<Component<WIDGET::Model, MSG, WIDGET::Container>, Error>
    where WIDGET: Widget<MSG> + 'static,
          WIDGET::Model: Send,
    {
    gtk::init()?;

    let remote = Core::run();
    let component = create_widget::<WIDGET, MSG>(&remote);
    init_component::<WIDGET, MSG>(&component, &remote);
    Ok(component)
}

fn init_component<WIDGET, MSG>(component: &Component<WIDGET::Model, MSG, WIDGET::Container>, remote: &Remote)
    where WIDGET: Widget<MSG> + 'static,
          WIDGET::Model: Send,
          MSG: Clone + DisplayVariant + Send + 'static,
{
    let stream = component.stream.clone();
    let model = component.model.clone();
    remote.spawn(move |handle| {
        let relm = Relm {
            handle: handle.clone(),
            stream: stream.clone(),
        };
        WIDGET::subscriptions(&relm);
        let event_future = stream.for_each(move |event| {
            let mut model = model.lock().unwrap();
            WIDGET::update_command(&relm, event, &mut *model);
            Ok(())
        });
        handle.spawn(event_future);
        Ok(())
    });
}

fn update_widget<MSG, WIDGET>(widget: &mut WIDGET, event: MSG, model: &mut WIDGET::Model)
    where MSG: Clone + DisplayVariant,
          WIDGET: Widget<MSG>,
{
    if cfg!(debug_assertions) {
        let time = SystemTime::now();
        let debug = event.display_variant();
        let debug =
            if debug.len() > 100 {
                format!("{}…", &debug[..100])
            }
            else {
                debug.to_string()
            };
        widget.update(event, model);
        if let Ok(duration) = time.elapsed() {
            let ms = duration.subsec_nanos() as u64 / 1_000_000 + duration.as_secs() * 1000;
            if ms >= 200 {
                warn!("The update function was slow to execute for message {}: {}ms", debug, ms);
            }
        }
    }
    else {
        widget.update(event, model)
    }
}

pub trait ContainerWidget
    where Self: ContainerExt
{
    /**
     * Add a widget `WIDGET` to the current widget.
     *
     * # Note
     *
     * The returned `Component` must be stored in a `Widget`. If it is not stored, a communication
     * receiver will be droped which will cause events to be ignored for this widget.
     */
    fn add_widget<WIDGET, MSG, WIDGETMSG>(&self, relm: &RemoteRelm<MSG>) -> Component<WIDGET::Model, WIDGETMSG, WIDGET::Container>
        where MSG: Clone + DisplayVariant + Send + 'static,
              WIDGET: Widget<WIDGETMSG> + 'static,
              WIDGET::Container: IsA<Object> + WidgetExt,
              WIDGET::Model: Send,
              WIDGETMSG: Clone + DisplayVariant + Send + 'static,
    {
        let component = create_widget::<WIDGET, WIDGETMSG>(&relm.remote);
        self.add(&component.widget);
        component.widget.show_all();
        init_component::<WIDGET, WIDGETMSG>(&component, &relm.remote);
        component
    }

    fn remove_widget<MODEL, MSG: Clone + DisplayVariant + 'static, WIDGET>(&self, component: Component<MODEL, MSG, WIDGET>)
        where WIDGET: IsA<gtk::Widget>,
    {
        self.remove(&component.widget);
    }
}

impl<W: ContainerExt> ContainerWidget for W { }

pub trait DisplayVariant {
    fn display_variant(&self) -> &'static str;
}
<|endoftext|>


<commit_before>//! Rust bindings for [libpcuid](https://github.com/anrieff/libcpuid)
//! CPU detection and feature extraction library.
//!
//! `rust-cpuid` provides a high-level interface for getting information
//! about the features of the CPU that runs your code. All the essential
//! work is done by the `libcpuid` C library and exposed through Rust's
//! FFI mechanism as a simple and convenient API.
//!
//! # Available features
//!
//! * CPU vendor, brand and codename detection
//! * information about number of cores (both physical and logical)
//! * cache size
//! * clock frequency
//!
//! # Installation
//!
//! First - download, and build libcpuid as [described in the readme](https://github.com/anrieff/libcpuid). Install it by running `make install` (you may want to run `ldconfig` afterwards).
//!
//! Add to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! cpuid = "*"
//! ```
//!
//! # Example
//!
//! ```rust
//! extern crate cpuid;
//!
//! fn main () {
//!     match cpuid::identify() {
//!         Ok(info) => {
//!             println!("Found: {} CPU, model: {}", info.vendor, info.codename);
//!             println!("The full brand string is: {}", info.brand);
//!             println!("Hardware AES support: {}", if info.has_feature(cpuid::CpuFeature::AES) { "yes" } else { "no" });
//!         },
//!         Err(err) => println!("cpuid error: {}", err),
//!     };
//!     match cpuid::clock_frequency() {
//!         Some(frequency) => println!("CPU speed: {} MHz", frequency),
//!         None => println!("Couldn't get CPU speed."),
//!     };
//! }
//! ```

#![feature(libc)]

extern crate libc;

use std::ffi::CStr;
use std::mem;
use std::str;

mod ffi;

/// A struct holding information about CPU features.
///
/// This data structure is returned by `identify()`. You can consult
/// [libcpuid docs for cpu_id_t](http://libcpuid.sourceforge.net/doxy/structcpu__id__t.html)
/// for more detailed descriptions of these fields.
pub struct CpuInfo {
    /// CPU vendor string, for example *GenuineIntel*.
    pub vendor: String,
    /// Brand string, for example *Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz*.
    pub brand: String,
    /// Brief CPU codename, such as *Sandy Bridge (Core i5)*.
    pub codename: String,
    /// Number of physical cores of the current CPU.
    pub num_cores: i32,
    /// Number of logical processors (may include HyperThreading or such).
    pub num_logical_cpus: i32,
    /// Total number of logical processors.
    pub total_logical_cpus: i32,
    /// L1 data cache size in kB. `Some(0)` if the CPU lacks cache, `None` if it couldn't be determined.
    pub l1_data_cache: Option<i32>,
    /// L1 instruction cache size in kB. `Some(0)` if the CPU lacks cache, `None` if it couldn't be determined.
    pub l1_instruction_cache: Option<i32>,
    /// L2 cache size in kB. `Some(0)` if the CPU lacks L2 cache, `None` if it couldn't be determined.
    pub l2_cache: Option<i32>,
    /// L3 cache size in kB. `Some(0)` if the CPU lacks L3 cache, `None` if it couldn't be determined.
    pub l3_cache: Option<i32>,
    flags: [u8; ffi::CPU_FLAGS_MAX],
}

/// CPU feature identifiers.
#[derive(Copy)]
pub enum CpuFeature {
    FloatingPointUnit = 0,
    VirtualModeExtension,
    DebugingExtension,
    PageSizeExtension,
    TimestampCounter,
    ModelSpecificRegisters,
    PhysicalAddressExtension,
    MachineCheckException,
    CMPXCHG8B,
    APIC,
    MemoryTypeRangeRegisters,
    SysenterSysexit,
    PageGlobalEnable,
    MachineCheckArchitecture,
    CMOV,
    PageAttributeTable,
    PageAddressExtension36bit,
    ProcessorSerialNumber,
    CLFLUSH,
    DebugStore,
    ACPI,
    MMX,
    FXSAVE,
    SSE,
    SSE2,
    SelfSnoop,
    HyperThreading,
    ThermalMonitor,
    IA64,
    PendingBreakEnable,
    SSE3,
    PCLMULQDQ,
    DebugStore64,
    MONITOR,
    CplQualifiedDebugStore,
    VirtualisationTechnology,
    SaferModeExceptions,
    EnhancedSpeedStep,
    ThermalMonitor2,
    SSSE3,
    ContextId,
    CMPXCHG16B,
    SendTaskPriorityMessages,
    PerformanceCapabilitiesMSR,
    DirectCacheAccess,
    SSE41,
    SSE42,
    SyscallSysret,
    ExecuteDisableBit,
    MOVBE,
    POPCNT,
    AES,
    XSAVE,
    OSXSAVE,
    AdvancedVectorExtensions,
    MMXExtensions,
    AMD3DNow,
    AMD3DNowExtended,
    NoExecuteBit,
    FXSAVEOptimizations,
    RDTSCP,
    LongMode,
    LAHFLongMode,
    CoreMultiProcessingLegacyMode,
    AMDSecureVirtualMachine,
    LZCNT,
    MisalignedSSE,
    SSE4a,
    PREFETCH,
    OsVisibleWorkaround,
    InstructionBasedSampling,
    SSE5,
    SKINIT,
    WatchdogTimer,
    TemperatureSensor,
    FrequencyIDControl,
    VoltageIDControl,
    THERMTRIP,
    AMDThermalControl,
    SoftwareThermalControl,
    Multiplier100Mhz,
    HardwarePstateControl,
    ConstantTSCTicks,
    XOP,
    FMA3,
    FMA4,
    TrailingBitManipulation,
    FPConvert16Bit,
    RDRAND,
    X2APIC,
    CorePerformanceBoost,
    MPERF,
    ProcessorFeedbackInterface,
    ProcessorAccumulator,
    NumCpuFeatures,
}

impl CpuInfo {
    /// Checks if current CPU supports given feature.
    ///
    /// See `CpuFeature` for a list of available feature identifiers.
    pub fn has_feature(&self, feature: CpuFeature) -> bool {
        return self.flags[feature as usize] == 1u8
    }
}

/// Checks if the CPUID instruction is present.
pub fn is_present() -> bool {
    unsafe {
        ffi::cpuid_present() == 1
    }
}

/// Returns libcpuid version string.
pub fn version() -> String {
    unsafe {
        let ptr = ffi::cpuid_lib_version();
        let bytes = CStr::from_ptr(ptr).to_bytes();
        str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
    }
}

/// Returns last libcpuid error string.
pub fn error() -> String {
    unsafe {
        let ptr = ffi::cpuid_error();
        let bytes = CStr::from_ptr(ptr).to_bytes();
        str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
    }
}

/// Tries to identify the current CPU and its features.
///
/// In case of successful detection, a `CpuInfo` struct is returned (wrapped
/// with `Ok`) which contains all available data about the processor.
/// If libcpuid encounters an error, `identify` returns an `Err` with
/// the error message inside.
pub fn identify() -> Result<CpuInfo, String> {
    let mut raw: ffi::cpu_raw_data_t = unsafe { mem::uninitialized() };
    let raw_result = unsafe {
        ffi::cpuid_get_raw_data(&mut raw)
    };
    if raw_result != 0 {
        return Err(error());
    }
    let mut data: ffi::cpu_id_t = unsafe { mem::uninitialized() };
    let identify_result = unsafe {
        ffi::cpu_identify(&mut raw, &mut data)
    };
    if identify_result != 0 {
        Err(error())
    } else {
        Ok(CpuInfo {
            vendor: String::from_utf8(data.vendor_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid vendor string"),
            brand: String::from_utf8(data.brand_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid brand string"),
            codename: String::from_utf8(data.cpu_codename.iter().map(|&x| x as u8).collect()).ok().expect("Invalid codename string"),
            num_cores: data.num_cores,
            num_logical_cpus: data.num_logical_cpus,
            total_logical_cpus: data.total_logical_cpus,
            l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache) } else { None },
            l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache) } else { None },
            l2_cache: if data.l2_cache != -1 { Some(data.l2_cache) } else { None },
            l3_cache: if data.l3_cache != -1 { Some(data.l3_cache) } else { None },
            flags: data.flags,
        })
    }
}

/// Gets the CPU clock frequency in MHz.
///
/// The underlying implementation uses several methods to discover CPU
/// speed, including direct measurement. If all these methods fail, function
/// returns `None`.
pub fn clock_frequency() -> Option<i32> {
    let frequency = unsafe {
        ffi::cpu_clock()
    };
    if frequency != -1 {
        Some(frequency)
    } else {
        None
    }
}

#[test]
fn test_is_present() {
    assert!(is_present());
}
<commit_msg>Derive Clone too.<commit_after>//! Rust bindings for [libpcuid](https://github.com/anrieff/libcpuid)
//! CPU detection and feature extraction library.
//!
//! `rust-cpuid` provides a high-level interface for getting information
//! about the features of the CPU that runs your code. All the essential
//! work is done by the `libcpuid` C library and exposed through Rust's
//! FFI mechanism as a simple and convenient API.
//!
//! # Available features
//!
//! * CPU vendor, brand and codename detection
//! * information about number of cores (both physical and logical)
//! * cache size
//! * clock frequency
//!
//! # Installation
//!
//! First - download, and build libcpuid as [described in the readme](https://github.com/anrieff/libcpuid). Install it by running `make install` (you may want to run `ldconfig` afterwards).
//!
//! Add to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! cpuid = "*"
//! ```
//!
//! # Example
//!
//! ```rust
//! extern crate cpuid;
//!
//! fn main () {
//!     match cpuid::identify() {
//!         Ok(info) => {
//!             println!("Found: {} CPU, model: {}", info.vendor, info.codename);
//!             println!("The full brand string is: {}", info.brand);
//!             println!("Hardware AES support: {}", if info.has_feature(cpuid::CpuFeature::AES) { "yes" } else { "no" });
//!         },
//!         Err(err) => println!("cpuid error: {}", err),
//!     };
//!     match cpuid::clock_frequency() {
//!         Some(frequency) => println!("CPU speed: {} MHz", frequency),
//!         None => println!("Couldn't get CPU speed."),
//!     };
//! }
//! ```

#![feature(libc)]

extern crate libc;

use std::ffi::CStr;
use std::mem;
use std::str;

mod ffi;

/// A struct holding information about CPU features.
///
/// This data structure is returned by `identify()`. You can consult
/// [libcpuid docs for cpu_id_t](http://libcpuid.sourceforge.net/doxy/structcpu__id__t.html)
/// for more detailed descriptions of these fields.
pub struct CpuInfo {
    /// CPU vendor string, for example *GenuineIntel*.
    pub vendor: String,
    /// Brand string, for example *Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz*.
    pub brand: String,
    /// Brief CPU codename, such as *Sandy Bridge (Core i5)*.
    pub codename: String,
    /// Number of physical cores of the current CPU.
    pub num_cores: i32,
    /// Number of logical processors (may include HyperThreading or such).
    pub num_logical_cpus: i32,
    /// Total number of logical processors.
    pub total_logical_cpus: i32,
    /// L1 data cache size in kB. `Some(0)` if the CPU lacks cache, `None` if it couldn't be determined.
    pub l1_data_cache: Option<i32>,
    /// L1 instruction cache size in kB. `Some(0)` if the CPU lacks cache, `None` if it couldn't be determined.
    pub l1_instruction_cache: Option<i32>,
    /// L2 cache size in kB. `Some(0)` if the CPU lacks L2 cache, `None` if it couldn't be determined.
    pub l2_cache: Option<i32>,
    /// L3 cache size in kB. `Some(0)` if the CPU lacks L3 cache, `None` if it couldn't be determined.
    pub l3_cache: Option<i32>,
    flags: [u8; ffi::CPU_FLAGS_MAX],
}

/// CPU feature identifiers.
#[derive(Clone, Copy)]
pub enum CpuFeature {
    FloatingPointUnit = 0,
    VirtualModeExtension,
    DebugingExtension,
    PageSizeExtension,
    TimestampCounter,
    ModelSpecificRegisters,
    PhysicalAddressExtension,
    MachineCheckException,
    CMPXCHG8B,
    APIC,
    MemoryTypeRangeRegisters,
    SysenterSysexit,
    PageGlobalEnable,
    MachineCheckArchitecture,
    CMOV,
    PageAttributeTable,
    PageAddressExtension36bit,
    ProcessorSerialNumber,
    CLFLUSH,
    DebugStore,
    ACPI,
    MMX,
    FXSAVE,
    SSE,
    SSE2,
    SelfSnoop,
    HyperThreading,
    ThermalMonitor,
    IA64,
    PendingBreakEnable,
    SSE3,
    PCLMULQDQ,
    DebugStore64,
    MONITOR,
    CplQualifiedDebugStore,
    VirtualisationTechnology,
    SaferModeExceptions,
    EnhancedSpeedStep,
    ThermalMonitor2,
    SSSE3,
    ContextId,
    CMPXCHG16B,
    SendTaskPriorityMessages,
    PerformanceCapabilitiesMSR,
    DirectCacheAccess,
    SSE41,
    SSE42,
    SyscallSysret,
    ExecuteDisableBit,
    MOVBE,
    POPCNT,
    AES,
    XSAVE,
    OSXSAVE,
    AdvancedVectorExtensions,
    MMXExtensions,
    AMD3DNow,
    AMD3DNowExtended,
    NoExecuteBit,
    FXSAVEOptimizations,
    RDTSCP,
    LongMode,
    LAHFLongMode,
    CoreMultiProcessingLegacyMode,
    AMDSecureVirtualMachine,
    LZCNT,
    MisalignedSSE,
    SSE4a,
    PREFETCH,
    OsVisibleWorkaround,
    InstructionBasedSampling,
    SSE5,
    SKINIT,
    WatchdogTimer,
    TemperatureSensor,
    FrequencyIDControl,
    VoltageIDControl,
    THERMTRIP,
    AMDThermalControl,
    SoftwareThermalControl,
    Multiplier100Mhz,
    HardwarePstateControl,
    ConstantTSCTicks,
    XOP,
    FMA3,
    FMA4,
    TrailingBitManipulation,
    FPConvert16Bit,
    RDRAND,
    X2APIC,
    CorePerformanceBoost,
    MPERF,
    ProcessorFeedbackInterface,
    ProcessorAccumulator,
    NumCpuFeatures,
}

impl CpuInfo {
    /// Checks if current CPU supports given feature.
    ///
    /// See `CpuFeature` for a list of available feature identifiers.
    pub fn has_feature(&self, feature: CpuFeature) -> bool {
        return self.flags[feature as usize] == 1u8
    }
}

/// Checks if the CPUID instruction is present.
pub fn is_present() -> bool {
    unsafe {
        ffi::cpuid_present() == 1
    }
}

/// Returns libcpuid version string.
pub fn version() -> String {
    unsafe {
        let ptr = ffi::cpuid_lib_version();
        let bytes = CStr::from_ptr(ptr).to_bytes();
        str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
    }
}

/// Returns last libcpuid error string.
pub fn error() -> String {
    unsafe {
        let ptr = ffi::cpuid_error();
        let bytes = CStr::from_ptr(ptr).to_bytes();
        str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
    }
}

/// Tries to identify the current CPU and its features.
///
/// In case of successful detection, a `CpuInfo` struct is returned (wrapped
/// with `Ok`) which contains all available data about the processor.
/// If libcpuid encounters an error, `identify` returns an `Err` with
/// the error message inside.
pub fn identify() -> Result<CpuInfo, String> {
    let mut raw: ffi::cpu_raw_data_t = unsafe { mem::uninitialized() };
    let raw_result = unsafe {
        ffi::cpuid_get_raw_data(&mut raw)
    };
    if raw_result != 0 {
        return Err(error());
    }
    let mut data: ffi::cpu_id_t = unsafe { mem::uninitialized() };
    let identify_result = unsafe {
        ffi::cpu_identify(&mut raw, &mut data)
    };
    if identify_result != 0 {
        Err(error())
    } else {
        Ok(CpuInfo {
            vendor: String::from_utf8(data.vendor_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid vendor string"),
            brand: String::from_utf8(data.brand_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid brand string"),
            codename: String::from_utf8(data.cpu_codename.iter().map(|&x| x as u8).collect()).ok().expect("Invalid codename string"),
            num_cores: data.num_cores,
            num_logical_cpus: data.num_logical_cpus,
            total_logical_cpus: data.total_logical_cpus,
            l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache) } else { None },
            l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache) } else { None },
            l2_cache: if data.l2_cache != -1 { Some(data.l2_cache) } else { None },
            l3_cache: if data.l3_cache != -1 { Some(data.l3_cache) } else { None },
            flags: data.flags,
        })
    }
}

/// Gets the CPU clock frequency in MHz.
///
/// The underlying implementation uses several methods to discover CPU
/// speed, including direct measurement. If all these methods fail, function
/// returns `None`.
pub fn clock_frequency() -> Option<i32> {
    let frequency = unsafe {
        ffi::cpu_clock()
    };
    if frequency != -1 {
        Some(frequency)
    } else {
        None
    }
}

#[test]
fn test_is_present() {
    assert!(is_present());
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;
use std::ops::{Drop, Deref, DerefMut};
use std::convert::{AsRef, AsMut};
use std::borrow::Borrow;

pub trait Recycleable {
  fn new() -> Self;
  fn reset(&mut self);
}

pub trait InitializeWith<T> {
  fn initialize_with(&mut self, source: T);
}

impl Recycleable for String {
  #[inline]
  fn new() -> String {
    String::new()
  }
  #[inline]
  fn reset(&mut self) {
    self.clear();
  }
}

impl <T> Recycleable for Vec<T> {
  #[inline]
  fn new() -> Vec<T> {
    Vec::new()
  }
  #[inline]
  fn reset(&mut self) {
    self.clear();
  }
}

impl <A> InitializeWith<A> for String where A : AsRef<str> {
  #[inline]
  fn initialize_with(&mut self, source: A) {
    let s : &str = source.as_ref();
    self.push_str(s);
  }
}

pub struct RcRecycled<T> where T: Recycleable {
  value: RecycledInner<Rc<RefCell<Vec<T>>>, T>
}

pub struct Recycled<'a, T: 'a> where T: Recycleable {
  value: RecycledInner<&'a RefCell<Vec<T>>, T>
}

macro_rules! impl_recycled {
  ($name: ident, $typ: ty, $pool: ty) => {
  impl <'a, T> AsRef<T> for $typ where T : Recycleable {
     fn as_ref(&self) -> &T {
      self.value.as_ref()
    }
  }

  impl <'a, T> AsMut<T> for $typ where T : Recycleable {
     fn as_mut(&mut self) -> &mut T {
      self.value.as_mut()
    }
  }

  impl <'a, T> fmt::Debug for $typ where T : fmt::Debug + Recycleable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      self.value.fmt(f)
    }
  }

  impl <'a, T> fmt::Display for $typ where T : fmt::Display + Recycleable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      self.value.fmt(f)
    }
  }

  impl <'a, T> Deref for $typ where T : Recycleable {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
      self.as_ref()
    }
  }

  impl <'a, T> DerefMut for $typ where T : Recycleable {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
      self.as_mut()
    }
  }

  impl <'a, T> $typ where T: Recycleable {
    pub fn new(pool: $pool, value: T) -> $typ {
      $name { value: RecycledInner::new(pool, value) }
    }

    #[inline]
    pub fn new_from<A>(pool: $pool, value: T, source: A) -> $typ where T : InitializeWith<A> {
      $name { value: RecycledInner::new_from(pool, value, source) }
    }

    #[inline]
    pub fn detach(self) -> T {
      self.value.detach()
    }
  }
}
}
impl_recycled!{ RcRecycled, RcRecycled<T>, Rc<RefCell<Vec<T>>> }
impl_recycled!{ Recycled, Recycled<'a, T>, &'a RefCell<Vec<T>> }

struct RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  value: Option<T>,
  pool: P
}

impl <P, T> Drop for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  #[inline]
  fn drop(&mut self) {
    if let Some(mut value) = self.value.take() {
      value.reset();
      self.pool.borrow().borrow_mut().push(value);
    }
  }
}

impl <P, T> AsRef<T> for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
   fn as_ref(&self) -> &T {
    match self.value.as_ref() {
      Some(v) => v,
      None => panic!("Recycled<T> smartpointer missing its value.")
    }
  }
}

impl <P, T> AsMut<T> for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
   fn as_mut(&mut self) -> &mut T {
    match self.value.as_mut() {
      Some(v) => v,
      None => panic!("Recycled<T> smartpointer missing its value.")
    }
  }
}

impl <P, T> fmt::Debug for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : fmt::Debug + Recycleable {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self.value {
      Some(ref s) => s.fmt(f),
      None => write!(f, "Empty Recycled<T>")
    }
  }
}

impl <P, T> fmt::Display for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : fmt::Display + Recycleable {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self.value {
      Some(ref s) => s.fmt(f),
      None => write!(f, "Empty Recycled<T>")
    }
  }
}

impl <P, T> Deref for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  type Target = T;
  #[inline]
  fn deref<'a>(&'a self) -> &'a T {
    self.as_ref()
  }
}

impl <P, T> DerefMut for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  #[inline]
  fn deref_mut<'a>(&'a mut self) -> &'a mut T {
    self.as_mut()
  }
}

impl <P, T> RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  #[inline]
  fn new(pool: P, value: T) -> RecycledInner<P, T> {
    RecycledInner {
      value: Some(value),
      pool: pool
    }
  }

  #[inline]
  fn new_from<A>(pool: P, mut value: T, source: A) -> RecycledInner<P, T> where T : InitializeWith<A> {
    value.initialize_with(source);
    RecycledInner {
      value: Some(value),
      pool: pool
    }
  }

  #[inline]
  fn detach(mut self) -> T {
    let value = self.value.take().unwrap();
    drop(self);
    value
  }
}

pub struct Pool <T> where T : Recycleable {
  values: Rc<RefCell<Vec<T>>>
}

impl <T> Pool <T>
  where T: Recycleable {

  #[inline]
  pub fn with_size(size: usize) -> Pool <T> {
    let values: Vec<T> =
      (0..size)
      .map(|_| T::new() )
      .collect();
    Pool {
      values: Rc::new(RefCell::new(values))
    }
  }

  #[inline]
  pub fn attach_rc(&self, value: T) -> RcRecycled<T> {
    let pool_reference = self.values.clone();
    RcRecycled { value: RecycledInner::new(pool_reference, value) }
  }

  #[inline]
  pub fn new_rc(&self) -> RcRecycled<T> {
    let t = self.detached();
    let pool_reference = self.values.clone();
    RcRecycled { value: RecycledInner::new(pool_reference, t) }
  }

  #[inline(always)]
  pub fn new_rc_from<A>(&self, source: A) -> RcRecycled<T> where T: InitializeWith<A> {
    let t = self.detached();
    let pool_reference = self.values.clone();
    RcRecycled { value: RecycledInner::new_from(pool_reference, t, source) }
  }

  #[inline]
  pub fn attach(&self, value: T) -> Recycled<T> {
    Recycled { value: RecycledInner::new(&*self.values, value) }
  }

  #[inline]
  pub fn new(&self) -> Recycled<T> {
    let t = self.detached();
    Recycled { value: RecycledInner::new(&*self.values, t) }
  }

  #[inline(always)]
  pub fn new_from<A>(&self, source: A) -> Recycled<T> where T: InitializeWith<A> {
    let t = self.detached();
    Recycled { value: RecycledInner::new_from(&*self.values, t, source) }
  }

  #[inline]
  pub fn detached(&self) -> T {
    match self.values.borrow_mut().pop() {
      Some(v) => v,
      None => T::new()
    }
  }

  #[inline]
  pub fn size(&self) -> usize {
    (*self.values).borrow().len()
  }
}

<commit_msg>Initial commit of rustdoc.<commit_after>#![allow(dead_code)]
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;
use std::ops::{Drop, Deref, DerefMut};
use std::convert::{AsRef, AsMut};
use std::borrow::Borrow;

/// In order to be managed by a `Pool`, values must be of a type that
/// implements the `Recycleable` trait. This allows the `Pool` to create
/// new instances as well as reset existing instances to a like-new state.
pub trait Recycleable {
  /// Allocates a new instance of the implementing type.
  fn new() -> Self;
  /// Sets the state of the modified instance to be that of a freshly
  /// allocated instance, thereby allowing it to be reused.
  fn reset(&mut self);
}

/// Informs how an already allocated value should be initialized
/// when provided with a model value or other meaningful input.
pub trait InitializeWith<T> {
  fn initialize_with(&mut self, source: T);
}

impl Recycleable for String {
  #[inline]
  fn new() -> String {
    String::new()
  }
  #[inline]
  fn reset(&mut self) {
    self.clear();
  }
}

impl <T> Recycleable for Vec<T> {
  #[inline]
  fn new() -> Vec<T> {
    Vec::new()
  }
  #[inline]
  fn reset(&mut self) {
    self.clear();
  }
}

impl <A> InitializeWith<A> for String where A : AsRef<str> {
  #[inline]
  fn initialize_with(&mut self, source: A) {
    let s : &str = source.as_ref();
    self.push_str(s);
  }
}

/// A smartpointer which uses reference counting (`Rc`) to know
/// when to move its wrapped value back to the `Pool` that
/// issued it.
pub struct RcRecycled<T> where T: Recycleable {
  value: RecycledInner<Rc<RefCell<Vec<T>>>, T>
}

/// A smartpointer which uses a shared reference (`&`) to know
/// when to move its wrapped value back to the `Pool` that
/// issued it.
pub struct Recycled<'a, T: 'a> where T: Recycleable {
  value: RecycledInner<&'a RefCell<Vec<T>>, T>
}

macro_rules! impl_recycled {
  ($name: ident, $typ: ty, $pool: ty) => {
  impl <'a, T> AsRef<T> for $typ where T : Recycleable {
     /// Gets a shared reference to the value wrapped by the smartpointer.
     fn as_ref(&self) -> &T {
      self.value.as_ref()
    }
  }

  impl <'a, T> AsMut<T> for $typ where T : Recycleable {
     /// Gets a mutable reference to the value wrapped by the smartpointer.
     fn as_mut(&mut self) -> &mut T {
      self.value.as_mut()
    }
  }

  impl <'a, T> fmt::Debug for $typ where T : fmt::Debug + Recycleable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      self.value.fmt(f)
    }
  }

  impl <'a, T> fmt::Display for $typ where T : fmt::Display + Recycleable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      self.value.fmt(f)
    }
  }

  impl <'a, T> Deref for $typ where T : Recycleable {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
      self.as_ref()
    }
  }

  impl <'a, T> DerefMut for $typ where T : Recycleable {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
      self.as_mut()
    }
  }

  impl <'a, T> $typ where T: Recycleable {
    fn new(pool: $pool, value: T) -> $typ {
      $name { value: RecycledInner::new(pool, value) }
    }

    #[inline]
    fn new_from<A>(pool: $pool, value: T, source: A) -> $typ where T : InitializeWith<A> {
      $name { value: RecycledInner::new_from(pool, value, source) }
    }

    #[inline]
    /// Disassociates the value from the `Pool` that issued it. This
    /// destroys the smartpointer and returns the previously wrapped value.
    pub fn detach(self) -> T {
      self.value.detach()
    }
  }
}
}
impl_recycled!{ RcRecycled, RcRecycled<T>, Rc<RefCell<Vec<T>>> }
impl_recycled!{ Recycled, Recycled<'a, T>, &'a RefCell<Vec<T>> }

struct RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  value: Option<T>,
  pool: P
}

impl <P, T> Drop for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  #[inline]
  fn drop(&mut self) {
    if let Some(mut value) = self.value.take() {
      value.reset();
      self.pool.borrow().borrow_mut().push(value);
    }
  }
}

impl <P, T> AsRef<T> for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
   fn as_ref(&self) -> &T {
    match self.value.as_ref() {
      Some(v) => v,
      None => panic!("Recycled<T> smartpointer missing its value.")
    }
  }
}

impl <P, T> AsMut<T> for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
   fn as_mut(&mut self) -> &mut T {
    match self.value.as_mut() {
      Some(v) => v,
      None => panic!("Recycled<T> smartpointer missing its value.")
    }
  }
}

impl <P, T> fmt::Debug for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : fmt::Debug + Recycleable {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self.value {
      Some(ref s) => s.fmt(f),
      None => write!(f, "Empty Recycled<T>")
    }
  }
}

impl <P, T> fmt::Display for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : fmt::Display + Recycleable {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self.value {
      Some(ref s) => s.fmt(f),
      None => write!(f, "Empty Recycled<T>")
    }
  }
}

impl <P, T> Deref for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  type Target = T;
  #[inline]
  fn deref<'a>(&'a self) -> &'a T {
    self.as_ref()
  }
}

impl <P, T> DerefMut for RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  #[inline]
  fn deref_mut<'a>(&'a mut self) -> &'a mut T {
    self.as_mut()
  }
}

impl <P, T> RecycledInner<P, T> where P: Borrow<RefCell<Vec<T>>>, T : Recycleable {
  #[inline]
  fn new(pool: P, value: T) -> RecycledInner<P, T> {
    RecycledInner {
      value: Some(value),
      pool: pool
    }
  }

  #[inline]
  fn new_from<A>(pool: P, mut value: T, source: A) -> RecycledInner<P, T> where T : InitializeWith<A> {
    value.initialize_with(source);
    RecycledInner {
      value: Some(value),
      pool: pool
    }
  }

  #[inline]
  fn detach(mut self) -> T {
    let value = self.value.take().unwrap();
    drop(self);
    value
  }
}

/// A collection of values that can be reused without requiring new allocations.
///
/// `Pool` issues each value wrapped in a smartpointer. When the smartpointer goes out of
/// scope, the wrapped value is automatically returned to the pool.
pub struct Pool <T> where T : Recycleable {
  values: Rc<RefCell<Vec<T>>>
}

impl <T> Pool <T> where T: Recycleable {

  /// Creates a pool with `size` elements of type `T` allocated.
  #[inline]
  pub fn with_size(size: usize) -> Pool <T> {
    let values: Vec<T> =
      (0..size)
      .map(|_| T::new() )
      .collect();
    Pool {
      values: Rc::new(RefCell::new(values))
    }
  }

  /// Returns the number of values remaining in the pool.
  #[inline]
  pub fn size(&self) -> usize {
    (*self.values).borrow().len()
  }

  /// Removes a value from the pool and returns it wrapped in
  /// a `Recycled smartpointer. If the pool is empty when the
  /// method is called, a new value will be allocated.
  #[inline]
  pub fn new(&self) -> Recycled<T> {
    let t = self.detached();
    Recycled { value: RecycledInner::new(&*self.values, t) }
  }

  /// Removes a value from the pool, initializes it using the provided
  /// source value, and returns it wrapped in a `Recycled` smartpointer.
  /// If the pool is empty when the method is called, a new value will be
  /// allocated.
  #[inline(always)]
  pub fn new_from<A>(&self, source: A) -> Recycled<T> where T: InitializeWith<A> {
    let t = self.detached();
    Recycled { value: RecycledInner::new_from(&*self.values, t, source) }
  }

  /// Associates the provided value with the pool by wrapping it in a
  /// `Recycled` smartpointer.
  #[inline]
  pub fn attach(&self, value: T) -> Recycled<T> {
    Recycled { value: RecycledInner::new(&*self.values, value) }
  }

  /// Removes a value from the pool and returns it without wrapping it in
  /// a smartpointer. When the value goes out of scope it will not be
  /// returned to the pool.
  #[inline]
  pub fn detached(&self) -> T {
    match self.values.borrow_mut().pop() {
      Some(v) => v,
      None => T::new()
    }
  }

  /// Removes a value from the pool and returns it wrapped in
  /// an `RcRecycled` smartpointer. If the pool is empty when the
  /// method is called, a new value will be allocated.
  #[inline]
  pub fn new_rc(&self) -> RcRecycled<T> {
    let t = self.detached();
    let pool_reference = self.values.clone();
    RcRecycled { value: RecycledInner::new(pool_reference, t) }
  }

  /// Removes a value from the pool, initializes it using the provided
  /// source value, and returns it wrapped in an `RcRecycled` smartpointer.
  /// If the pool is empty when the method is called, a new value will be
  /// allocated.
  #[inline(always)]
  pub fn new_rc_from<A>(&self, source: A) -> RcRecycled<T> where T: InitializeWith<A> {
    let t = self.detached();
    let pool_reference = self.values.clone();
    RcRecycled { value: RecycledInner::new_from(pool_reference, t, source) }
  }

  /// Associates the provided value with the pool by wrapping it in an
  /// `RcRecycled` smartpointer.
  #[inline]
  pub fn attach_rc(&self, value: T) -> RcRecycled<T> {
    let pool_reference = self.values.clone();
    RcRecycled { value: RecycledInner::new(pool_reference, value) }
  }
}
<|endoftext|>


<commit_before>#![allow(raw_pointer_derive)]

pub mod graph;
pub mod vertex;
pub mod edge;
pub mod traversal;

#[cfg(test)]
mod tests {
    use vertex::{Vertex, GraphProperty};
    use graph::Graph;
    #[test]
    fn test_unsafe_vertex() {
        let v = Vertex::new(1);

        let out_edges = &v.out_edges;
        let in_edges = &v.in_edges;
    }

    #[test]
    fn test_deref() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let vertex = &*v1;
        assert!(vertex.id == 1);
    }

    #[test]
    fn test_new_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();

        assert_eq!(v1.id, 1);

        unsafe {
            let vertex = &*v1;
            assert_eq!((*v1).id, 1);
        }

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let mut v2 = g.add_vertex();

        let e1 = v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);

        assert_eq!(v1.out_edges.len(), v2.in_edges.len());

        // ensure the vertex and edge pointers are correct

        assert_eq!(v1.v, e1.from_vertex);
        assert_eq!(e1.to_vertex, v2.v);

        //assert_eq!(v1.v, *(e1.edge).from_vertex);
    }

    #[test]
    fn test_properties() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let key = "jon".to_string();
        let value = GraphProperty::Int(1);
        v1.set_property(key.clone(), value);

        let result = v1.get_property(key).unwrap();

        match result {
            &GraphProperty::Int(1) =>
                // we're ok
                println!("OK"),
            _ =>
                panic!("wrong graph property")
        }
    }

    fn test_get_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let v = g.get(1).unwrap();
        assert_eq!(v.id, 1);
    }

    fn test_traversal_map() {

    }
}
<commit_msg>g.v() test<commit_after>#![allow(raw_pointer_derive)]

pub mod graph;
pub mod vertex;
pub mod edge;
pub mod traversal;

#[cfg(test)]
mod tests {
    use vertex::{Vertex, GraphProperty};
    use graph::Graph;
    #[test]
    fn test_unsafe_vertex() {
        let v = Vertex::new(1);

        let out_edges = &v.out_edges;
        let in_edges = &v.in_edges;
    }

    #[test]
    fn test_deref() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let vertex = &*v1;
        assert!(vertex.id == 1);
    }

    #[test]
    fn test_new_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();

        assert_eq!(v1.id, 1);

        unsafe {
            let vertex = &*v1;
            assert_eq!((*v1).id, 1);
        }

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let mut v2 = g.add_vertex();

        let e1 = v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);

        assert_eq!(v1.out_edges.len(), v2.in_edges.len());

        // ensure the vertex and edge pointers are correct

        assert_eq!(v1.v, e1.from_vertex);
        assert_eq!(e1.to_vertex, v2.v);

        //assert_eq!(v1.v, *(e1.edge).from_vertex);
    }

    #[test]
    fn test_properties() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let key = "jon".to_string();
        let value = GraphProperty::Int(1);
        v1.set_property(key.clone(), value);

        let result = v1.get_property(key).unwrap();

        match result {
            &GraphProperty::Int(1) =>
                // we're ok
                println!("OK"),
            _ =>
                panic!("wrong graph property")
        }
    }

    fn test_get_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let v = g.get(1).unwrap();
        assert_eq!(v.id, 1);
    }

    fn test_graph_query_off_vertex() {
        let mut g = Graph::new();
        let vertex = g.add_vertex();
        let query = g.v(1);
    }

    fn test_traversal_map() {

    }
}
<|endoftext|>


<commit_before>extern crate url;

trait Queryable {
    fn to_query(self) -> String;
}

mod util;
pub mod types;
pub mod command;
pub mod command_query;
pub mod dump;
pub mod select;
pub mod load;
pub mod status;
pub mod delete;
pub mod table_create;
<commit_msg>lib queryable: Mark as pub to make public traits<commit_after>extern crate url;

pub trait Queryable {
    fn to_query(self) -> String;
}

mod util;
pub mod types;
pub mod command;
pub mod command_query;
pub mod dump;
pub mod select;
pub mod load;
pub mod status;
pub mod delete;
pub mod table_create;
<|endoftext|>


<commit_before>pub type Num = f32;

/// Represents the state of a neuron.
#[derive(Copy, Clone)]
pub struct State {
    /// membrane potential of neuron (in mV)
    v: Num,

    /// recovery variable
    u: Num
}

impl State {
    pub fn new() -> State {
        State {
            v: -70.0,
            u: -14.0
        }
    }
    pub fn potential(&self) -> Num {
        self.v
    }
}

/// The neuron configuration parameters.
pub struct Config {

    /// Rate of recovery.
    a: Num,

    /// Sensitivity of recovery variable `u` to the membrane potential `v`.
    b: Num,

    /// After-spike reset value of membrane potential `v`.
    c: Num,

    /// After-spike reset of recovery variable `u`.
    d: Num
}

impl Config {
    /// Generates an excitatory neuron configuration according to Izhikevich's paper [reentry]
    /// where `r` is a random variable uniformly distributed in [0, 1].
    pub fn excitatory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        let r2 = r*r;
        Config {
            a: 0.02,
            b: 0.2,
            c: -65.0 + 15.0 * r2,
            d: 8.0 - 6.0 * r2
        }
    }

    pub fn inhibitory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        Config {
            a: 0.02 + 0.08 * r,
            b: 0.25 - 0.05 * r,
            c: -65.0,
            d: 2.0
        }
    }

    /// Regular spiking (RS) cell configuration.
    pub fn regular_spiking() -> Config {
        Config::excitatory(0.0)
    }

    /// Chattering (CH) cell configuration.
    pub fn chattering() -> Config {
        Config::excitatory(1.0)
    }
}

#[inline(always)]
fn dv(u: Num, v: Num, i_syn: Num) -> Num {
    0.04 * (v*v) + 5.0 * v + 140.0 - u - i_syn
}

#[inline(always)]
fn du(u: Num, v: Num, a: Num, b: Num) -> Num {
    a * (b*v - u)
}

impl State {
    /// Calculate the new state after `dt` ms.
    #[inline(always)]
    pub fn step(self, dt: Num, i_syn: Num, config: &Config) -> State {
        if self.v >= 30.0 {
            State {
                v: config.c,
                u: self.u + config.d
            }
        }
        else {
            State {
                v: self.v + dt*dv(self.u, self.v, i_syn),
                u: self.u + dt*du(self.u, self.v, config.a, config.b)
            }
        }
    }
}
<commit_msg>Comment<commit_after>/// We use this numerical type for all calculations.
pub type Num = f32;

/// Represents the state of a neuron.
#[derive(Copy, Clone)]
pub struct State {
    /// membrane potential of neuron (in mV)
    v: Num,

    /// recovery variable
    u: Num
}

impl State {
    pub fn new() -> State {
        State {
            v: -70.0,
            u: -14.0
        }
    }
    pub fn potential(&self) -> Num {
        self.v
    }
}

/// The neuron configuration parameters.
pub struct Config {
    /// Rate of recovery.
    a: Num,

    /// Sensitivity of recovery variable `u` to the membrane potential `v`.
    b: Num,

    /// After-spike reset value of membrane potential `v`.
    c: Num,

    /// After-spike reset of recovery variable `u`.
    d: Num
}

impl Config {
    /// Generates an excitatory neuron configuration according to Izhikevich's paper [reentry]
    /// where `r` is a random variable uniformly distributed in [0, 1].
    pub fn excitatory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        let r2 = r*r;
        Config {
            a: 0.02,
            b: 0.2,
            c: -65.0 + 15.0 * r2,
            d: 8.0 - 6.0 * r2
        }
    }

    pub fn inhibitory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        Config {
            a: 0.02 + 0.08 * r,
            b: 0.25 - 0.05 * r,
            c: -65.0,
            d: 2.0
        }
    }

    /// Regular spiking (RS) cell configuration.
    pub fn regular_spiking() -> Config {
        Config::excitatory(0.0)
    }

    /// Chattering (CH) cell configuration.
    pub fn chattering() -> Config {
        Config::excitatory(1.0)
    }
}

#[inline(always)]
fn dv(u: Num, v: Num, i_syn: Num) -> Num {
    0.04 * (v*v) + 5.0 * v + 140.0 - u - i_syn
}

#[inline(always)]
fn du(u: Num, v: Num, a: Num, b: Num) -> Num {
    a * (b*v - u)
}

impl State {
    /// Calculate the new state after `dt` ms.
    #[inline(always)]
    pub fn step(self, dt: Num, i_syn: Num, config: &Config) -> State {
        if self.v >= 30.0 {
            State {
                v: config.c,
                u: self.u + config.d
            }
        }
        else {
            State {
                v: self.v + dt*dv(self.u, self.v, i_syn),
                u: self.u + dt*du(self.u, self.v, config.a, config.b)
            }
        }
    }
}
<|endoftext|>