<commit_before>//! Event sources and callbacks.
//!
//! This is a light-weight implementation of the observer pattern. Subjects are
//! modelled as the `Source` type and observers as boxed closures.

use std::sync::{ RwLock, Weak };

/// An error that can occur with a weakly referenced callback.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum CallbackError {
    Disappeared,
    Poisoned,
}

/// Shorthand for common callback results.
pub type CallbackResult<T=()> = Result<T, CallbackError>;

/// A boxed callback.
type Callback<A> = Box<FnMut(A) -> CallbackResult + Send + Sync + 'static>;

/// Perform some callback on a weak reference to a mutex and handle errors
/// gracefully.
pub fn with_weak<T, U, F: FnOnce(&mut T) -> U>(weak: &Weak<RwLock<T>>, f: F) -> CallbackResult<U> {
    weak.upgrade()
        .ok_or(CallbackError::Disappeared)
        .and_then(|mutex| mutex.write()
            .map(|mut t| f(&mut t))
            .map_err(|_| CallbackError::Poisoned)
        )
}

/// An event source.
pub struct Source<A> {
    callbacks: Vec<Callback<A>>,
}

impl<A> Source<A> {
    /// Create a new source.
    pub fn new() -> Source<A> {
        Source { callbacks: vec![] }
    }

    /// Register a callback. The callback will be a mutable closure that takes
    /// an event and must return a result. To unsubscribe from further events,
    /// the callback has to return an error.
    pub fn register<F>(&mut self, callback: F)
        where F: FnMut(A) -> CallbackResult + Send + Sync + 'static
    {
        self.callbacks.push(Box::new(callback));
    }
}

impl<A: Send + Sync + Clone + 'static> Source<A> {
    /// Make the source send an event to all its observers.
    pub fn send(&mut self, a: A) {
        use std::mem;
        let mut new_callbacks = vec!();
        mem::swap(&mut new_callbacks, &mut self.callbacks);
        self.callbacks = new_callbacks
            .into_iter()
            .filter_map(|mut callback| {
                let result = callback(a.clone());
                match result {
                    Ok(_) => Some(callback),
                    Err(_) => None,
                }
            })
            .collect();
    }
}

#[cfg(test)]
mod test {
    use std::sync::{ Arc, RwLock };
    use std::thread;
    use super::*;

    #[test]
    fn with_weak_no_error() {
        let a = Arc::new(RwLock::new(3));
        let weak = Arc::downgrade(&a);
        assert_eq!(with_weak(&weak, |a| { *a = 4; }), Ok(()));
        assert_eq!(*a.read().unwrap(), 4);
    }

    #[test]
    fn with_weak_disappeared() {
        let weak = Arc::downgrade(&Arc::new(RwLock::new(3)));
        assert_eq!(with_weak(&weak, |_| ()), Err(CallbackError::Disappeared));
    }

    #[test]
    fn with_weak_poisoned() {
        let a = Arc::new(RwLock::new(3));
        let a2 = a.clone();
        let weak = Arc::downgrade(&a);
        let _ = thread::spawn(move || {
            let _g = a2.write().unwrap();
            panic!();
        }).join();
        assert_eq!(with_weak(&weak, |_| ()), Err(CallbackError::Poisoned));
    }

    #[test]
    fn source_register_and_send() {
        let mut src = Source::new();
        let a = Arc::new(RwLock::new(3));
        {
            let a = a.clone();
            src.register(move |x| {
                *a.write().unwrap() = x;
                Ok(())
            });
        }
        assert_eq!(src.callbacks.len(), 1);
        src.send(4);
        assert_eq!(*a.read().unwrap(), 4);
    }

    #[test]
    fn source_unregister() {
        let mut src = Source::new();
        src.register(|_| Err(CallbackError::Disappeared));
        assert_eq!(src.callbacks.len(), 1);
        src.send(());
        assert_eq!(src.callbacks.len(), 0);
    }
}
<commit_msg>Avoid an unnecessary extra clone when processing callbacks<commit_after>//! Event sources and callbacks.
//!
//! This is a light-weight implementation of the observer pattern. Subjects are
//! modelled as the `Source` type and observers as boxed closures.

use std::sync::{ RwLock, Weak };

/// An error that can occur with a weakly referenced callback.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum CallbackError {
    Disappeared,
    Poisoned,
}

/// Shorthand for common callback results.
pub type CallbackResult<T=()> = Result<T, CallbackError>;

/// A boxed callback.
type Callback<A> = Box<FnMut(A) -> CallbackResult + Send + Sync + 'static>;

/// Perform some callback on a weak reference to a mutex and handle errors
/// gracefully.
pub fn with_weak<T, U, F: FnOnce(&mut T) -> U>(weak: &Weak<RwLock<T>>, f: F) -> CallbackResult<U> {
    weak.upgrade()
        .ok_or(CallbackError::Disappeared)
        .and_then(|mutex| mutex.write()
            .map(|mut t| f(&mut t))
            .map_err(|_| CallbackError::Poisoned)
        )
}

/// An event source.
pub struct Source<A> {
    callbacks: Vec<Callback<A>>,
}

impl<A> Source<A> {
    /// Create a new source.
    pub fn new() -> Source<A> {
        Source { callbacks: vec![] }
    }

    /// Register a callback. The callback will be a mutable closure that takes
    /// an event and must return a result. To unsubscribe from further events,
    /// the callback has to return an error.
    pub fn register<F>(&mut self, callback: F)
        where F: FnMut(A) -> CallbackResult + Send + Sync + 'static
    {
        self.callbacks.push(Box::new(callback));
    }
}

impl<A: Send + Sync + Clone + 'static> Source<A> {
    /// Make the source send an event to all its observers.
    pub fn send(&mut self, a: A) {
        use std::mem;
        let mut new_callbacks = vec!();
        mem::swap(&mut new_callbacks, &mut self.callbacks);
        let n = new_callbacks.len();
        let mut iter = new_callbacks.into_iter();
        for _ in 1..n {
            let mut callback = iter.next().unwrap();
            if let Ok(_) = callback(a.clone()) {
                self.callbacks.push(callback);
            }
        }
        // process the last element without cloning
        if let Some(mut callback) = iter.next() {
            if let Ok(_) = callback(a) {
                self.callbacks.push(callback);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::{ Arc, RwLock };
    use std::thread;
    use super::*;

    #[test]
    fn with_weak_no_error() {
        let a = Arc::new(RwLock::new(3));
        let weak = Arc::downgrade(&a);
        assert_eq!(with_weak(&weak, |a| { *a = 4; }), Ok(()));
        assert_eq!(*a.read().unwrap(), 4);
    }

    #[test]
    fn with_weak_disappeared() {
        let weak = Arc::downgrade(&Arc::new(RwLock::new(3)));
        assert_eq!(with_weak(&weak, |_| ()), Err(CallbackError::Disappeared));
    }

    #[test]
    fn with_weak_poisoned() {
        let a = Arc::new(RwLock::new(3));
        let a2 = a.clone();
        let weak = Arc::downgrade(&a);
        let _ = thread::spawn(move || {
            let _g = a2.write().unwrap();
            panic!();
        }).join();
        assert_eq!(with_weak(&weak, |_| ()), Err(CallbackError::Poisoned));
    }

    #[test]
    fn source_register_and_send() {
        let mut src = Source::new();
        let a = Arc::new(RwLock::new(3));
        {
            let a = a.clone();
            src.register(move |x| {
                *a.write().unwrap() = x;
                Ok(())
            });
        }
        assert_eq!(src.callbacks.len(), 1);
        src.send(4);
        assert_eq!(*a.read().unwrap(), 4);
    }

    #[test]
    fn source_unregister() {
        let mut src = Source::new();
        src.register(|_| Err(CallbackError::Disappeared));
        assert_eq!(src.callbacks.len(), 1);
        src.send(());
        assert_eq!(src.callbacks.len(), 0);
    }
}
<|endoftext|>


<commit_before>//  notty is a new kind of terminal emulator.
//  Copyright (C) 2015 without boats
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
extern crate cairo;
extern crate gdk;
extern crate gtk;

extern crate tty;
extern crate notty;
extern crate notty_cairo;

use std::cell::RefCell;
use std::env;
use std::io::BufReader;
use std::sync::mpsc;
use std::rc::Rc;
use std::thread;

use gtk::{WindowTrait, WidgetTrait, WidgetSignals, ContainerTrait};

use notty::{Output, Command, KeyPress, KeyRelease};
use notty::terminal::Terminal;
use notty_cairo::Renderer;

mod commands;
mod key;

use commands::CommandApplicator;
use key::FromEvent;

static mut X_PIXELS: Option<u32> = None;
static mut Y_PIXELS: Option<u32> = None;

static COLS: u32 = 80;
static ROWS: u32 = 25;

fn main() {

    // Set up window and drawing canvas.
    gtk::init().unwrap();
    let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
    let canvas = Rc::new(gtk::DrawingArea::new().unwrap());
    window.add(&*canvas);

    // Set the TERM variable and establish a TTY connection
    env::set_var("TERM", "notty");
    let (tty_r, tty_w) = tty::pty("sh", COLS as u16, ROWS as u16);

    // Handler program output (tty -> screen) on separate thread.
    let (tx_out, rx) = mpsc::channel();
    let (tx_key_press, tx_key_release) = (tx_out.clone(), tx_out.clone());
    thread::spawn(move || {
        let output = Output::new(BufReader::new(tty_r));
        for cmd in output {
            tx_out.send(cmd.unwrap()).unwrap();
        }
    });

    // Set up logical terminal and renderer.
    let terminal = Rc::new(RefCell::new(Terminal::new(COLS, ROWS, tty_w)));
    let renderer = RefCell::new(Renderer::new());

    // Process screen logic every 125 milliseconds.
    let cmd = CommandApplicator::new(rx, terminal.clone(), canvas.clone());
    gdk::glib::timeout_add(125, move || cmd.apply());

    // Connect signal to draw on canvas.
    canvas.connect_draw(move |_, canvas| {
        let mut terminal = terminal.borrow_mut();
        if let (Some(x_pix), Some(y_pix)) = unsafe {(X_PIXELS.take(), Y_PIXELS.take())} {
            reset_dimensions(&canvas, &mut terminal, x_pix, y_pix);
        }
        renderer.borrow_mut().draw(&terminal, &canvas);
        gtk::signal::Inhibit(false)
    });

    // Connect signal for changing window size.
    canvas.connect_configure_event(move |canvas, config| {
        unsafe {
            X_PIXELS = Some(config.width as u32);
            Y_PIXELS = Some(config.height as u32);
        }
        canvas.queue_draw();
        gtk::signal::Inhibit(false)
    });

    // Connect signal to receive key presses.
    window.connect_key_press_event(move |window, event| {
        if let Some(cmd) = KeyPress::from_event(event) {
            tx_key_press.send(cmd).unwrap();
        } else { window.queue_draw(); }
        gtk::signal::Inhibit(false)
    });

    // Connect signal to receive key releases.
    window.connect_key_release_event(move |window, event| {
        if let Some(cmd) = KeyRelease::from_event(event) {
            tx_key_release.send(cmd).unwrap();
        } else { window.queue_draw(); }
        gtk::signal::Inhibit(false)
    });

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        gtk::signal::Inhibit(false)
    });

    // Show the window and run the GTK event loop.
    window.set_default_size(800, 800);
    window.show_all();
    gtk::main();

}

fn reset_dimensions(canvas: &cairo::Context, terminal: &mut Terminal, x_pix: u32, y_pix: u32) {
    let f_extents = canvas.font_extents();
    let w = x_pix / f_extents.max_x_advance as u32;
    let h = y_pix / (f_extents.height + f_extents.ascent + f_extents.descent) as u32;
    terminal.set_winsize(w, h).unwrap_or_else(|e| panic!("{}", e));
}
<commit_msg>Fail slightly more gracefully on Ctrl-D<commit_after>//  notty is a new kind of terminal emulator.
//  Copyright (C) 2015 without boats
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
extern crate cairo;
extern crate gdk;
extern crate gtk;

extern crate tty;
extern crate notty;
extern crate notty_cairo;

use std::cell::RefCell;
use std::env;
use std::io::BufReader;
use std::sync::mpsc;
use std::rc::Rc;
use std::thread;

use gtk::{WindowTrait, WidgetTrait, WidgetSignals, ContainerTrait};

use notty::{Output, Command, KeyPress, KeyRelease};
use notty::terminal::Terminal;
use notty_cairo::Renderer;

mod commands;
mod key;

use commands::CommandApplicator;
use key::FromEvent;

static mut X_PIXELS: Option<u32> = None;
static mut Y_PIXELS: Option<u32> = None;

static COLS: u32 = 80;
static ROWS: u32 = 25;

fn quit_because(e: std::io::Error) {
    println!("Quitting because: {}", e);
    std::process::exit(1)
}

fn main() {

    // Set up window and drawing canvas.
    gtk::init().unwrap();
    let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
    let canvas = Rc::new(gtk::DrawingArea::new().unwrap());
    window.add(&*canvas);

    // Set the TERM variable and establish a TTY connection
    env::set_var("TERM", "notty");
    let (tty_r, tty_w) = tty::pty("sh", COLS as u16, ROWS as u16);

    // Handler program output (tty -> screen) on separate thread.
    let (tx_out, rx) = mpsc::channel();
    let (tx_key_press, tx_key_release) = (tx_out.clone(), tx_out.clone());
    thread::spawn(move || {
        let output = Output::new(BufReader::new(tty_r));
        for cmd in output {
            match cmd {
                Ok(good) => tx_out.send(good).unwrap(),
                Err(err) => quit_because(err)
            };
            // tx_out.send(cmd.unwrap()).unwrap();
        }
    });

    // Set up logical terminal and renderer.
    let terminal = Rc::new(RefCell::new(Terminal::new(COLS, ROWS, tty_w)));
    let renderer = RefCell::new(Renderer::new());

    // Process screen logic every 125 milliseconds.
    let cmd = CommandApplicator::new(rx, terminal.clone(), canvas.clone());
    gdk::glib::timeout_add(125, move || cmd.apply());

    // Connect signal to draw on canvas.
    canvas.connect_draw(move |_, canvas| {
        let mut terminal = terminal.borrow_mut();
        if let (Some(x_pix), Some(y_pix)) = unsafe {(X_PIXELS.take(), Y_PIXELS.take())} {
            reset_dimensions(&canvas, &mut terminal, x_pix, y_pix);
        }
        renderer.borrow_mut().draw(&terminal, &canvas);
        gtk::signal::Inhibit(false)
    });

    // Connect signal for changing window size.
    canvas.connect_configure_event(move |canvas, config| {
        unsafe {
            X_PIXELS = Some(config.width as u32);
            Y_PIXELS = Some(config.height as u32);
        }
        canvas.queue_draw();
        gtk::signal::Inhibit(false)
    });

    // Connect signal to receive key presses.
    window.connect_key_press_event(move |window, event| {
        if let Some(cmd) = KeyPress::from_event(event) {
            tx_key_press.send(cmd).unwrap();
        } else { window.queue_draw(); }
        gtk::signal::Inhibit(false)
    });

    // Connect signal to receive key releases.
    window.connect_key_release_event(move |window, event| {
        if let Some(cmd) = KeyRelease::from_event(event) {
            tx_key_release.send(cmd).unwrap();
        } else { window.queue_draw(); }
        gtk::signal::Inhibit(false)
    });

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        gtk::signal::Inhibit(false)
    });

    // Show the window and run the GTK event loop.
    window.set_default_size(800, 800);
    window.show_all();
    gtk::main();

}

fn reset_dimensions(canvas: &cairo::Context, terminal: &mut Terminal, x_pix: u32, y_pix: u32) {
    let f_extents = canvas.font_extents();
    let w = x_pix / f_extents.max_x_advance as u32;
    let h = y_pix / (f_extents.height + f_extents.ascent + f_extents.descent) as u32;
    terminal.set_winsize(w, h).unwrap_or_else(|e| panic!("{}", e));
}
<|endoftext|>


<commit_before>use num::traits::{Num, NumCast};

/// This is the basic trait that must be satisfied for basic elements used in `Tensor`.
pub trait TensorTrait: Copy {}
impl<T: Copy> TensorTrait for T {}

/// `NumericTrait` extends `TensorTrait` to all the numeric types supported by `Tensor`
/// (e.g. `u8` and `f32`).
pub trait NumericTrait: TensorTrait + Num + NumCast + PartialOrd {}
impl<T: TensorTrait + Num + NumCast + PartialOrd> NumericTrait for T {}
<commit_msg>DOC: Added short blurb for traits mod<commit_after>//! Traits used by Tensor.

use num::traits::{Num, NumCast};

/// This is the basic trait that must be satisfied for basic elements used in `Tensor`.
pub trait TensorTrait: Copy {}
impl<T: Copy> TensorTrait for T {}

/// `NumericTrait` extends `TensorTrait` to all the numeric types supported by `Tensor`
/// (e.g. `u8` and `f32`).
pub trait NumericTrait: TensorTrait + Num + NumCast + PartialOrd {}
impl<T: TensorTrait + Num + NumCast + PartialOrd> NumericTrait for T {}
<|endoftext|>


<commit_before>use radians::{self, Radians};
use turtle_window::TurtleWindow;
use event::MouseButton;
use {Speed, Color, Event};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AngleUnit {
    Degrees,
    Radians,
}

impl AngleUnit {
    fn to_radians(&self, angle: Angle) -> Radians {
        match *self {
            AngleUnit::Degrees => Radians::from_degrees_value(angle),
            AngleUnit::Radians => Radians::from_radians_value(angle),
        }
    }

    fn to_angle(&self, angle: Radians) -> Angle {
        match *self {
            AngleUnit::Degrees => angle.to_degrees(),
            AngleUnit::Radians => angle.to_radians(),
        }
    }
}

/// A point in 2D space: [x, y]
///
/// ```rust
/// # extern crate turtle;
/// # use turtle::Point;
/// # fn main() {
/// let p: Point = [100., 120.];
/// // get x coordinate
/// let x = p[0];
/// assert_eq!(x, 100.);
/// // get y coordinate
/// let y = p[1];
/// assert_eq!(y, 120.);
/// # }
pub type Point = [f64; 2];

/// Any distance value
pub type Distance = f64;

/// An angle value without a unit
///
/// The unit of the angle represented by this value depends on what
/// unit the Turtle was set to when this angle was retrieved
pub type Angle = f64;

/// A turtle with a pen attached to its tail
pub struct Turtle {
    window: TurtleWindow,
    angle_unit: AngleUnit,
}

impl Turtle {
    /// Initialize a new Turtle instance
    pub fn new() -> Turtle {
        Turtle {
            window: TurtleWindow::new(),
            angle_unit: AngleUnit::Degrees,
        }
    }

    /// Returns the current speed of the turtle
    pub fn speed(&self) -> Speed {
        self.window.turtle().speed
    }

    /// Returns the turtle's current location (x, y)
    pub fn position(&self) -> Point {
        self.window.turtle().position
    }

    /// Returns the turtle's current heading
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn heading(&self) -> Angle {
        let heading = self.window.turtle().heading;
        self.angle_unit.to_angle(heading)
    }

    /// Returns true if the turtle is visible
    pub fn is_visible(&self) -> bool {
        self.window.turtle().visible
    }

    /// Returns true if Angle values will be interpreted as degrees
    pub fn is_using_degrees(&self) -> bool {
        self.angle_unit == AngleUnit::Degrees
    }

    /// Returns true if Angle values will be interpreted as radians
    pub fn is_using_radians(&self) -> bool {
        self.angle_unit == AngleUnit::Radians
    }

    /// Return true if pen is down, false if it’s up.
    pub fn is_pen_down(&self) -> bool {
        self.window.drawing().pen.enabled
    }

    /// Returns the size (thickness) of the pen
    pub fn pen_size(&self) -> f64 {
        self.window.drawing().pen.thickness
    }

    /// Returns the color of the pen
    pub fn pen_color(&self) -> Color {
        self.window.drawing().pen.color
    }

    /// Returns the color of the background
    pub fn background_color(&self) -> Color {
        self.window.drawing().background
    }

    /// Returns the current fill color
    ///
    /// This will be used to fill the shape when `begin_fill()` and `end_fill()` are called.
    //TODO: Hyperlink begin_fill() and end_fill() methods to their docs
    pub fn fill_color(&self) -> Color {
        self.window.drawing().fill_color
    }

    /// Begin filling the shape drawn by the turtle's movements
    pub fn begin_fill(&mut self) {
        self.window.begin_fill();
    }

    /// Stop filling the shape drawn by the turtle's movements
    pub fn end_fill(&mut self) {
        self.window.end_fill();
    }

    /// Pull the pen down so that the turtle draws while moving
    pub fn pen_down(&mut self) {
        self.window.drawing_mut().pen.enabled = true;
    }

    /// Pick the pen up so that the turtle does not draw while moving
    pub fn pen_up(&mut self) {
        self.window.drawing_mut().pen.enabled = false;
    }

    /// Sets the thickness of the pen to the given size
    //TODO: Document this more like set_speed
    pub fn set_pen_size(&mut self, thickness: f64) {
        self.window.drawing_mut().pen.thickness = thickness;
    }

    /// Sets the color of the pen to the given color
    //TODO: Document this more like set_speed
    pub fn set_pen_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().pen.color = color.into();
    }

    /// Sets the color of the background to the given color
    //TODO: Document this more like set_speed
    pub fn set_background_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().background = color.into();
    }

    /// Sets the fill color to the given color
    ///
    /// **Note:** Only the fill color set **before** `begin_fill()` is called will be used to fill
    /// the shape.
    //TODO: Document this more like set_speed
    pub fn set_fill_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().fill_color = color.into();
    }

    /// Set the turtle's movement speed to the given setting. This speed affects the animation of
    /// the turtle's movement and rotation.
    ///
    /// This method's types make it so that it can be called in a number of different ways:
    ///
    /// ```rust,no_run
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed("normal");
    /// turtle.set_speed("fast");
    /// turtle.set_speed(2);
    /// turtle.set_speed(10);
    /// // Directly using a Speed variant works, but the methods above are usually more convenient.
    /// turtle.set_speed(Speed::Six);
    /// # }
    /// ```
    ///
    /// If input is a number greater than 10 or smaller than 1,
    /// speed is set to 0 (`Speed::Instant`). Strings are converted as follows:
    ///
    /// | String      | Value          |
    /// | ----------- | -------------- |
    /// | `"slowest"` | `Speed::One`     |
    /// | `"slow"`    | `Speed::Three`   |
    /// | `"normal"`  | `Speed::Six`     |
    /// | `"fast"`    | `Speed::Eight`   |
    /// | `"fastest"` | `Speed::Ten`     |
    /// | `"instant"` | `Speed::Instant` |
    ///
    /// Anything else will cause the program to `panic!` at runtime.
    ///
    /// ## Moving Instantly
    ///
    /// A speed of zero (`Speed::Instant`) results in no animation. The turtle moves instantly
    /// and turns instantly. This is very useful for moving the turtle from its "home" position
    /// before you start drawing. By setting the speed to instant, you don't have to wait for
    /// the turtle to move into position.
    ///
    /// ## Learning About Conversion Traits
    ///
    /// Using this method is an excellent way to learn about conversion
    /// traits `From` and `Into`. This method takes a *generic type* as its speed parameter. That type
    /// is specified to implement the `Into` trait for the type `Speed`. That means that *any* type
    /// that can be converted into a `Speed` can be passed to this method.
    ///
    /// We have implemented that trait for several types like strings and 32-bit integers so that
    /// those values can be passed into this method.
    /// Rather than calling this function and passing `Speed::Six` directly, you can use just `6`.
    /// Rust will then allow us to call `.into()` as provided by the `Into<Speed>` trait to get the
    /// corresponding `Speed` value.
    ///
    /// You can pass in strings, 32-bit integers, and even `Speed` enum variants because they all
    /// implement the `Into<Speed>` trait.
    pub fn set_speed<S: Into<Speed>>(&mut self, speed: S) {
        self.window.turtle_mut().speed = speed.into();
    }

    /// Delete the turtle's drawings from the screen.
    ///
    /// Do not move turtle. Position and heading of the turtle are not affected.
    pub fn clear(&mut self) {
        self.window.clear();
    }

    /// Makes the turtle invisible. The shell will not be shown, but drawings will continue.
    ///
    /// Useful for some complex drawings.
    pub fn hide(&mut self) {
        self.window.turtle_mut().visible = false;
    }

    /// Makes the turtle visible.
    pub fn show(&mut self) {
        self.window.turtle_mut().visible = true;
    }

    /// Change the angle unit to degrees.
    pub fn use_degrees(&mut self) {
        self.angle_unit = AngleUnit::Degrees;
    }

    /// Change the angle unit to radians.
    pub fn use_radians(&mut self) {
        self.angle_unit = AngleUnit::Radians;
    }

    /// Move the turtle forward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move backward
    /// using this method.
    pub fn forward(&mut self, distance: Distance) {
        self.window.forward(distance);
    }

    /// Move the turtle backward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move forwards
    /// using this method.
    pub fn backward(&mut self, distance: Distance) {
        // Moving backwards is essentially moving forwards with a negative distance
        self.window.forward(-distance);
    }

    /// Rotate the turtle right (clockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn right(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, true);
    }

    /// Rotate the turtle left (counterclockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn left(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, false);
    }

    /// Rotates the turtle to face the given coordinates.
    /// Coordinates are relative to the center of the window.
    ///
    /// If the coordinates are the same as the turtle's current position, no rotation takes place.
    /// Always rotates the least amount necessary in order to face the given point.
    ///
    /// ## UNSTABLE
    /// This feature is currently unstable and completely buggy. Do not use it until it is fixed.
    pub fn turn_towards(&mut self, target: Point) {
        let target_x = target[0];
        let target_y = target[1];

        let position = self.position();
        let x = position[0];
        let y = position[1];

        if (target_x - x).abs() < 0.1 && (target_y - y).abs() < 0.1 {
            return;
        }

        let heading = self.window.turtle().heading;

        let angle = (target_y - y).atan2(target_x - x);
        let angle = Radians::from_radians_value(angle);
        let angle = (angle - heading) % radians::TWO_PI;
        // Try to rotate as little as possible
        let angle = if angle.abs() > radians::PI {
            // Using signum to deal with negative angles properly
            angle.signum()*(radians::TWO_PI - angle.abs())
        }
        else {
            angle
        };
        self.window.rotate(angle, false);
    }

    /// Returns the next event (if any).
    //TODO: Example of usage with an event loop
    pub fn poll_event(&mut self) -> Option<Event> {
        self.window.poll_event()
    }

    /// Convenience function that waits for a click to occur before returning.
    ///
    /// Useful for when you want your program to wait for the user to click before continuing so
    /// that it doesn't start right away.
    pub fn wait_for_click(&mut self) {
        loop {
            if let Some(Event::MouseButtonReleased(MouseButton::Left)) = self.poll_event() {
                break;
            }
        }
    }
}
<commit_msg>Added some documentation to the Turtle struct about how the Turtle works.<commit_after>use radians::{self, Radians};
use turtle_window::TurtleWindow;
use event::MouseButton;
use {Speed, Color, Event};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AngleUnit {
    Degrees,
    Radians,
}

impl AngleUnit {
    fn to_radians(&self, angle: Angle) -> Radians {
        match *self {
            AngleUnit::Degrees => Radians::from_degrees_value(angle),
            AngleUnit::Radians => Radians::from_radians_value(angle),
        }
    }

    fn to_angle(&self, angle: Radians) -> Angle {
        match *self {
            AngleUnit::Degrees => angle.to_degrees(),
            AngleUnit::Radians => angle.to_radians(),
        }
    }
}

/// A point in 2D space: [x, y]
///
/// ```rust
/// # extern crate turtle;
/// # use turtle::Point;
/// # fn main() {
/// let p: Point = [100., 120.];
/// // get x coordinate
/// let x = p[0];
/// assert_eq!(x, 100.);
/// // get y coordinate
/// let y = p[1];
/// assert_eq!(y, 120.);
/// # }
pub type Point = [f64; 2];

/// Any distance value
pub type Distance = f64;

/// An angle value without a unit
///
/// The unit of the angle represented by this value depends on what
/// unit the Turtle was set to when this angle was retrieved
pub type Angle = f64;

/// A turtle with a pen attached to its tail.
///
/// **The idea:** You control a turtle with a pen tied to its tail. As it moves
/// across the screen, it draws the path that it follows. You can use this to draw
/// any picture you want just by moving the turtle across the screen.
///
/// ![turtle moving forward](https://github.com/sunjay/turtle/raw/master/forward.gif)
///
/// See the documentation for the methods below to learn about the different drawing commands you
/// can use with the turtle.
pub struct Turtle {
    window: TurtleWindow,
    angle_unit: AngleUnit,
}

impl Turtle {
    /// Initialize a new Turtle instance
    pub fn new() -> Turtle {
        Turtle {
            window: TurtleWindow::new(),
            angle_unit: AngleUnit::Degrees,
        }
    }

    /// Returns the current speed of the turtle
    pub fn speed(&self) -> Speed {
        self.window.turtle().speed
    }

    /// Returns the turtle's current location (x, y)
    pub fn position(&self) -> Point {
        self.window.turtle().position
    }

    /// Returns the turtle's current heading
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn heading(&self) -> Angle {
        let heading = self.window.turtle().heading;
        self.angle_unit.to_angle(heading)
    }

    /// Returns true if the turtle is visible
    pub fn is_visible(&self) -> bool {
        self.window.turtle().visible
    }

    /// Returns true if Angle values will be interpreted as degrees
    pub fn is_using_degrees(&self) -> bool {
        self.angle_unit == AngleUnit::Degrees
    }

    /// Returns true if Angle values will be interpreted as radians
    pub fn is_using_radians(&self) -> bool {
        self.angle_unit == AngleUnit::Radians
    }

    /// Return true if pen is down, false if it’s up.
    pub fn is_pen_down(&self) -> bool {
        self.window.drawing().pen.enabled
    }

    /// Returns the size (thickness) of the pen
    pub fn pen_size(&self) -> f64 {
        self.window.drawing().pen.thickness
    }

    /// Returns the color of the pen
    pub fn pen_color(&self) -> Color {
        self.window.drawing().pen.color
    }

    /// Returns the color of the background
    pub fn background_color(&self) -> Color {
        self.window.drawing().background
    }

    /// Returns the current fill color
    ///
    /// This will be used to fill the shape when `begin_fill()` and `end_fill()` are called.
    //TODO: Hyperlink begin_fill() and end_fill() methods to their docs
    pub fn fill_color(&self) -> Color {
        self.window.drawing().fill_color
    }

    /// Begin filling the shape drawn by the turtle's movements
    pub fn begin_fill(&mut self) {
        self.window.begin_fill();
    }

    /// Stop filling the shape drawn by the turtle's movements
    pub fn end_fill(&mut self) {
        self.window.end_fill();
    }

    /// Pull the pen down so that the turtle draws while moving
    pub fn pen_down(&mut self) {
        self.window.drawing_mut().pen.enabled = true;
    }

    /// Pick the pen up so that the turtle does not draw while moving
    pub fn pen_up(&mut self) {
        self.window.drawing_mut().pen.enabled = false;
    }

    /// Sets the thickness of the pen to the given size
    //TODO: Document this more like set_speed
    pub fn set_pen_size(&mut self, thickness: f64) {
        self.window.drawing_mut().pen.thickness = thickness;
    }

    /// Sets the color of the pen to the given color
    //TODO: Document this more like set_speed
    pub fn set_pen_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().pen.color = color.into();
    }

    /// Sets the color of the background to the given color
    //TODO: Document this more like set_speed
    pub fn set_background_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().background = color.into();
    }

    /// Sets the fill color to the given color
    ///
    /// **Note:** Only the fill color set **before** `begin_fill()` is called will be used to fill
    /// the shape.
    //TODO: Document this more like set_speed
    pub fn set_fill_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().fill_color = color.into();
    }

    /// Set the turtle's movement speed to the given setting. This speed affects the animation of
    /// the turtle's movement and rotation.
    ///
    /// This method's types make it so that it can be called in a number of different ways:
    ///
    /// ```rust,no_run
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed("normal");
    /// turtle.set_speed("fast");
    /// turtle.set_speed(2);
    /// turtle.set_speed(10);
    /// // Directly using a Speed variant works, but the methods above are usually more convenient.
    /// turtle.set_speed(Speed::Six);
    /// # }
    /// ```
    ///
    /// If input is a number greater than 10 or smaller than 1,
    /// speed is set to 0 (`Speed::Instant`). Strings are converted as follows:
    ///
    /// | String      | Value          |
    /// | ----------- | -------------- |
    /// | `"slowest"` | `Speed::One`     |
    /// | `"slow"`    | `Speed::Three`   |
    /// | `"normal"`  | `Speed::Six`     |
    /// | `"fast"`    | `Speed::Eight`   |
    /// | `"fastest"` | `Speed::Ten`     |
    /// | `"instant"` | `Speed::Instant` |
    ///
    /// Anything else will cause the program to `panic!` at runtime.
    ///
    /// ## Moving Instantly
    ///
    /// A speed of zero (`Speed::Instant`) results in no animation. The turtle moves instantly
    /// and turns instantly. This is very useful for moving the turtle from its "home" position
    /// before you start drawing. By setting the speed to instant, you don't have to wait for
    /// the turtle to move into position.
    ///
    /// ## Learning About Conversion Traits
    ///
    /// Using this method is an excellent way to learn about conversion
    /// traits `From` and `Into`. This method takes a *generic type* as its speed parameter. That type
    /// is specified to implement the `Into` trait for the type `Speed`. That means that *any* type
    /// that can be converted into a `Speed` can be passed to this method.
    ///
    /// We have implemented that trait for several types like strings and 32-bit integers so that
    /// those values can be passed into this method.
    /// Rather than calling this function and passing `Speed::Six` directly, you can use just `6`.
    /// Rust will then allow us to call `.into()` as provided by the `Into<Speed>` trait to get the
    /// corresponding `Speed` value.
    ///
    /// You can pass in strings, 32-bit integers, and even `Speed` enum variants because they all
    /// implement the `Into<Speed>` trait.
    pub fn set_speed<S: Into<Speed>>(&mut self, speed: S) {
        self.window.turtle_mut().speed = speed.into();
    }

    /// Delete the turtle's drawings from the screen.
    ///
    /// Do not move turtle. Position and heading of the turtle are not affected.
    pub fn clear(&mut self) {
        self.window.clear();
    }

    /// Makes the turtle invisible. The shell will not be shown, but drawings will continue.
    ///
    /// Useful for some complex drawings.
    pub fn hide(&mut self) {
        self.window.turtle_mut().visible = false;
    }

    /// Makes the turtle visible.
    pub fn show(&mut self) {
        self.window.turtle_mut().visible = true;
    }

    /// Change the angle unit to degrees.
    pub fn use_degrees(&mut self) {
        self.angle_unit = AngleUnit::Degrees;
    }

    /// Change the angle unit to radians.
    pub fn use_radians(&mut self) {
        self.angle_unit = AngleUnit::Radians;
    }

    /// Move the turtle forward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move backward
    /// using this method.
    pub fn forward(&mut self, distance: Distance) {
        self.window.forward(distance);
    }

    /// Move the turtle backward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move forwards
    /// using this method.
    pub fn backward(&mut self, distance: Distance) {
        // Moving backwards is essentially moving forwards with a negative distance
        self.window.forward(-distance);
    }

    /// Rotate the turtle right (clockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn right(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, true);
    }

    /// Rotate the turtle left (counterclockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn left(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, false);
    }

    /// Rotates the turtle to face the given coordinates.
    /// Coordinates are relative to the center of the window.
    ///
    /// If the coordinates are the same as the turtle's current position, no rotation takes place.
    /// Always rotates the least amount necessary in order to face the given point.
    ///
    /// ## UNSTABLE
    /// This feature is currently unstable and completely buggy. Do not use it until it is fixed.
    pub fn turn_towards(&mut self, target: Point) {
        let target_x = target[0];
        let target_y = target[1];

        let position = self.position();
        let x = position[0];
        let y = position[1];

        if (target_x - x).abs() < 0.1 && (target_y - y).abs() < 0.1 {
            return;
        }

        let heading = self.window.turtle().heading;

        let angle = (target_y - y).atan2(target_x - x);
        let angle = Radians::from_radians_value(angle);
        let angle = (angle - heading) % radians::TWO_PI;
        // Try to rotate as little as possible
        let angle = if angle.abs() > radians::PI {
            // Using signum to deal with negative angles properly
            angle.signum()*(radians::TWO_PI - angle.abs())
        }
        else {
            angle
        };
        self.window.rotate(angle, false);
    }

    /// Returns the next event (if any).
    //TODO: Example of usage with an event loop
    pub fn poll_event(&mut self) -> Option<Event> {
        self.window.poll_event()
    }

    /// Convenience function that waits for a click to occur before returning.
    ///
    /// Useful for when you want your program to wait for the user to click before continuing so
    /// that it doesn't start right away.
    pub fn wait_for_click(&mut self) {
        loop {
            if let Some(Event::MouseButtonReleased(MouseButton::Left)) = self.poll_event() {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>//!
//! Values manipulated by services
//!
use std::cmp::{PartialOrd, Ordering};
use std::time::Duration;
use std::str::FromStr;
use std::sync::Arc;

use serde_json;
use chrono;
use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

///
/// The type of values manipulated by endpoints.
///
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    Temperature,
    String,
    ///
    /// ...
    ///
    Color,
    Json,
    Binary,
    ExtNumeric,
}

/// A temperature. Internal representation may be either Fahrenheit or
/// Celcius. The FoxBox adapters are expected to perform conversions
/// to the format requested by their devices.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Temperature {
    /// Fahrenheit
    F(f64),
    /// Celcius
    C(f64),
}

impl Temperature {
    /// Get a temperature in Fahrenheit.
    pub fn as_f(&self) -> f64 {
        unimplemented!();
    }

    /// Get a temperature in Celcius.
    pub fn as_c(&self) -> f64 {
        unimplemented!();
    }
}

impl PartialOrd for Temperature {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_c().partial_cmp(&other.as_c())
    }
}

/// A color. Internal representation may vary. The FoxBox adapters are
/// expected to perform conversions to the format requested by their
/// device.
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum Color {
    RGBA(f64, f64, f64, f64, f64)
}

/// Representation of an object in JSON. It is often (albeit not
/// always) possible to choose a more precise data structure for
/// representing values send/accepted by a service. If possible,
/// adapters should rather pick such more precise data structure.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Json(pub serde_json::value::Value);

impl PartialOrd for Json {
    /// Two Json objects are never comparable to each other.
    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
        None
    }
}

/// A data structure holding a numeric value of a type that has not
/// been standardized yet.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExtNumeric {
    pub value: f64,

    /// The vendor. Used for namespacing purposes, to avoid
    /// confusing two incompatible extensions with similar
    /// names. For instance, "foxlink@mozilla.com".
    pub vendor: String,

    /// Identification of the adapter introducing this value.
    /// Designed to aid with tracing and debugging.
    pub adapter: String,

    /// A string describing the nature of the value, designed to
    /// aid with type-checking.
    ///
    /// Examples: `"GroundHumidity"`.
    pub kind: String,
}

impl PartialOrd for ExtNumeric {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.vendor != other.vendor {
            return None;
        } else if self.kind != other.kind {
            return None;
        } else {
            self.value.partial_cmp(&other.value)
        }
    }
}

/// Representation of an actual value that can be sent to/received
/// from a service.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Value {
    Unit,
    Bool(bool),
    Duration(ValDuration),
    TimeStamp(TimeStamp),
    Temperature(Temperature),
    Color(Color),
    String(Arc<String>),

    // FIXME: Add more as we identify needs

    /// A numeric value representing a unit that has not been
    /// standardized yet into the API.
    ExtNumeric(ExtNumeric),

    /// A Json value. We put it behind an `Arc` to make sure that
    /// cloning remains unexpensive.
    Json(Arc<Json>),

    /// Binary data.
    Binary {
        /// The actual data. We put it behind an `Arc` to make sure
        /// that cloning remains unexpensive.
        data: Arc<Vec<u8>>,
        mimetype: String
    }
}

impl Value {
    pub fn get_type(&self) -> Type {
        match *self {
            Value::Unit => Type::Unit,
            Value::Bool(_) => Type::Bool,
            Value::String(_) => Type::String,
            Value::Duration(_) => Type::Duration,
            Value::TimeStamp(_) => Type::TimeStamp,
            Value::Temperature(_) => Type::Temperature,
            Value::Color(_) => Type::Color,
            Value::Json(_) => Type::Json,
            Value::Binary{..} => Type::Binary,
            Value::ExtNumeric(_) => Type::ExtNumeric,
        }
    }
}

impl PartialOrd for Value {
    /// Two values of the same type can be compared using the usual
    /// comparison for values of this type. Two values of distinct
    /// types cannot be compared.
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        use self::Value::*;
        use std::cmp::Ordering::*;
        match (self, other) {
            (&Unit, &Unit) => Some(Equal),
            (&Unit, _) => None,

            (&Bool(a), &Bool(b)) => a.partial_cmp(&b),
            (&Bool(_), _) => None,

            (&Duration(ref a), &Duration(ref b)) => a.partial_cmp(b),
            (&Duration(_), _) => None,

            (&TimeStamp(ref a), &TimeStamp(ref b)) => a.partial_cmp(b),
            (&TimeStamp(_), _) => None,

            (&Temperature(ref a), &Temperature(ref b)) => a.partial_cmp(b),
            (&Temperature(_), _) => None,

            (&Color(ref a), &Color(ref b)) => a.partial_cmp(b),
            (&Color(_), _) => None,

            (&ExtNumeric(ref a), &ExtNumeric(ref b)) => a.partial_cmp(b),
            (&ExtNumeric(_), _) => None,

            (&String(ref a), &String(ref b)) => a.partial_cmp(b),
            (&String(_), _) => None,

            (&Json(ref a), &Json(ref b)) => a.partial_cmp(b),
            (&Json(_), _) => None,

            (&Binary{mimetype: ref a_mimetype, data: ref a_data},
             &Binary{mimetype: ref b_mimetype, data: ref b_data}) if a_mimetype == b_mimetype => a_data.partial_cmp(b_data),
            (&Binary{..}, _) => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct ValDuration(Duration);
impl ValDuration {
    pub fn new(duration: Duration) -> Self {
        ValDuration(duration)
    }
}
impl Serialize for ValDuration {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        let as_ms : u64 = self.0.as_secs() * 1000
            + (self.0.subsec_nanos() as u64) / 1_000_000;
        as_ms.serialize(serializer)
    }
}
impl Deserialize for ValDuration {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        let as_ms : u64 = try!(u64::deserialize(deserializer));
        let as_sec = as_ms / 1000;
        let as_ns = (as_ms / 1_000_000) as u32;
        Ok(ValDuration(Duration::new(as_sec, as_ns)))
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct TimeStamp(chrono::DateTime<chrono::Local>);
impl TimeStamp {
    pub fn from_s(s: i64) -> Self {
        use chrono::*;
        let naive = chrono::naive::datetime::NaiveDateTime::from_timestamp(s, 0);
        let offset = chrono::offset::fixed::FixedOffset::east(0);
        let date = DateTime::<Local>::from_utc(naive, offset);
        TimeStamp(date)
    }
}
impl Serialize for TimeStamp {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        let str = self.0.to_rfc3339();
        str.serialize(serializer)
    }
}
impl Deserialize for TimeStamp {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        let str = try!(String::deserialize(deserializer));
        match chrono::DateTime::<chrono::Local>::from_str(&str) {
            Ok(dt) => Ok(TimeStamp(dt)),
            Err(_) => Err(D::Error::syntax("Invalid date"))
        }
    }
}
<commit_msg>ValDuration now uses float<commit_after>//!
//! Values manipulated by services
//!
use std::cmp::{PartialOrd, Ordering};
use std::time::Duration;
use std::str::FromStr;
use std::sync::Arc;

use serde_json;
use chrono;
use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

///
/// The type of values manipulated by endpoints.
///
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    Temperature,
    String,
    ///
    /// ...
    ///
    Color,
    Json,
    Binary,
    ExtNumeric,
}

/// A temperature. Internal representation may be either Fahrenheit or
/// Celcius. The FoxBox adapters are expected to perform conversions
/// to the format requested by their devices.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Temperature {
    /// Fahrenheit
    F(f64),
    /// Celcius
    C(f64),
}

impl Temperature {
    /// Get a temperature in Fahrenheit.
    pub fn as_f(&self) -> f64 {
        unimplemented!();
    }

    /// Get a temperature in Celcius.
    pub fn as_c(&self) -> f64 {
        unimplemented!();
    }
}

impl PartialOrd for Temperature {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_c().partial_cmp(&other.as_c())
    }
}

/// A color. Internal representation may vary. The FoxBox adapters are
/// expected to perform conversions to the format requested by their
/// device.
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum Color {
    RGBA(f64, f64, f64, f64, f64)
}

/// Representation of an object in JSON. It is often (albeit not
/// always) possible to choose a more precise data structure for
/// representing values send/accepted by a service. If possible,
/// adapters should rather pick such more precise data structure.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Json(pub serde_json::value::Value);

impl PartialOrd for Json {
    /// Two Json objects are never comparable to each other.
    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
        None
    }
}

/// A data structure holding a numeric value of a type that has not
/// been standardized yet.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExtNumeric {
    pub value: f64,

    /// The vendor. Used for namespacing purposes, to avoid
    /// confusing two incompatible extensions with similar
    /// names. For instance, "foxlink@mozilla.com".
    pub vendor: String,

    /// Identification of the adapter introducing this value.
    /// Designed to aid with tracing and debugging.
    pub adapter: String,

    /// A string describing the nature of the value, designed to
    /// aid with type-checking.
    ///
    /// Examples: `"GroundHumidity"`.
    pub kind: String,
}

impl PartialOrd for ExtNumeric {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.vendor != other.vendor {
            return None;
        } else if self.kind != other.kind {
            return None;
        } else {
            self.value.partial_cmp(&other.value)
        }
    }
}

/// Representation of an actual value that can be sent to/received
/// from a service.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Value {
    Unit,
    Bool(bool),
    Duration(ValDuration),
    TimeStamp(TimeStamp),
    Temperature(Temperature),
    Color(Color),
    String(Arc<String>),

    // FIXME: Add more as we identify needs

    /// A numeric value representing a unit that has not been
    /// standardized yet into the API.
    ExtNumeric(ExtNumeric),

    /// A Json value. We put it behind an `Arc` to make sure that
    /// cloning remains unexpensive.
    Json(Arc<Json>),

    /// Binary data.
    Binary {
        /// The actual data. We put it behind an `Arc` to make sure
        /// that cloning remains unexpensive.
        data: Arc<Vec<u8>>,
        mimetype: String
    }
}

impl Value {
    pub fn get_type(&self) -> Type {
        match *self {
            Value::Unit => Type::Unit,
            Value::Bool(_) => Type::Bool,
            Value::String(_) => Type::String,
            Value::Duration(_) => Type::Duration,
            Value::TimeStamp(_) => Type::TimeStamp,
            Value::Temperature(_) => Type::Temperature,
            Value::Color(_) => Type::Color,
            Value::Json(_) => Type::Json,
            Value::Binary{..} => Type::Binary,
            Value::ExtNumeric(_) => Type::ExtNumeric,
        }
    }
}

impl PartialOrd for Value {
    /// Two values of the same type can be compared using the usual
    /// comparison for values of this type. Two values of distinct
    /// types cannot be compared.
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        use self::Value::*;
        use std::cmp::Ordering::*;
        match (self, other) {
            (&Unit, &Unit) => Some(Equal),
            (&Unit, _) => None,

            (&Bool(a), &Bool(b)) => a.partial_cmp(&b),
            (&Bool(_), _) => None,

            (&Duration(ref a), &Duration(ref b)) => a.partial_cmp(b),
            (&Duration(_), _) => None,

            (&TimeStamp(ref a), &TimeStamp(ref b)) => a.partial_cmp(b),
            (&TimeStamp(_), _) => None,

            (&Temperature(ref a), &Temperature(ref b)) => a.partial_cmp(b),
            (&Temperature(_), _) => None,

            (&Color(ref a), &Color(ref b)) => a.partial_cmp(b),
            (&Color(_), _) => None,

            (&ExtNumeric(ref a), &ExtNumeric(ref b)) => a.partial_cmp(b),
            (&ExtNumeric(_), _) => None,

            (&String(ref a), &String(ref b)) => a.partial_cmp(b),
            (&String(_), _) => None,

            (&Json(ref a), &Json(ref b)) => a.partial_cmp(b),
            (&Json(_), _) => None,

            (&Binary{mimetype: ref a_mimetype, data: ref a_data},
             &Binary{mimetype: ref b_mimetype, data: ref b_data}) if a_mimetype == b_mimetype => a_data.partial_cmp(b_data),
            (&Binary{..}, _) => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct ValDuration(Duration);
impl ValDuration {
    pub fn new(duration: Duration) -> Self {
        ValDuration(duration)
    }
}
impl Serialize for ValDuration {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        let as_ms : u64 = self.0.as_secs() * 1000
            + (self.0.subsec_nanos() as u64) / 1_000_000;
        as_ms.serialize(serializer)
    }
}
impl Deserialize for ValDuration {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        let as_sec : f64 = try!(f64::deserialize(deserializer));
        Ok(ValDuration(Duration::new(as_sec as u64, as_sec.fract() as u32)))
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct TimeStamp(chrono::DateTime<chrono::Local>);
impl TimeStamp {
    pub fn from_s(s: i64) -> Self {
        use chrono::*;
        let naive = chrono::naive::datetime::NaiveDateTime::from_timestamp(s, 0);
        let offset = chrono::offset::fixed::FixedOffset::east(0);
        let date = DateTime::<Local>::from_utc(naive, offset);
        TimeStamp(date)
    }
}
impl Serialize for TimeStamp {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        let str = self.0.to_rfc3339();
        str.serialize(serializer)
    }
}
impl Deserialize for TimeStamp {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        let str = try!(String::deserialize(deserializer));
        match chrono::DateTime::<chrono::Local>::from_str(&str) {
            Ok(dt) => Ok(TimeStamp(dt)),
            Err(_) => Err(D::Error::syntax("Invalid date"))
        }
    }
}
<|endoftext|>


<commit_before>use num::{ Float, ToPrimitive, FromPrimitive };
use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use dimensions::Dimensions;
use graphics;
use graphics::Graphics;
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use mouse::Mouse;
use point::Point;
use rectangle;
use rectangle::{
    Corner
};
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    map_range,
    val_to_string,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::Widget;

/// Represents the state of the xy_pad widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(XYPad, State, Widget::XYPad(State::Normal));

/// Check the current state of the button.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _                      => Normal,
    }
}

/// Draw the crosshair.
fn draw_crosshair<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    pos: Point,
    line_width: f64,
    vert_x: f64, hori_y: f64,
    pad_dim: Dimensions,
    color: Color
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    let Color(col) = color;
    let line = graphics::Line::new(col, 0.5 * line_width);
    line.draw(
        [vert_x, pos[1], vert_x, pos[1] + pad_dim[1]],
        draw_state,
        transform,
        graphics
    );
    line.draw(
        [pos[0], hori_y, pos[0] + pad_dim[0], hori_y],
        draw_state,
        transform,
        graphics
    );
}

/// A context on which the builder pattern can be implemented.
pub struct XYPad<'a, X, Y, F> {
    ui_id: UIID,
    x: X, min_x: X, max_x: X,
    y: Y, min_y: Y, max_y: Y,
    line_width: f64,
    font_size: FontSize,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl <'a, X, Y, F> XYPad<'a, X, Y, F> {
    #[inline]
    pub fn line_width(self, width: f64) -> XYPad<'a, X, Y, F> {
        XYPad { line_width: width, ..self }
    }
    #[inline]
    pub fn value_font_size(self, size: FontSize) -> XYPad<'a, X, Y, F> {
        XYPad { font_size: size, ..self }
    }
}

impl<'a, X, Y, F> XYPad<'a, X, Y, F> {
    /// An xy_pad builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID,
              x_val: X, min_x: X, max_x: X,
              y_val: Y, min_y: Y, max_y: Y) -> XYPad<'a, X, Y, F> {
        XYPad {
            ui_id: ui_id,
            x: x_val, min_x: min_x, max_x: max_x,
            y: y_val, min_y: min_y, max_y: max_y,
            line_width: 1.0,
            font_size: 18u32,
            pos: [0.0, 0.0],
            dim: [128.0, 128.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, X, Y, F> Colorable for XYPad<'a, X, Y, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, X, Y, F> Frameable for XYPad<'a, X, Y, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, X, Y, F> Callable<F> for XYPad<'a, X, Y, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

/*
quack! {
    xy_pad: XYPad['a, X, Y, F]
    get:
        fn () -> Size [] { Size(xy_pad.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::XYPad(State::Normal))
        }
        fn () -> Id [] { Id(xy_pad.ui_id) }
    set:
        fn (val: LabelText<'a>) [] { xy_pad.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { xy_pad.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { xy_pad.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { xy_pad.pos = val.0 }
        fn (val: Size) [] { xy_pad.dim = val.0 }
    action:
}
*/

impl<'a, X, Y, F> ::draw::Drawable for XYPad<'a, X, Y, F>
    where
        X: Float + ToPrimitive + FromPrimitive + ToString,
        Y: Float + ToPrimitive + FromPrimitive + ToString,
        F: FnMut(X, Y) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        // Init.
        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        let pad_dim = vec2_sub(self.dim, [frame_w2; 2]);
        let pad_pos = vec2_add(self.pos, [frame_w, frame_w]);
        let is_over_pad = rectangle::is_over(pad_pos, mouse.pos, pad_dim);
        let new_state = get_new_state(is_over_pad, state, mouse);

        // Determine new values.
        let (new_x, new_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) => (self.x, self.y),
            (_, State::Clicked) => {
                let temp_x = clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]);
                let temp_y = clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1]);
                (map_range(temp_x - self.pos[0], pad_dim[0], 0.0, self.min_x, self.max_x),
                 map_range(temp_y - self.pos[1], pad_dim[1], 0.0, self.min_y, self.max_y))
            }
        };

        // Callback if value is changed or the pad is clicked/released.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.x != new_x || self.y != new_y { (*callback)(new_x, new_y) }
                else {
                    match (state, new_state) {
                        (State::Highlighted, State::Clicked)
                        | (State::Clicked, State::Highlighted) => (*callback)(new_x, new_y),
                        _ => (),
                    }
                }
            },
            None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state, self.pos,
                        self.dim, maybe_frame, color);
        let (vert_x, hori_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) =>
                (pad_pos[0] + map_range(new_x, self.min_x, self.max_x, pad_dim[0], 0.0),
                 pad_pos[1] + map_range(new_y, self.min_y, self.max_y, pad_dim[1], 0.0)),
            (_, State::Clicked) =>
                (clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]),
                 clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1])),
        };
        // Crosshair.
        draw_crosshair(uic.win_w, uic.win_h, graphics, pad_pos, self.line_width,
                       vert_x, hori_y, pad_dim, color.plain_contrast());
        // Label.
        if let Some(l_text) = self.maybe_label {
            let l_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let l_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let l_w = label::width(uic, l_size, l_text);
            let l_x = pad_pos[0] + (pad_dim[0] - l_w) / 2.0;
            let l_y = pad_pos[1] + (pad_dim[1] - l_size as f64) / 2.0;
            let l_pos = [l_x, l_y];
            uic.draw_text(graphics, l_pos, l_size, l_color, l_text);
        }
        // xy value string.
        let x_string = val_to_string(self.x, self.max_x,
                                     self.max_x - self.min_x, self.dim[0] as usize);
        let y_string = val_to_string(self.y, self.max_y,
                                     self.max_y - self.min_y, self.dim[1] as usize);
        let xy_string = format!("{}, {}", x_string, y_string);
        let xy_string_w = label::width(uic, self.font_size, &xy_string);
        let xy_string_pos = {
            match rectangle::corner(pad_pos, [vert_x, hori_y], pad_dim) {
                Corner::TopLeft => [vert_x, hori_y],
                Corner::TopRight => [vert_x - xy_string_w, hori_y],
                Corner::BottomLeft => [vert_x, hori_y - self.font_size as f64],
                Corner::BottomRight => [vert_x - xy_string_w, hori_y - self.font_size as f64],
            }
        };
        uic.draw_text(graphics, xy_string_pos, self.font_size,
                    color.plain_contrast(), &xy_string);

        set_state(uic, self.ui_id, Widget::XYPad(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implement `Labelable` for `XYPad`<commit_after>use num::{ Float, ToPrimitive, FromPrimitive };
use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use label::{ FontSize, Labelable };
use dimensions::Dimensions;
use graphics;
use graphics::Graphics;
use graphics::character::CharacterCache;
use label;
use mouse::Mouse;
use point::Point;
use rectangle;
use rectangle::{
    Corner
};
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    map_range,
    val_to_string,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::Widget;

/// Represents the state of the xy_pad widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(XYPad, State, Widget::XYPad(State::Normal));

/// Check the current state of the button.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _                      => Normal,
    }
}

/// Draw the crosshair.
fn draw_crosshair<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    pos: Point,
    line_width: f64,
    vert_x: f64, hori_y: f64,
    pad_dim: Dimensions,
    color: Color
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    let Color(col) = color;
    let line = graphics::Line::new(col, 0.5 * line_width);
    line.draw(
        [vert_x, pos[1], vert_x, pos[1] + pad_dim[1]],
        draw_state,
        transform,
        graphics
    );
    line.draw(
        [pos[0], hori_y, pos[0] + pad_dim[0], hori_y],
        draw_state,
        transform,
        graphics
    );
}

/// A context on which the builder pattern can be implemented.
pub struct XYPad<'a, X, Y, F> {
    ui_id: UIID,
    x: X, min_x: X, max_x: X,
    y: Y, min_y: Y, max_y: Y,
    line_width: f64,
    font_size: FontSize,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl <'a, X, Y, F> XYPad<'a, X, Y, F> {
    #[inline]
    pub fn line_width(self, width: f64) -> XYPad<'a, X, Y, F> {
        XYPad { line_width: width, ..self }
    }
    #[inline]
    pub fn value_font_size(self, size: FontSize) -> XYPad<'a, X, Y, F> {
        XYPad { font_size: size, ..self }
    }
}

impl<'a, X, Y, F> XYPad<'a, X, Y, F> {
    /// An xy_pad builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID,
              x_val: X, min_x: X, max_x: X,
              y_val: Y, min_y: Y, max_y: Y) -> XYPad<'a, X, Y, F> {
        XYPad {
            ui_id: ui_id,
            x: x_val, min_x: min_x, max_x: max_x,
            y: y_val, min_y: min_y, max_y: max_y,
            line_width: 1.0,
            font_size: 18u32,
            pos: [0.0, 0.0],
            dim: [128.0, 128.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, X, Y, F> Colorable for XYPad<'a, X, Y, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, X, Y, F> Frameable for XYPad<'a, X, Y, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, X, Y, F> Callable<F> for XYPad<'a, X, Y, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

impl<'a, X, Y, F> Labelable<'a> for XYPad<'a, X, Y, F>
{
    fn label(mut self, text: &'a str) -> Self {
        self.maybe_label = Some(text);
        self
    }

    fn label_color(mut self, color: Color) -> Self {
        self.maybe_label_color = Some(color);
        self
    }

    fn label_font_size(mut self, size: FontSize) -> Self {
        self.maybe_label_font_size = Some(size);
        self
    }
}

/*
quack! {
    xy_pad: XYPad['a, X, Y, F]
    get:
        fn () -> Size [] { Size(xy_pad.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::XYPad(State::Normal))
        }
        fn () -> Id [] { Id(xy_pad.ui_id) }
    set:
        fn (val: Position) [] { xy_pad.pos = val.0 }
        fn (val: Size) [] { xy_pad.dim = val.0 }
    action:
}
*/

impl<'a, X, Y, F> ::draw::Drawable for XYPad<'a, X, Y, F>
    where
        X: Float + ToPrimitive + FromPrimitive + ToString,
        Y: Float + ToPrimitive + FromPrimitive + ToString,
        F: FnMut(X, Y) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        // Init.
        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        let pad_dim = vec2_sub(self.dim, [frame_w2; 2]);
        let pad_pos = vec2_add(self.pos, [frame_w, frame_w]);
        let is_over_pad = rectangle::is_over(pad_pos, mouse.pos, pad_dim);
        let new_state = get_new_state(is_over_pad, state, mouse);

        // Determine new values.
        let (new_x, new_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) => (self.x, self.y),
            (_, State::Clicked) => {
                let temp_x = clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]);
                let temp_y = clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1]);
                (map_range(temp_x - self.pos[0], pad_dim[0], 0.0, self.min_x, self.max_x),
                 map_range(temp_y - self.pos[1], pad_dim[1], 0.0, self.min_y, self.max_y))
            }
        };

        // Callback if value is changed or the pad is clicked/released.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.x != new_x || self.y != new_y { (*callback)(new_x, new_y) }
                else {
                    match (state, new_state) {
                        (State::Highlighted, State::Clicked)
                        | (State::Clicked, State::Highlighted) => (*callback)(new_x, new_y),
                        _ => (),
                    }
                }
            },
            None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state, self.pos,
                        self.dim, maybe_frame, color);
        let (vert_x, hori_y) = match (is_over_pad, new_state) {
            (_, State::Normal) | (_, State::Highlighted) =>
                (pad_pos[0] + map_range(new_x, self.min_x, self.max_x, pad_dim[0], 0.0),
                 pad_pos[1] + map_range(new_y, self.min_y, self.max_y, pad_dim[1], 0.0)),
            (_, State::Clicked) =>
                (clamp(mouse.pos[0], pad_pos[0], pad_pos[0] + pad_dim[0]),
                 clamp(mouse.pos[1], pad_pos[1], pad_pos[1] + pad_dim[1])),
        };
        // Crosshair.
        draw_crosshair(uic.win_w, uic.win_h, graphics, pad_pos, self.line_width,
                       vert_x, hori_y, pad_dim, color.plain_contrast());
        // Label.
        if let Some(l_text) = self.maybe_label {
            let l_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let l_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let l_w = label::width(uic, l_size, l_text);
            let l_x = pad_pos[0] + (pad_dim[0] - l_w) / 2.0;
            let l_y = pad_pos[1] + (pad_dim[1] - l_size as f64) / 2.0;
            let l_pos = [l_x, l_y];
            uic.draw_text(graphics, l_pos, l_size, l_color, l_text);
        }
        // xy value string.
        let x_string = val_to_string(self.x, self.max_x,
                                     self.max_x - self.min_x, self.dim[0] as usize);
        let y_string = val_to_string(self.y, self.max_y,
                                     self.max_y - self.min_y, self.dim[1] as usize);
        let xy_string = format!("{}, {}", x_string, y_string);
        let xy_string_w = label::width(uic, self.font_size, &xy_string);
        let xy_string_pos = {
            match rectangle::corner(pad_pos, [vert_x, hori_y], pad_dim) {
                Corner::TopLeft => [vert_x, hori_y],
                Corner::TopRight => [vert_x - xy_string_w, hori_y],
                Corner::BottomLeft => [vert_x, hori_y - self.font_size as f64],
                Corner::BottomRight => [vert_x - xy_string_w, hori_y - self.font_size as f64],
            }
        };
        uic.draw_text(graphics, xy_string_pos, self.font_size,
                    color.plain_contrast(), &xy_string);

        set_state(uic, self.ui_id, Widget::XYPad(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "read")]
use alloc::boxed::Box;
#[cfg(feature = "read")]
use alloc::vec::Vec;
use core::fmt;
use core::mem::MaybeUninit;
use core::ops;
use core::ptr;
use core::slice;

mod sealed {
    // SAFETY: Implementer must not modify the content in storage.
    pub unsafe trait Sealed {
        type Storage;

        fn new_storage() -> Self::Storage;

        fn grow(_storage: &mut Self::Storage, _additional: usize) -> Result<(), CapacityFull> {
            Err(CapacityFull)
        }
    }

    #[derive(Clone, Copy, Debug)]
    pub struct CapacityFull;
}

use sealed::*;

/// Marker trait for types that can be used as backing storage when a growable array type is needed.
///
/// This trait is sealed and cannot be implemented for types outside this crate.
pub trait ArrayLike: Sealed {
    /// Type of the elements being stored.
    type Item;

    #[doc(hidden)]
    fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<Self::Item>];

    #[doc(hidden)]
    fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<Self::Item>];
}

// Use macro since const generics can't be used due to MSRV.
macro_rules! impl_array {
    () => {};
    ($n:literal $($rest:tt)*) => {
        // SAFETY: does not modify the content in storage.
        unsafe impl<T> Sealed for [T; $n] {
            type Storage = [MaybeUninit<T>; $n];

            fn new_storage() -> Self::Storage {
                // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
                unsafe { MaybeUninit::uninit().assume_init() }
            }
        }

        impl<T> ArrayLike for [T; $n] {
            type Item = T;

            fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
                storage
            }

            fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
                storage
            }
        }

        impl_array!($($rest)*);
    }
}

impl_array!(0 1 2 3 4 8 16 32 64 128 192);

#[cfg(feature = "read")]
unsafe impl<T> Sealed for Vec<T> {
    type Storage = Box<[MaybeUninit<T>]>;

    fn new_storage() -> Self::Storage {
        Box::new([])
    }

    fn grow(storage: &mut Self::Storage, additional: usize) -> Result<(), CapacityFull> {
        let mut vec: Vec<_> = core::mem::replace(storage, Box::new([])).into();
        vec.reserve(additional);
        // SAFETY: This is a `Vec` of `MaybeUninit`.
        unsafe { vec.set_len(vec.capacity()) };
        *storage = vec.into_boxed_slice();
        Ok(())
    }
}

#[cfg(feature = "read")]
impl<T> ArrayLike for Vec<T> {
    type Item = T;

    fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
        storage
    }

    fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
        storage
    }
}

pub(crate) struct ArrayVec {
    storage: A::Storage,
    len: usize,
}

impl ArrayVec {
    pub fn new() -> Self {
        Self {
            storage: A::new_storage(),
            len: 0,
        }
    }

    pub fn clear(&mut self) {
        let ptr: *mut [A::Item] = &mut **self;
        // Set length first so the type invariant is upheld even if `drop_in_place` panicks.
        self.len = 0;
        // SAFETY: `ptr` contains valid elements only and we "forget" them by setting the length.
        unsafe { ptr::drop_in_place(ptr) };
    }

    pub fn try_push(&mut self, value: A::Item) -> Result<(), CapacityFull> {
        let mut storage = A::as_mut_slice(&mut self.storage);
        if self.len >= storage.len() {
            A::grow(&mut self.storage, 1)?;
            storage = A::as_mut_slice(&mut self.storage);
        }

        storage[self.len] = MaybeUninit::new(value);
        self.len += 1;
        Ok(())
    }

    pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), CapacityFull> {
        assert!(index <= self.len);

        let mut storage = A::as_mut_slice(&mut self.storage);
        if self.len >= storage.len() {
            A::grow(&mut self.storage, 1)?;
            storage = A::as_mut_slice(&mut self.storage);
        }

        // SAFETY: storage[index] is filled later.
        unsafe {
            let p = storage.as_mut_ptr().add(index);
            core::ptr::copy(p as *const _, p.add(1), self.len - index);
        }
        storage[index] = MaybeUninit::new(element);
        self.len += 1;
        Ok(())
    }

    pub fn pop(&mut self) -> Option {
        if self.len == 0 {
            None
        } else {
            self.len -= 1;
            // SAFETY: this element is valid and we "forget" it by setting the length.
            Some(unsafe { A::as_slice(&mut self.storage)[self.len].as_ptr().read() })
        }
    }

    pub fn swap_remove(&mut self, index: usize) -> A::Item {
        assert!(self.len > 0);
        A::as_mut_slice(&mut self.storage).swap(index, self.len - 1);
        self.pop().unwrap()
    }
}

#[cfg(feature = "read")]
impl<T> ArrayVec<Vec<T>> {
    pub fn into_vec(mut self) -> Vec<T> {
        let storage = core::mem::replace(&mut self.storage, Box::new([]));
        let slice = Box::leak(storage);
        // SAFETY: valid elements.
        unsafe { Vec::from_raw_parts(slice.as_ptr() as _, self.len, slice.len()) }
    }
}

impl Drop for ArrayVec {
    fn drop(&mut self) {
        self.clear();
    }
}

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

impl ops::Deref for ArrayVec {
    type Target = [A::Item];

    fn deref(&self) -> &[A::Item] {
        let slice = &A::as_slice(&self.storage);
        // SAFETY: valid elements.
        unsafe { slice::from_raw_parts(slice.as_ptr() as _, self.len) }
    }
}

impl ops::DerefMut for ArrayVec {
    fn deref_mut(&mut self) -> &mut [A::Item] {
        let slice = &mut A::as_mut_slice(&mut self.storage);
        // SAFETY: valid elements.
        unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as _, self.len) }
    }
}

impl Clone for ArrayVec
where
    A::Item: Clone,
{
    fn clone(&self) -> Self {
        let mut new = Self::default();
        for value in &**self {
            new.try_push(value.clone()).unwrap();
        }
        new
    }
}

impl PartialEq for ArrayVec
where
    A::Item: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        **self == **other
    }
}

impl Eq for ArrayVec where A::Item: Eq {}

impl fmt::Debug for ArrayVec
where
    A::Item: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}
<commit_msg>Fix segfault in ArrayVec<Vec<T>>::into_vec (#601)<commit_after>#[cfg(feature = "read")]
use alloc::boxed::Box;
#[cfg(feature = "read")]
use alloc::vec::Vec;
use core::fmt;
use core::mem::MaybeUninit;
use core::ops;
use core::ptr;
use core::slice;

mod sealed {
    // SAFETY: Implementer must not modify the content in storage.
    pub unsafe trait Sealed {
        type Storage;

        fn new_storage() -> Self::Storage;

        fn grow(_storage: &mut Self::Storage, _additional: usize) -> Result<(), CapacityFull> {
            Err(CapacityFull)
        }
    }

    #[derive(Clone, Copy, Debug)]
    pub struct CapacityFull;
}

use sealed::*;

/// Marker trait for types that can be used as backing storage when a growable array type is needed.
///
/// This trait is sealed and cannot be implemented for types outside this crate.
pub trait ArrayLike: Sealed {
    /// Type of the elements being stored.
    type Item;

    #[doc(hidden)]
    fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<Self::Item>];

    #[doc(hidden)]
    fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<Self::Item>];
}

// Use macro since const generics can't be used due to MSRV.
macro_rules! impl_array {
    () => {};
    ($n:literal $($rest:tt)*) => {
        // SAFETY: does not modify the content in storage.
        unsafe impl<T> Sealed for [T; $n] {
            type Storage = [MaybeUninit<T>; $n];

            fn new_storage() -> Self::Storage {
                // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
                unsafe { MaybeUninit::uninit().assume_init() }
            }
        }

        impl<T> ArrayLike for [T; $n] {
            type Item = T;

            fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
                storage
            }

            fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
                storage
            }
        }

        impl_array!($($rest)*);
    }
}

impl_array!(0 1 2 3 4 8 16 32 64 128 192);

#[cfg(feature = "read")]
unsafe impl<T> Sealed for Vec<T> {
    type Storage = Box<[MaybeUninit<T>]>;

    fn new_storage() -> Self::Storage {
        Box::new([])
    }

    fn grow(storage: &mut Self::Storage, additional: usize) -> Result<(), CapacityFull> {
        let mut vec: Vec<_> = core::mem::replace(storage, Box::new([])).into();
        vec.reserve(additional);
        // SAFETY: This is a `Vec` of `MaybeUninit`.
        unsafe { vec.set_len(vec.capacity()) };
        *storage = vec.into_boxed_slice();
        Ok(())
    }
}

#[cfg(feature = "read")]
impl<T> ArrayLike for Vec<T> {
    type Item = T;

    fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
        storage
    }

    fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
        storage
    }
}

pub(crate) struct ArrayVec {
    storage: A::Storage,
    len: usize,
}

impl ArrayVec {
    pub fn new() -> Self {
        Self {
            storage: A::new_storage(),
            len: 0,
        }
    }

    pub fn clear(&mut self) {
        let ptr: *mut [A::Item] = &mut **self;
        // Set length first so the type invariant is upheld even if `drop_in_place` panicks.
        self.len = 0;
        // SAFETY: `ptr` contains valid elements only and we "forget" them by setting the length.
        unsafe { ptr::drop_in_place(ptr) };
    }

    pub fn try_push(&mut self, value: A::Item) -> Result<(), CapacityFull> {
        let mut storage = A::as_mut_slice(&mut self.storage);
        if self.len >= storage.len() {
            A::grow(&mut self.storage, 1)?;
            storage = A::as_mut_slice(&mut self.storage);
        }

        storage[self.len] = MaybeUninit::new(value);
        self.len += 1;
        Ok(())
    }

    pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), CapacityFull> {
        assert!(index <= self.len);

        let mut storage = A::as_mut_slice(&mut self.storage);
        if self.len >= storage.len() {
            A::grow(&mut self.storage, 1)?;
            storage = A::as_mut_slice(&mut self.storage);
        }

        // SAFETY: storage[index] is filled later.
        unsafe {
            let p = storage.as_mut_ptr().add(index);
            core::ptr::copy(p as *const _, p.add(1), self.len - index);
        }
        storage[index] = MaybeUninit::new(element);
        self.len += 1;
        Ok(())
    }

    pub fn pop(&mut self) -> Option {
        if self.len == 0 {
            None
        } else {
            self.len -= 1;
            // SAFETY: this element is valid and we "forget" it by setting the length.
            Some(unsafe { A::as_slice(&mut self.storage)[self.len].as_ptr().read() })
        }
    }

    pub fn swap_remove(&mut self, index: usize) -> A::Item {
        assert!(self.len > 0);
        A::as_mut_slice(&mut self.storage).swap(index, self.len - 1);
        self.pop().unwrap()
    }
}

#[cfg(feature = "read")]
impl<T> ArrayVec<Vec<T>> {
    pub fn into_vec(mut self) -> Vec<T> {
        let len = core::mem::replace(&mut self.len, 0);
        let storage = core::mem::replace(&mut self.storage, Box::new([]));
        let slice = Box::leak(storage);
        debug_assert!(len <= slice.len());
        // SAFETY: valid elements.
        unsafe { Vec::from_raw_parts(slice.as_ptr() as _, len, slice.len()) }
    }
}

impl Drop for ArrayVec {
    fn drop(&mut self) {
        self.clear();
    }
}

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

impl ops::Deref for ArrayVec {
    type Target = [A::Item];

    fn deref(&self) -> &[A::Item] {
        let slice = &A::as_slice(&self.storage);
        debug_assert!(self.len <= slice.len());
        // SAFETY: valid elements.
        unsafe { slice::from_raw_parts(slice.as_ptr() as _, self.len) }
    }
}

impl ops::DerefMut for ArrayVec {
    fn deref_mut(&mut self) -> &mut [A::Item] {
        let slice = &mut A::as_mut_slice(&mut self.storage);
        debug_assert!(self.len <= slice.len());
        // SAFETY: valid elements.
        unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as _, self.len) }
    }
}

impl Clone for ArrayVec
where
    A::Item: Clone,
{
    fn clone(&self) -> Self {
        let mut new = Self::default();
        for value in &**self {
            new.try_push(value.clone()).unwrap();
        }
        new
    }
}

impl PartialEq for ArrayVec
where
    A::Item: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        **self == **other
    }
}

impl Eq for ArrayVec where A::Item: Eq {}

impl fmt::Debug for ArrayVec
where
    A::Item: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}
<|endoftext|>