<commit_before>use traitdefs::{Float, Point, Vector};
use std::convert::{AsRef, AsMut, From};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::fmt::{Debug, Formatter};
use std::ops::Range;

use super::{BezCurve, Point2d, Vector2d, lerp};

/// A struct that contains range information for slicing, used for slicing into the global factor
/// vector. The reason this is used instead of stdlib's `Range` struct is that `Range` does not
/// implement Copy, which means we have to use `RefCell`s instead of `Cell`s for interior mutability.
#[derive(Copy, Clone)]
struct RangeSlice {
    start: usize,
    end: usize
}

impl RangeSlice {
    #[inline]
    fn new(start: usize, end: usize) -> RangeSlice {
        RangeSlice {
            start: start,
            end: end
        }
    }

    fn as_range(&self) -> Range<usize> {
        self.start..self.end
    }

    fn len(&self) -> usize {
        self.end - self.start
    }
}

fn combination(n: u64, k: u64) -> u64 {
    factorial(n) / (factorial(k) * factorial(n - k))
}

fn factorial(mut n: u64) -> u64 {
    let mut accumulator: u64 = 1;
    while n > 0 {
        accumulator = accumulator.checked_mul(n).expect("Attempted to create Bézier curve with combination that overflow u64; decrease curve order");
        n -= 1;
    }
    accumulator
}

/// Given the `order` and references to the `factors`, `dfactors`, and `vec` cells, update the
/// cells to contain accurate information about the factors of the order.
fn update_factors(order: usize, factors: &Cell<RangeSlice>, dfactors: &Cell<RangeSlice>, vec: &RefCell<Vec<u64>>) {
    if factors.get().len() != order + 1 {
        let mut vec = vec.borrow_mut();
        // Remove everything from the vector without freeing memory
        unsafe{ vec.set_len(0) };

        // The vector stores both the factors of the order and the order's derivative, and this is the
        // length necessary to contain those factors.
        let new_len = (order + 1) * 2 - 1;
        if vec.capacity() < new_len {
            let reserve_amount = new_len - vec.capacity();
            vec.reserve(reserve_amount);
        }

        {
            let order = order as u64;

            for k in 0..order + 1 {
                vec.push(combination(order, k));
            }

            for k in 0..order {
                vec.push(combination(order - 1, k));
            }
        }

        factors.set(RangeSlice::new(0, order + 1));
        dfactors.set(RangeSlice::new(order + 1, vec.len()));
    }
}

/// An n-order bezier curve
#[derive(Clone)]
pub struct NBez<F, P = Point2d<F>, V = Vector2d<F>, C = Vec<P>>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    points: C,
    factor_vec: RefCell<Vec<u64>>,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,
    phantom: PhantomData<(F, P, V)>
}

impl<F, P, V, C> From<C> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    fn from(container: C) -> NBez<F, P, V, C> {
        NBez::from_container(container)
    }
}

impl<F, P, V, C> NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    #[inline]
    pub fn from_container(points: C) -> NBez<F, P, V, C> {
        if points.as_ref().len() >= 22 {
            panic!("Cannot create Bézier polynomials with an order >= 21")
        }

        NBez {
            points: points,
            factor_vec: RefCell::new(Vec::new()),
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),
            phantom: PhantomData
        }
    }

    #[inline]
    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<F, P, V, C> BezCurve<F> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    type Point = P;
    type Vector = V;
    type Elevated = NBez<F, P, V, Vec<P>>;

    /// Currently non-functional; returns `None`
    fn from_slice(_: &[P]) -> Option<NBez<F, P, V, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> P {
        let points = self.points.as_ref();
        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);
        let factors = &self.factor_vec.borrow()[self.factors.get().as_range()];

        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = factors.len() - 1;
        let mut acc = P::zero();
        let mut factor = 0;

        for point in points.iter() {
            acc = acc + *point *
                        t.powi(factor as i32) *
                        t1.powi((order - factor) as i32) *
                        F::from_u64(factors[factor]).unwrap();
            factor += 1;
        }
        acc
    }

    fn slope_unbounded(&self, t: F) -> V {
        let points = self.points.as_ref();
        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);
        let dfactors = &self.factor_vec.borrow()[self.dfactors.get().as_range()];

        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = dfactors.len() - 1;
        let mut acc = P::zero();
        let mut factor = 0;
        let mut point_last = points[0].clone();

        for point in points[1..].iter().map(|p| *p) {
            acc = acc + (point - point_last) *
                        t.powi(factor as i32) *
                        t1.powi((order-factor) as i32) *
                        F::from_u64(dfactors[factor] * (order + 1) as u64).unwrap();
            point_last = point;
            factor += 1;
        }
        acc.into()
    }

    fn elevate(&self) -> NBez<F, P, V, Vec<P>> {
        let points = self.points.as_ref();
        let order = self.order() + 1;
        let order_f = F::from_usize(order).unwrap();

        // Elevated points
        let mut el_points = Vec::with_capacity(order + 1);
        el_points.push(points[0]);

        let mut prev_p = points[0];
        for (i, p) in points[1..].iter().map(|p| *p).enumerate() {
            el_points.push(lerp(p, prev_p, F::from_usize(i).unwrap()/order_f));

            prev_p = p;
        }

        el_points.push(points[self.order()]);
        NBez::from_container(el_points)
    }

    /// Currently non-functional; returns `None`
    fn split(&self, _: F) -> Option<(NBez<F, P, V, C>, NBez<F, P, V, C>)> {
        None
    }

    fn order(&self) -> usize {
        self.points.as_ref().len()-1
    }
}

impl<F, P, V, C> AsRef<C> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, P, V, C> AsMut<C> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

impl<F, P, V, C> Debug for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        f.debug_tuple("NBez")
            .field(&self.points)
            .finish()
    }
}
<commit_msg>Fixed bug with nbez elevation<commit_after>use traitdefs::{Float, Point, Vector};
use std::convert::{AsRef, AsMut, From};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
use std::fmt::{Debug, Formatter};
use std::ops::Range;

use super::{BezCurve, Point2d, Vector2d, lerp};

/// A struct that contains range information for slicing, used for slicing into the global factor
/// vector. The reason this is used instead of stdlib's `Range` struct is that `Range` does not
/// implement Copy, which means we have to use `RefCell`s instead of `Cell`s for interior mutability.
#[derive(Copy, Clone)]
struct RangeSlice {
    start: usize,
    end: usize
}

impl RangeSlice {
    #[inline]
    fn new(start: usize, end: usize) -> RangeSlice {
        RangeSlice {
            start: start,
            end: end
        }
    }

    fn as_range(&self) -> Range<usize> {
        self.start..self.end
    }

    fn len(&self) -> usize {
        self.end - self.start
    }
}

fn combination(n: u64, k: u64) -> u64 {
    factorial(n) / (factorial(k) * factorial(n - k))
}

fn factorial(mut n: u64) -> u64 {
    let mut accumulator: u64 = 1;
    while n > 0 {
        accumulator = accumulator.checked_mul(n).expect("Attempted to create Bézier curve with combination that overflow u64; decrease curve order");
        n -= 1;
    }
    accumulator
}

/// Given the `order` and references to the `factors`, `dfactors`, and `vec` cells, update the
/// cells to contain accurate information about the factors of the order.
fn update_factors(order: usize, factors: &Cell<RangeSlice>, dfactors: &Cell<RangeSlice>, vec: &RefCell<Vec<u64>>) {
    if factors.get().len() != order + 1 {
        let mut vec = vec.borrow_mut();
        // Remove everything from the vector without freeing memory
        unsafe{ vec.set_len(0) };

        // The vector stores both the factors of the order and the order's derivative, and this is the
        // length necessary to contain those factors.
        let new_len = (order + 1) * 2 - 1;
        if vec.capacity() < new_len {
            let reserve_amount = new_len - vec.capacity();
            vec.reserve(reserve_amount);
        }

        {
            let order = order as u64;

            for k in 0..order + 1 {
                vec.push(combination(order, k));
            }

            for k in 0..order {
                vec.push(combination(order - 1, k));
            }
        }

        factors.set(RangeSlice::new(0, order + 1));
        dfactors.set(RangeSlice::new(order + 1, vec.len()));
    }
}

/// An n-order bezier curve
#[derive(Clone)]
pub struct NBez<F, P = Point2d<F>, V = Vector2d<F>, C = Vec<P>>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    points: C,
    factor_vec: RefCell<Vec<u64>>,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,
    phantom: PhantomData<(F, P, V)>
}

impl<F, P, V, C> From<C> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    fn from(container: C) -> NBez<F, P, V, C> {
        NBez::from_container(container)
    }
}

impl<F, P, V, C> NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    #[inline]
    pub fn from_container(points: C) -> NBez<F, P, V, C> {
        if points.as_ref().len() >= 22 {
            panic!("Cannot create Bézier polynomials with an order >= 21")
        }

        NBez {
            points: points,
            factor_vec: RefCell::new(Vec::new()),
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),
            phantom: PhantomData
        }
    }

    #[inline]
    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<F, P, V, C> BezCurve<F> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    type Point = P;
    type Vector = V;
    type Elevated = NBez<F, P, V, Vec<P>>;

    /// Currently non-functional; returns `None`
    fn from_slice(_: &[P]) -> Option<NBez<F, P, V, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> P {
        let points = self.points.as_ref();
        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);
        let factors = &self.factor_vec.borrow()[self.factors.get().as_range()];

        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = factors.len() - 1;
        let mut acc = P::zero();
        let mut factor = 0;

        for point in points.iter() {
            acc = acc + *point *
                        t.powi(factor as i32) *
                        t1.powi((order - factor) as i32) *
                        F::from_u64(factors[factor]).unwrap();
            factor += 1;
        }
        acc
    }

    fn slope_unbounded(&self, t: F) -> V {
        let points = self.points.as_ref();
        update_factors(self.order(), &self.factors, &self.dfactors, &self.factor_vec);
        let dfactors = &self.factor_vec.borrow()[self.dfactors.get().as_range()];

        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = dfactors.len() - 1;
        let mut acc = P::zero();
        let mut factor = 0;
        let mut point_last = points[0].clone();

        for point in points[1..].iter().map(|p| *p) {
            acc = acc + (point - point_last) *
                        t.powi(factor as i32) *
                        t1.powi((order-factor) as i32) *
                        F::from_u64(dfactors[factor] * (order + 1) as u64).unwrap();
            point_last = point;
            factor += 1;
        }
        acc.into()
    }

    fn elevate(&self) -> NBez<F, P, V, Vec<P>> {
        let points = self.points.as_ref();
        let order = self.order() + 1;
        let order_f = F::from_usize(order).unwrap();

        // Elevated points
        let mut el_points = Vec::with_capacity(order + 1);
        el_points.push(points[0]);

        let mut prev_p = points[0];
        for (i, p) in points.iter().map(|p| *p).enumerate().skip(1) {
            el_points.push(lerp(p, prev_p, F::from_usize(i).unwrap()/order_f));

            prev_p = p;
        }

        el_points.push(points[self.order()]);
        NBez::from_container(el_points)
    }

    /// Currently non-functional; returns `None`
    fn split(&self, _: F) -> Option<(NBez<F, P, V, C>, NBez<F, P, V, C>)> {
        None
    }

    fn order(&self) -> usize {
        self.points.as_ref().len()-1
    }
}

impl<F, P, V, C> AsRef<C> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, P, V, C> AsMut<C> for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

impl<F, P, V, C> Debug for NBez<F, P, V, C>
        where F: Float,
              P: Point<F, V>,
              V: Vector<F>,
              C: AsRef<[P]> + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        f.debug_tuple("NBez")
            .field(&self.points)
            .finish()
    }
}
<|endoftext|>


<commit_before>#[doc="
    The content task is the main task that runs JavaScript and spawns layout
    tasks.
"]

export ContentTask;
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg;
export PingMsg, PongMsg;

import std::arc::{arc, clone};
import comm::{Port, Chan, port, chan, listen, select2};
import task::{spawn, spawn_listener};
import io::{read_whole_file, println};
import result::{ok, err};

import dom::base::{Document, Node, NodeScope, Window, define_bindings};
import dom::event::{Event, ResizeEvent};
import dom::style;
import dom::style::Stylesheet;
import gfx::compositor::Compositor;
import parser::html_lexer::spawn_html_lexer_task;
import parser::html_builder::build_dom;
import layout::layout_task;
import layout_task::{LayoutTask, BuildMsg};

import jsrt = js::rust::rt;
import js::rust::methods;
import js::global::{global_class, debug_fns};

import either::{Either, Left, Right};

import dom::bindings::utils::rust_box;
import js::rust::compartment;

import resource::resource_task;
import resource_task::{ResourceTask};

import std::net::url::url;
import url_to_str = std::net::url::to_str;
import util::url::make_url;

enum ControlMsg {
    ParseMsg(url),
    ExecuteMsg(url),
    ExitMsg
}

enum PingMsg {
    PongMsg
}

type ContentTask = Chan<ControlMsg>;

fn ContentTask<S: Compositor send copy>(layout_task: LayoutTask, +compositor: S, resource_task: ResourceTask) -> ContentTask {
    do spawn_listener::<ControlMsg> |from_master| {
        Content(layout_task, compositor, from_master, resource_task).start();
    }
}

#[doc="Sends a ping to layout and waits for the response."]
#[allow(non_implicitly_copyable_typarams)]
fn join_layout(scope: NodeScope, layout_task: LayoutTask) {

    if scope.is_reader_forked() {
        listen(|response_from_layout| {
            layout_task.send(layout_task::PingMsg(response_from_layout));
            response_from_layout.recv();
        });
        scope.reader_joined();
    }
}

struct Content<C:Compositor> {
    let compositor: C;
    let layout_task: LayoutTask;
    let from_master: comm::Port<ControlMsg>;
    let event_port: comm::Port<Event>;

    let scope: NodeScope;
    let jsrt: jsrt;

    let mut document: option<@Document>;
    let mut window:   option<@Window>;
    let mut doc_url: option<url>;

    let resource_task: ResourceTask;

    new(layout_task: LayoutTask, +compositor: C, from_master: Port<ControlMsg>,
        resource_task: ResourceTask) {
        self.layout_task = layout_task;
        self.compositor = compositor;
        self.from_master = from_master;
        self.event_port = port();

        self.scope = NodeScope();
        self.jsrt = jsrt();

        self.document = none;
        self.window   = none;
        self.doc_url  = none;

        self.compositor.add_event_listener(self.event_port.chan());

        self.resource_task = resource_task;
    }

    fn start() {
        while self.handle_msg(select2(self.from_master, self.event_port)) {
            // Go on...
        }
    }

    fn handle_msg(msg: Either<ControlMsg,Event>) -> bool {
        match msg {
            Left(control_msg) => self.handle_control_msg(control_msg),
            Right(event) => self.handle_event(event)
        }
    }

    fn handle_control_msg(control_msg: ControlMsg) -> bool {
        match control_msg {
          ParseMsg(url) => {
            #debug["content: Received url `%s` to parse", url_to_str(url)];

            // Note: we can parse the next document in parallel
            // with any previous documents.
            let stream = spawn_html_lexer_task(copy url, self.resource_task);
            let (root, style_port, js_port) = build_dom(self.scope, stream, url,
                                                        self.resource_task);
            let css_rules = style_port.recv();
            let js_scripts = js_port.recv();

            // Apply the css rules to the dom tree:
            #debug["css_rules: %?", css_rules];

            #debug["js_scripts: %?", js_scripts];

            let document = Document(root, css_rules);
            let window   = Window();
            self.relayout(document, &url);
            self.document = some(@document);
            self.window   = some(@window);
            self.doc_url = some(copy url);

            //XXXjdm it was easier to duplicate the relevant ExecuteMsg code;
            //       they should be merged somehow in the future.
            for vec::each(js_scripts) |bytes| {
                let cx = self.jsrt.cx();
                cx.set_default_options_and_version();
                cx.set_logging_error_reporter();
                cx.new_compartment(global_class).chain(|compartment| {
                    compartment.define_functions(debug_fns);
                    define_bindings(*compartment, option::get(self.document),
                                    option::get(self.window));
                    cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u)
                });
            }

            return true;
          }

          ExecuteMsg(url) => {
            #debug["content: Received url `%s` to execute", url_to_str(url)];

            match read_whole_file(url.path) {
              err(msg) => {
                println(#fmt["Error opening %s: %s", url_to_str(url), msg]);
              }
              ok(bytes) => {
                let cx = self.jsrt.cx();
                cx.set_default_options_and_version();
                cx.set_logging_error_reporter();
                cx.new_compartment(global_class).chain(|compartment| {
                    compartment.define_functions(debug_fns);
                    cx.evaluate_script(compartment.global_obj, bytes, url.path, 1u)
                });
              }
            }
            return true;
          }

          ExitMsg => {
            self.layout_task.send(layout_task::ExitMsg);
            return false;
          }
        }
    }

    fn relayout(document: Document, doc_url: &url) {
        #debug("content: performing relayout");

        // Now, join the layout so that they will see the latest
        // changes we have made.
        join_layout(self.scope, self.layout_task);

        // Send new document and relevant styles to layout
        // FIXME: Put CSS rules in an arc or something.
        self.layout_task.send(BuildMsg(document.root, clone(&document.css_rules), copy *doc_url, self.event_port.chan()));

        // Indicate that reader was forked so any further
        // changes will be isolated.
        self.scope.reader_forked();
    }

    fn handle_event(event: Event) -> bool {
        match event {
          ResizeEvent(new_width, new_height) => {
            #debug("content got resize event: %d, %d", new_width, new_height);
            match copy self.document {
                none => {
                    // Nothing to do.
                }
                some(document) => {
                    assert self.doc_url.is_some();
                    self.relayout(*document, &self.doc_url.get());
                }
            }
            return true;
          }
          ReflowEvent => {
            #debug("content got reflow event");
            match copy self.document {
                none => {
                    // Nothing to do.
                }
                some(document) => {
                    assert self.doc_url.is_some();
                    self.relayout(*document, &self.doc_url.get());
                }
            }
            return true;
          }
        }
    }
}
<commit_msg>Move content task onto its own schedule.<commit_after>#[doc="
    The content task is the main task that runs JavaScript and spawns layout
    tasks.
"]

export ContentTask;
export ControlMsg, ExecuteMsg, ParseMsg, ExitMsg;
export PingMsg, PongMsg;

import std::arc::{arc, clone};
import comm::{Port, Chan, port, chan, listen, select2};
import task::{spawn, spawn_listener};
import io::{read_whole_file, println};
import result::{ok, err};

import dom::base::{Document, Node, NodeScope, Window, define_bindings};
import dom::event::{Event, ResizeEvent};
import dom::style;
import dom::style::Stylesheet;
import gfx::compositor::Compositor;
import parser::html_lexer::spawn_html_lexer_task;
import parser::html_builder::build_dom;
import layout::layout_task;
import layout_task::{LayoutTask, BuildMsg};

import jsrt = js::rust::rt;
import js::rust::methods;
import js::global::{global_class, debug_fns};

import either::{Either, Left, Right};

import dom::bindings::utils::rust_box;
import js::rust::compartment;

import resource::resource_task;
import resource_task::{ResourceTask};

import std::net::url::url;
import url_to_str = std::net::url::to_str;
import util::url::make_url;
import task::{task, SingleThreaded};

enum ControlMsg {
    ParseMsg(url),
    ExecuteMsg(url),
    ExitMsg
}

enum PingMsg {
    PongMsg
}

type ContentTask = Chan<ControlMsg>;

fn ContentTask<S: Compositor send copy>(layout_task: LayoutTask, +compositor: S, resource_task: ResourceTask) -> ContentTask {
    do task().sched_mode(SingleThreaded).spawn_listener::<ControlMsg> |from_master| {
        Content(layout_task, compositor, from_master, resource_task).start();
    }
}

#[doc="Sends a ping to layout and waits for the response."]
#[allow(non_implicitly_copyable_typarams)]
fn join_layout(scope: NodeScope, layout_task: LayoutTask) {

    if scope.is_reader_forked() {
        listen(|response_from_layout| {
            layout_task.send(layout_task::PingMsg(response_from_layout));
            response_from_layout.recv();
        });
        scope.reader_joined();
    }
}

struct Content<C:Compositor> {
    let compositor: C;
    let layout_task: LayoutTask;
    let from_master: comm::Port<ControlMsg>;
    let event_port: comm::Port<Event>;

    let scope: NodeScope;
    let jsrt: jsrt;

    let mut document: option<@Document>;
    let mut window:   option<@Window>;
    let mut doc_url: option<url>;

    let resource_task: ResourceTask;

    new(layout_task: LayoutTask, +compositor: C, from_master: Port<ControlMsg>,
        resource_task: ResourceTask) {
        self.layout_task = layout_task;
        self.compositor = compositor;
        self.from_master = from_master;
        self.event_port = port();

        self.scope = NodeScope();
        self.jsrt = jsrt();

        self.document = none;
        self.window   = none;
        self.doc_url  = none;

        self.compositor.add_event_listener(self.event_port.chan());

        self.resource_task = resource_task;
    }

    fn start() {
        while self.handle_msg(select2(self.from_master, self.event_port)) {
            // Go on...
        }
    }

    fn handle_msg(msg: Either<ControlMsg,Event>) -> bool {
        match msg {
            Left(control_msg) => self.handle_control_msg(control_msg),
            Right(event) => self.handle_event(event)
        }
    }

    fn handle_control_msg(control_msg: ControlMsg) -> bool {
        match control_msg {
          ParseMsg(url) => {
            #debug["content: Received url `%s` to parse", url_to_str(url)];

            // Note: we can parse the next document in parallel
            // with any previous documents.
            let stream = spawn_html_lexer_task(copy url, self.resource_task);
            let (root, style_port, js_port) = build_dom(self.scope, stream, url,
                                                        self.resource_task);
            let css_rules = style_port.recv();
            let js_scripts = js_port.recv();

            // Apply the css rules to the dom tree:
            #debug["css_rules: %?", css_rules];

            #debug["js_scripts: %?", js_scripts];

            let document = Document(root, css_rules);
            let window   = Window();
            self.relayout(document, &url);
            self.document = some(@document);
            self.window   = some(@window);
            self.doc_url = some(copy url);

            //XXXjdm it was easier to duplicate the relevant ExecuteMsg code;
            //       they should be merged somehow in the future.
            for vec::each(js_scripts) |bytes| {
                let cx = self.jsrt.cx();
                cx.set_default_options_and_version();
                cx.set_logging_error_reporter();
                cx.new_compartment(global_class).chain(|compartment| {
                    compartment.define_functions(debug_fns);
                    define_bindings(*compartment, option::get(self.document),
                                    option::get(self.window));
                    cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u)
                });
            }

            return true;
          }

          ExecuteMsg(url) => {
            #debug["content: Received url `%s` to execute", url_to_str(url)];

            match read_whole_file(url.path) {
              err(msg) => {
                println(#fmt["Error opening %s: %s", url_to_str(url), msg]);
              }
              ok(bytes) => {
                let cx = self.jsrt.cx();
                cx.set_default_options_and_version();
                cx.set_logging_error_reporter();
                cx.new_compartment(global_class).chain(|compartment| {
                    compartment.define_functions(debug_fns);
                    cx.evaluate_script(compartment.global_obj, bytes, url.path, 1u)
                });
              }
            }
            return true;
          }

          ExitMsg => {
            self.layout_task.send(layout_task::ExitMsg);
            return false;
          }
        }
    }

    fn relayout(document: Document, doc_url: &url) {
        #debug("content: performing relayout");

        // Now, join the layout so that they will see the latest
        // changes we have made.
        join_layout(self.scope, self.layout_task);

        // Send new document and relevant styles to layout
        // FIXME: Put CSS rules in an arc or something.
        self.layout_task.send(BuildMsg(document.root, clone(&document.css_rules), copy *doc_url, self.event_port.chan()));

        // Indicate that reader was forked so any further
        // changes will be isolated.
        self.scope.reader_forked();
    }

    fn handle_event(event: Event) -> bool {
        match event {
          ResizeEvent(new_width, new_height) => {
            #debug("content got resize event: %d, %d", new_width, new_height);
            match copy self.document {
                none => {
                    // Nothing to do.
                }
                some(document) => {
                    assert self.doc_url.is_some();
                    self.relayout(*document, &self.doc_url.get());
                }
            }
            return true;
          }
          ReflowEvent => {
            #debug("content got reflow event");
            match copy self.document {
                none => {
                    // Nothing to do.
                }
                some(document) => {
                    assert self.doc_url.is_some();
                    self.relayout(*document, &self.doc_url.get());
                }
            }
            return true;
          }
        }
    }
}
<|endoftext|>


<commit_before>//! Contains the `Snes` struct, which wields the combined power of this project.

use apu::Apu;
use cpu::Cpu;
use dma::{do_dma, do_hdma, DmaChannel};
use frontend::Renderer;
use input::Input;
use log_util::LogOnPanic;
use ppu::Ppu;
use rom::Rom;

const WRAM_SIZE: usize = 128 * 1024;
byte_array!(Wram[WRAM_SIZE]);

/// Contains everything connected to the CPU via one of the two address buses. All memory accesses
/// will be directed through this (the CPU already takes access time into account).
pub struct Peripherals {
    apu: Apu,
    ppu: Ppu,
    rom: Rom,
    /// The 128 KB of working RAM of the SNES (separate from cartridge RAM)
    wram: Wram,
    input: Input,

    pub dma: [DmaChannel; 8],
    /// `$420c` - HDMAEN: HDMA enable flags
    /// (Note that general DMA doesn't have a register here, since all transactions are started
    /// immediately and the register can't be read)
    hdmaen: u8,
    /// `$4200` - NMITIMEN: Interrupt enable flags
    /// `n-xy---a`
    /// * `n`: Enable NMI on V-Blank
    /// * `x`: Enable IRQ on H-Counter match
    /// * `y`: Enable IRQ on V-Counter match
    /// * `a`: Enable auto-joypad read
    nmien: u8,
    /// `$4207`/`$4208` - HTIMEL/HTIMEH: H Timer (9-bit value)
    htime: u16,
    /// `$4209`/`$420a` - VTIMEL/VTIMEH: V Timer (9-bit value)
    vtime: u16,
    /// `$4210` NMI flag and 5A22 Version
    /// `n---vvvv`
    /// * `n`: `self.nmi`
    /// * `v`: Version
    nmi: bool,
    /// `$4211` TIMEUP - IRQ flag
    /// `i-------`
    /// * `i`: IRQ flag (cleared on read)
    irq: bool,

    /// Additional cycles spent doing IO (in master clock cycles). This is reset before each CPU
    /// instruction and added to the cycle count returned by the CPU.
    cy: u32,
}

impl Peripherals {
    pub fn new(rom: Rom) -> Peripherals {
        Peripherals {
            rom: rom,
            apu: Apu::new(),
            ppu: Ppu::new(),
            wram: Wram::default(),
            input: Input::default(),
            dma: [DmaChannel::new(); 8],
            hdmaen: 0x00,
            nmien: 0x00,
            htime: 0x1ff,
            vtime: 0x1ff,
            nmi: false,
            irq: false,
            cy: 0,
        }
    }

    pub fn load(&mut self, bank: u8, addr: u16) -> u8 {
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf => match addr {
                // Mirror of first 8k of WRAM
                0x0000 ... 0x1fff => self.wram[addr as usize],
                // PPU
                0x2100 ... 0x2133 => panic!("read from write-only PPU register ${:04X}", addr),
                0x2138 ... 0x213f => self.ppu.load(addr),
                // APU IO registers
                0x2140 ... 0x217f => self.apu.read_port((addr & 0b11) as u8),
                0x4016 | 0x4017 => self.input.load(addr),
                0x4210 => {
                    const CPU_VERSION: u8 = 2;  // FIXME Is 2 okay in all cases? Does anyone care?
                    let nmi = if self.nmi { 0x80 } else { 0 };
                    self.nmi = false;   // Cleared on read
                    nmi | CPU_VERSION
                }
                0x4211 => {
                    let val = if self.irq { 0x80 } else { 0 };
                    self.irq = false;
                    val
                }
                0x4218 ... 0x421f => self.input.load(addr),
                // DMA channels (0x43xr, where x is the channel and r is the channel register)
                0x4300 ... 0x43ff => self.dma[(addr as usize & 0x00f0) >> 4].load(addr as u8 & 0xf),
                0x8000 ... 0xffff => self.rom.loadb(bank, addr),
                _ => panic!("invalid/unimplemented load from ${:02X}:{:04X}", bank, addr)
            },
            // WRAM banks. The first 8k are mapped into the start of all banks.
            0x7e | 0x7f => self.wram[(bank as usize - 0x7e) * 65536 + addr as usize],
            0x40 ... 0x7d | 0xc0 ... 0xff => self.rom.loadb(bank, addr),
            _ => unreachable!(),    // Rust should know this!
        }
    }

    pub fn store(&mut self, bank: u8, addr: u16, value: u8) {
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf => match addr {
                0x0000 ... 0x1fff => self.wram[addr as usize] = value,
                // PPU registers. Let it deal with the access.
                0x2100 ... 0x2133 => self.ppu.store(addr, value),
                0x2138 ... 0x213f => panic!("store to read-only PPU register ${:04X}", addr),
                // APU IO registers.
                0x2140 ... 0x217f => self.apu.store_port((addr & 0b11) as u8, value),
                0x2180 ... 0x2183 => panic!("NYI: WRAM registers"),
                0x4016 => self.input.store(addr, value),
                0x4200 => {
                    // NMITIMEN - NMI/IRQ enable
                    // E-HV---J
                    // E: Enable NMI
                    // H: Enable IRQ on H-Counter
                    // V: Enable IRQ on V-Counter
                    // J: Enable Auto-Joypad-Read

                    // Check useless bits
                    if value & 0x4e != 0 { panic!("Invalid value for NMIEN: ${:02X}", value) }
                    self.nmien = value;
                }
                0x4207 => self.htime = (self.htime & 0xff00) | value as u16,
                0x4208 => {
                    assert!(value & 0x01 == value, "invalid value for $4207: ${:02X}", value);
                    self.htime = ((value as u16) << 8) | (self.htime & 0xff);
                }
                0x4209 => self.vtime = (self.vtime & 0xff00) | value as u16,
                0x420a => {
                    assert!(value & 0x01 == value, "invalid value for $4209: ${:02X}", value);
                    self.vtime = ((value as u16) << 8) | (self.vtime & 0xff);
                }
                // MDMAEN - Party enable
                0x420b => self.cy += do_dma(self, value),
                // HDMAEN - HDMA enable
                0x420c => self.hdmaen = value,
                // DMA channels (0x43xr, where x is the channel and r is the channel register)
                0x4300 ... 0x43ff => {
                    self.dma[(addr as usize & 0x00f0) >> 4].store(addr as u8 & 0xf, value);
                }
                0x8000 ... 0xffff => self.rom.storeb(bank, addr, value),
                _ => panic!("invalid store: ${:02X} to ${:02X}:{:04X}", value, bank, addr)
            },
            // WRAM main banks
            0x7e | 0x7f => self.wram[(bank as usize - 0x7e) * 65536 + addr as usize] = value,
            0x40 ... 0x7d | 0xc0 ... 0xff => self.rom.storeb(bank, addr, value),
            _ => unreachable!(),    // Rust should know this!
        }
    }

    fn nmi_enabled(&self) -> bool { self.nmien & 0x80 != 0 }
    fn v_irq_enabled(&self) -> bool { self.nmien & 0x10 != 0 }
    fn h_irq_enabled(&self) -> bool { self.nmien & 0x20 != 0 }
}

pub struct Snes {
    cpu: Cpu,
    renderer: Box<Renderer>,
}

impl Snes {
    pub fn new(rom: Rom, renderer: Box<Renderer>) -> Snes {
        Snes {
            cpu: Cpu::new(Peripherals::new(rom)),
            renderer: renderer,
        }
    }

    pub fn run(&mut self) {
        /// Exit after this number of master clock cycles
        const CY_LIMIT: u64 = 150_000_000;
        /// Start tracing at this master cycle (0 to trace everything)
        const TRACE_START: u64 = CY_LIMIT - 10_000;

        /// Approximated APU clock divider. It's actually somewhere around 20.9..., which is why we
        /// can't directly use `MASTER_CLOCK_FREQ / APU_CLOCK_FREQ` (it would round down, which
        /// might not be critical, but better safe than sorry).
        const APU_DIVIDER: i32 = 21;

        // Master cycle counter, used only for debugging atm
        let mut master_cy: u64 = 0;
        let mut total_apu_cy: u64 = 0;
        let mut total_ppu_cy: u64 = 0;
        // Master clock cycles for the APU not yet accounted for (can be negative)
        let mut apu_master_cy_debt = 0;
        let mut ppu_master_cy_debt = 0;
        let working_cy = LogOnPanic::new(0);

        while master_cy < CY_LIMIT {
            if master_cy >= TRACE_START {
                self.cpu.trace = true;
                self.cpu.mem.apu.trace = true;
            }

            // Run a CPU instruction and calculate the master cycles elapsed
            self.cpu.mem.cy = 0;
            let cpu_master_cy = self.cpu.dispatch() as i32 + self.cpu.mem.cy as i32;
            master_cy += cpu_master_cy as u64;

            // Now we "owe" the other components a few cycles:
            apu_master_cy_debt += cpu_master_cy;
            ppu_master_cy_debt += cpu_master_cy;

            // Run all components until we no longer owe them:
            while apu_master_cy_debt > APU_DIVIDER {
                // (Since the APU uses lots of cycles to do stuff - lower clock rate and such - we
                // only run it if we owe it `APU_DIVIDER` master cycles - or one SPC700 cycle)
                let apu_master_cy = self.cpu.mem.apu.dispatch() as i32 * APU_DIVIDER;
                apu_master_cy_debt -= apu_master_cy;
                total_apu_cy += apu_master_cy as u64;
            }
            while ppu_master_cy_debt > 0 {
                let (cy, result) = self.cpu.mem.ppu.update();
                ppu_master_cy_debt -= cy as i32;
                total_ppu_cy += cy as u64;

                if result.hblank {
                    // FIXME Cycles
                    do_hdma(self.cpu.mem.hdmaen);
                }
                if result.last_pixel {
                    self.renderer.render(&*self.cpu.mem.ppu.framebuf);
                }
                if result.vblank {
                    self.cpu.mem.input.new_frame();
                    if self.cpu.mem.nmi_enabled() {
                        //trace!("V-Blank NMI triggered! Trace started!");
                        //self.cpu.trace = true;
                        self.cpu.mem.nmi = true;
                        self.cpu.trigger_nmi();
                        // XXX Break to handle the NMI immediately. Let's hope we don't owe the PPU
                        // too many cycles.
                        break;
                    }
                }
                if result.new_frame {
                    self.cpu.mem.nmi = false;   // Flag cleared on read or end of VBlank
                }

                let cpu = &mut self.cpu;
                if cpu.mem.ppu.v_counter() == cpu.mem.vtime && cpu.mem.v_irq_enabled() {
                    cpu.mem.irq = true;
                    cpu.trigger_irq();
                    break;
                }
                if cpu.mem.ppu.h_counter() == cpu.mem.htime && cpu.mem.h_irq_enabled() {
                    cpu.mem.irq = true;
                    cpu.trigger_irq();
                    break;
                }
            }

            working_cy.set(master_cy);
        }

        info!("EXITING. Master cycle count: {}, APU: {}, PPU: {}",
            master_cy, total_apu_cy, total_ppu_cy);
    }
}
<commit_msg>Allow stores to division registers<commit_after>//! Contains the `Snes` struct, which wields the combined power of this project.

use apu::Apu;
use cpu::Cpu;
use dma::{do_dma, do_hdma, DmaChannel};
use frontend::Renderer;
use input::Input;
use log_util::LogOnPanic;
use ppu::Ppu;
use rom::Rom;

const WRAM_SIZE: usize = 128 * 1024;
byte_array!(Wram[WRAM_SIZE]);

/// Contains everything connected to the CPU via one of the two address buses. All memory accesses
/// will be directed through this (the CPU already takes access time into account).
pub struct Peripherals {
    apu: Apu,
    ppu: Ppu,
    rom: Rom,
    /// The 128 KB of working RAM of the SNES (separate from cartridge RAM)
    wram: Wram,
    input: Input,

    pub dma: [DmaChannel; 8],
    /// `$420c` - HDMAEN: HDMA enable flags
    /// (Note that general DMA doesn't have a register here, since all transactions are started
    /// immediately and the register can't be read)
    hdmaen: u8,
    /// `$4200` - NMITIMEN: Interrupt enable flags
    /// `n-xy---a`
    /// * `n`: Enable NMI on V-Blank
    /// * `x`: Enable IRQ on H-Counter match
    /// * `y`: Enable IRQ on V-Counter match
    /// * `a`: Enable auto-joypad read
    nmien: u8,
    /// `$4204`/`$4205` - WRDIVH/WRDIVL: Dividend C
    wrdiv: u16,
    /// `$4206` - WRDIVB: Divisor B
    wrdivb: u8,
    /// `$4207`/`$4208` - HTIMEL/HTIMEH: H Timer (9-bit value)
    htime: u16,
    /// `$4209`/`$420a` - VTIMEL/VTIMEH: V Timer (9-bit value)
    vtime: u16,
    /// `$4210` NMI flag and 5A22 Version
    /// `n---vvvv`
    /// * `n`: `self.nmi`
    /// * `v`: Version
    nmi: bool,
    /// `$4211` TIMEUP - IRQ flag
    /// `i-------`
    /// * `i`: IRQ flag (cleared on read)
    irq: bool,

    /// Additional cycles spent doing IO (in master clock cycles). This is reset before each CPU
    /// instruction and added to the cycle count returned by the CPU.
    cy: u32,
}

impl Peripherals {
    pub fn new(rom: Rom) -> Peripherals {
        Peripherals {
            rom: rom,
            apu: Apu::new(),
            ppu: Ppu::new(),
            wram: Wram::default(),
            input: Input::default(),
            dma: [DmaChannel::new(); 8],
            hdmaen: 0x00,
            nmien: 0x00,
            wrdiv: 0xffff,
            wrdivb: 0,
            htime: 0x1ff,
            vtime: 0x1ff,
            nmi: false,
            irq: false,
            cy: 0,
        }
    }

    pub fn load(&mut self, bank: u8, addr: u16) -> u8 {
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf => match addr {
                // Mirror of first 8k of WRAM
                0x0000 ... 0x1fff => self.wram[addr as usize],
                // PPU
                0x2100 ... 0x2133 => panic!("read from write-only PPU register ${:04X}", addr),
                0x2138 ... 0x213f => self.ppu.load(addr),
                // APU IO registers
                0x2140 ... 0x217f => self.apu.read_port((addr & 0b11) as u8),
                0x4016 | 0x4017 => self.input.load(addr),
                0x4210 => {
                    const CPU_VERSION: u8 = 2;  // FIXME Is 2 okay in all cases? Does anyone care?
                    let nmi = if self.nmi { 0x80 } else { 0 };
                    self.nmi = false;   // Cleared on read
                    nmi | CPU_VERSION
                }
                0x4211 => {
                    let val = if self.irq { 0x80 } else { 0 };
                    self.irq = false;
                    val
                }
                0x4218 ... 0x421f => self.input.load(addr),
                // DMA channels (0x43xr, where x is the channel and r is the channel register)
                0x4300 ... 0x43ff => self.dma[(addr as usize & 0x00f0) >> 4].load(addr as u8 & 0xf),
                0x8000 ... 0xffff => self.rom.loadb(bank, addr),
                _ => panic!("invalid/unimplemented load from ${:02X}:{:04X}", bank, addr)
            },
            // WRAM banks. The first 8k are mapped into the start of all banks.
            0x7e | 0x7f => self.wram[(bank as usize - 0x7e) * 65536 + addr as usize],
            0x40 ... 0x7d | 0xc0 ... 0xff => self.rom.loadb(bank, addr),
            _ => unreachable!(),    // Rust should know this!
        }
    }

    pub fn store(&mut self, bank: u8, addr: u16, value: u8) {
        match bank {
            0x00 ... 0x3f | 0x80 ... 0xbf => match addr {
                0x0000 ... 0x1fff => self.wram[addr as usize] = value,
                // PPU registers. Let it deal with the access.
                0x2100 ... 0x2133 => self.ppu.store(addr, value),
                0x2138 ... 0x213f => panic!("store to read-only PPU register ${:04X}", addr),
                // APU IO registers.
                0x2140 ... 0x217f => self.apu.store_port((addr & 0b11) as u8, value),
                0x2180 ... 0x2183 => panic!("NYI: WRAM registers"),
                0x4016 => self.input.store(addr, value),
                0x4200 => {
                    // NMITIMEN - NMI/IRQ enable
                    // E-HV---J
                    // E: Enable NMI
                    // H: Enable IRQ on H-Counter
                    // V: Enable IRQ on V-Counter
                    // J: Enable Auto-Joypad-Read

                    // Check useless bits
                    if value & 0x4e != 0 { panic!("Invalid value for NMIEN: ${:02X}", value) }
                    self.nmien = value;
                }
                0x4204 => self.wrdiv = (self.wrdiv & 0xff00) | value as u16,
                0x4205 => self.wrdiv = ((value as u16) << 8) | (self.wrdiv & 0xff),
                0x4206 => self.wrdivb = value,
                0x4207 => self.htime = (self.htime & 0xff00) | value as u16,
                0x4208 => {
                    assert!(value & 0x01 == value, "invalid value for $4207: ${:02X}", value);
                    self.htime = ((value as u16) << 8) | (self.htime & 0xff);
                }
                0x4209 => self.vtime = (self.vtime & 0xff00) | value as u16,
                0x420a => {
                    assert!(value & 0x01 == value, "invalid value for $4209: ${:02X}", value);
                    self.vtime = ((value as u16) << 8) | (self.vtime & 0xff);
                }
                // MDMAEN - Party enable
                0x420b => self.cy += do_dma(self, value),
                // HDMAEN - HDMA enable
                0x420c => self.hdmaen = value,
                // DMA channels (0x43xr, where x is the channel and r is the channel register)
                0x4300 ... 0x43ff => {
                    self.dma[(addr as usize & 0x00f0) >> 4].store(addr as u8 & 0xf, value);
                }
                0x8000 ... 0xffff => self.rom.storeb(bank, addr, value),
                _ => panic!("invalid store: ${:02X} to ${:02X}:{:04X}", value, bank, addr)
            },
            // WRAM main banks
            0x7e | 0x7f => self.wram[(bank as usize - 0x7e) * 65536 + addr as usize] = value,
            0x40 ... 0x7d | 0xc0 ... 0xff => self.rom.storeb(bank, addr, value),
            _ => unreachable!(),    // Rust should know this!
        }
    }

    fn nmi_enabled(&self) -> bool { self.nmien & 0x80 != 0 }
    fn v_irq_enabled(&self) -> bool { self.nmien & 0x10 != 0 }
    fn h_irq_enabled(&self) -> bool { self.nmien & 0x20 != 0 }
}

pub struct Snes {
    cpu: Cpu,
    renderer: Box<Renderer>,
}

impl Snes {
    pub fn new(rom: Rom, renderer: Box<Renderer>) -> Snes {
        Snes {
            cpu: Cpu::new(Peripherals::new(rom)),
            renderer: renderer,
        }
    }

    pub fn run(&mut self) {
        /// Exit after this number of master clock cycles
        const CY_LIMIT: u64 = 150_000_000;
        /// Start tracing at this master cycle (0 to trace everything)
        const TRACE_START: u64 = CY_LIMIT - 10_000;

        /// Approximated APU clock divider. It's actually somewhere around 20.9..., which is why we
        /// can't directly use `MASTER_CLOCK_FREQ / APU_CLOCK_FREQ` (it would round down, which
        /// might not be critical, but better safe than sorry).
        const APU_DIVIDER: i32 = 21;

        // Master cycle counter, used only for debugging atm
        let mut master_cy: u64 = 0;
        let mut total_apu_cy: u64 = 0;
        let mut total_ppu_cy: u64 = 0;
        // Master clock cycles for the APU not yet accounted for (can be negative)
        let mut apu_master_cy_debt = 0;
        let mut ppu_master_cy_debt = 0;
        let working_cy = LogOnPanic::new(0);

        while master_cy < CY_LIMIT {
            if master_cy >= TRACE_START {
                self.cpu.trace = true;
                self.cpu.mem.apu.trace = true;
            }

            // Run a CPU instruction and calculate the master cycles elapsed
            self.cpu.mem.cy = 0;
            let cpu_master_cy = self.cpu.dispatch() as i32 + self.cpu.mem.cy as i32;
            master_cy += cpu_master_cy as u64;

            // Now we "owe" the other components a few cycles:
            apu_master_cy_debt += cpu_master_cy;
            ppu_master_cy_debt += cpu_master_cy;

            // Run all components until we no longer owe them:
            while apu_master_cy_debt > APU_DIVIDER {
                // (Since the APU uses lots of cycles to do stuff - lower clock rate and such - we
                // only run it if we owe it `APU_DIVIDER` master cycles - or one SPC700 cycle)
                let apu_master_cy = self.cpu.mem.apu.dispatch() as i32 * APU_DIVIDER;
                apu_master_cy_debt -= apu_master_cy;
                total_apu_cy += apu_master_cy as u64;
            }
            while ppu_master_cy_debt > 0 {
                let (cy, result) = self.cpu.mem.ppu.update();
                ppu_master_cy_debt -= cy as i32;
                total_ppu_cy += cy as u64;

                if result.hblank {
                    // FIXME Cycles
                    do_hdma(self.cpu.mem.hdmaen);
                }
                if result.last_pixel {
                    self.renderer.render(&*self.cpu.mem.ppu.framebuf);
                }
                if result.vblank {
                    self.cpu.mem.input.new_frame();
                    if self.cpu.mem.nmi_enabled() {
                        //trace!("V-Blank NMI triggered! Trace started!");
                        //self.cpu.trace = true;
                        self.cpu.mem.nmi = true;
                        self.cpu.trigger_nmi();
                        // XXX Break to handle the NMI immediately. Let's hope we don't owe the PPU
                        // too many cycles.
                        break;
                    }
                }
                if result.new_frame {
                    self.cpu.mem.nmi = false;   // Flag cleared on read or end of VBlank
                }

                let cpu = &mut self.cpu;
                if cpu.mem.ppu.v_counter() == cpu.mem.vtime && cpu.mem.v_irq_enabled() {
                    cpu.mem.irq = true;
                    cpu.trigger_irq();
                    break;
                }
                if cpu.mem.ppu.h_counter() == cpu.mem.htime && cpu.mem.h_irq_enabled() {
                    cpu.mem.irq = true;
                    cpu.trigger_irq();
                    break;
                }
            }

            working_cy.set(master_cy);
        }

        info!("EXITING. Master cycle count: {}, APU: {}, PPU: {}",
            master_cy, total_apu_cy, total_ppu_cy);
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::mem;
use std::str;

#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ssid {
    vec: Vec<u8>,
}

impl Ssid {
    pub fn new() -> Self {
        Ssid {
            vec: Vec::new(),
        }
    }

    pub fn from_bytes<B>(bytes: B) -> Result<Self, String>
    where
        B: Into<Vec<u8>> + AsRef<[u8]>,
    {
        match bytes.as_ref().as_ssid_slice() {
            Ok(_) => Ok(unsafe { Ssid::from_bytes_unchecked(bytes) }),
            Err(e) => Err(e),
        }
    }

    unsafe fn from_bytes_unchecked<B>(bytes: B) -> Self
    where
        B: Into<Vec<u8>>,
    {
        Ssid {
            vec: bytes.into(),
        }
    }
}

pub trait IntoSsid: Sized {
    fn into_ssid(self) -> Result<Ssid, String>;
}

impl Deref for Ssid {
    type Target = SsidSlice;

    #[inline]
    fn deref(&self) -> &SsidSlice {
        unsafe { mem::transmute(&self.vec[..]) }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SsidSlice {
    slice: [u8],
}

pub trait AsSsidSlice {
    fn as_ssid_slice(&self) -> Result<&SsidSlice, String>;
}

impl SsidSlice {
    pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
        str::from_utf8(&self.slice)
    }

    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }
}

impl AsSsidSlice for [u8] {
    fn as_ssid_slice(&self) -> Result<&SsidSlice, String> {
        if self.len() > 32 {
            Err(format!("SSID length should not exceed 32: {} len", self.len()))
        } else {
            Ok(unsafe { mem::transmute(self) })
        }
    }
}

impl AsSsidSlice for str {
    fn as_ssid_slice(&self) -> Result<&SsidSlice, String> {
        self.as_bytes().as_ssid_slice()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ssid_from_bytes_as_bytes() {
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let ssid = Ssid::from_bytes(vec_u8.clone()).unwrap();
        let slice = &ssid as &SsidSlice;
        let as_bytes = slice.as_bytes();
        assert_eq!(vec_u8, as_bytes);
    }

    #[test]
    fn test_ssid_from_bytes_as_str() {
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let ssid = Ssid::from_bytes(vec_u8.clone()).unwrap();
        let slice = &ssid as &SsidSlice;
        let as_str = slice.as_str().unwrap();
        assert_eq!(vec_u8, as_str.as_bytes());
    }

    #[test]
    fn test_ssid_from_bytes_eq() {
        let from_string = Ssid::from_bytes("hello".to_string()).unwrap();
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let from_vec_u8 = Ssid::from_bytes(vec_u8).unwrap();
        assert_eq!(from_string, from_vec_u8);
    }

    #[test]
    fn test_as_ssid_slice() {
        let slice_from_str = "hello".as_ssid_slice().unwrap();
        let ssid_u8 = [0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let slice_from_u8 = (&ssid_u8 as &[u8]).as_ssid_slice().unwrap();
        assert_eq!(slice_from_str, slice_from_u8);
    }
}
<commit_msg>ASCII oriented SSID Debug formatting<commit_after>use std::ops::Deref;
use std::mem;
use std::str;
use std::fmt;
use std::fmt::Write;
use std::ascii;

#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ssid {
    vec: Vec<u8>,
}

impl Ssid {
    pub fn new() -> Self {
        Ssid {
            vec: Vec::new(),
        }
    }

    pub fn from_bytes<B>(bytes: B) -> Result<Self, String>
    where
        B: Into<Vec<u8>> + AsRef<[u8]>,
    {
        match bytes.as_ref().as_ssid_slice() {
            Ok(_) => Ok(unsafe { Ssid::from_bytes_unchecked(bytes) }),
            Err(e) => Err(e),
        }
    }

    unsafe fn from_bytes_unchecked<B>(bytes: B) -> Self
    where
        B: Into<Vec<u8>>,
    {
        Ssid {
            vec: bytes.into(),
        }
    }
}

pub trait IntoSsid: Sized {
    fn into_ssid(self) -> Result<Ssid, String>;
}

impl Deref for Ssid {
    type Target = SsidSlice;

    #[inline]
    fn deref(&self) -> &SsidSlice {
        unsafe { mem::transmute(&self.vec[..]) }
    }
}

impl fmt::Debug for Ssid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self as &SsidSlice, f)
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SsidSlice {
    slice: [u8],
}

pub trait AsSsidSlice {
    fn as_ssid_slice(&self) -> Result<&SsidSlice, String>;
}

impl SsidSlice {
    pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
        str::from_utf8(&self.slice)
    }

    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }
}

impl fmt::Debug for SsidSlice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_char('"')?;
        for byte in self.as_bytes() {
            for c in ascii::escape_default(*byte) {
                f.write_char(c as char)?;
            }
        }
        f.write_char('"')
    }
}

impl AsSsidSlice for [u8] {
    fn as_ssid_slice(&self) -> Result<&SsidSlice, String> {
        if self.len() > 32 {
            Err(format!("SSID length should not exceed 32: {} len", self.len()))
        } else {
            Ok(unsafe { mem::transmute(self) })
        }
    }
}

impl AsSsidSlice for str {
    fn as_ssid_slice(&self) -> Result<&SsidSlice, String> {
        self.as_bytes().as_ssid_slice()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ssid_from_bytes_as_bytes() {
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let ssid = Ssid::from_bytes(vec_u8.clone()).unwrap();
        let slice = &ssid as &SsidSlice;
        let as_bytes = slice.as_bytes();
        assert_eq!(vec_u8, as_bytes);
    }

    #[test]
    fn test_ssid_from_bytes_as_str() {
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let ssid = Ssid::from_bytes(vec_u8.clone()).unwrap();
        let slice = &ssid as &SsidSlice;
        let as_str = slice.as_str().unwrap();
        assert_eq!(vec_u8, as_str.as_bytes());
    }

    #[test]
    fn test_ssid_from_bytes_eq() {
        let from_string = Ssid::from_bytes("hello".to_string()).unwrap();
        let vec_u8 = vec![0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let from_vec_u8 = Ssid::from_bytes(vec_u8).unwrap();
        assert_eq!(from_string, from_vec_u8);
    }

    #[test]
    fn test_as_ssid_slice() {
        let slice_from_str = "hello".as_ssid_slice().unwrap();
        let ssid_u8 = [0x68_u8, 0x65_u8, 0x6c_u8, 0x6c_u8, 0x6f_u8];
        let slice_from_u8 = (&ssid_u8 as &[u8]).as_ssid_slice().unwrap();
        assert_eq!(slice_from_str, slice_from_u8);
    }

    #[test]
    fn test_ssid_debug() {
        let ssid = Ssid::from_bytes(b"hello\0\x7F".to_vec()).unwrap();
        let debug = format!("{:?}", ssid);
        assert_eq!(debug, "\"hello\\x00\\x7f\"");
    }

    #[test]
    fn test_ssid_slice_debug() {
        let ssid = Ssid::from_bytes(b"hello\0\x7F".to_vec()).unwrap();
        let slice = &ssid as &SsidSlice;
        let debug = format!("{:?}", slice);
        assert_eq!(debug, "\"hello\\x00\\x7f\"");
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::result::Result as RResult;

use serde_json::value::Value;
use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Visitor;
use serde::de::Error as SerdeError;
use serde::ser::MapVisitor;
use serde::de::MapVisitor as DeserializeMapVisitor;
use uuid::Uuid;

use error::TaskError;
use error::TaskErrorKind;
use priority::TaskPriority;
use result::Result;
use status::TaskStatus;
use project::Project;
use tag::Tag;
use date::Date;

#[derive(Debug, Clone)]
pub struct Task {
    status      : TaskStatus,
    uuid        : Uuid,
    entry       : Date,
    description : String,

    annotation  : Option<Vec<String>>,
    depends     : Option<String>,
    due         : Option<Date>,
    end         : Option<Date>,
    imask       : Option<i64>,
    mask        : Option<String>,
    modified    : Option<Date>,
    parent      : Option<Uuid>,
    priority    : Option<TaskPriority>,
    project     : Option<Project>,
    recur       : Option<String>,
    scheduled   : Option<Date>,
    start       : Option<Date>,
    tags        : Option<Vec<Tag>>,
    until       : Option<Date>,
    wait        : Option<Date>,
}

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

    pub fn new(
        status      : TaskStatus,
        uuid        : Uuid,
        entry       : Date,
        description : String,

        annotation  : Option<Vec<String>>,
        depends     : Option<String>,
        due         : Option<Date>,
        end         : Option<Date>,
        imask       : Option<i64>,
        mask        : Option<String>,
        modified    : Option<Date>,
        parent      : Option<Uuid>,
        priority    : Option<TaskPriority>,
        project     : Option<Project>,
        recur       : Option<String>,
        scheduled   : Option<Date>,
        start       : Option<Date>,
        tags        : Option<Vec<Tag>>,
        until       : Option<Date>,
        wait        : Option<Date>,
    ) -> Task
    {
        Task {
            status      : status,
            uuid        : uuid,
            entry       : entry,
            description : description,

            annotation  : annotation,
            depends     : depends,
            due         : due,
            end         : end,
            imask       : imask,
            mask        : mask,
            modified    : modified,
            parent      : parent,
            priority    : priority,
            project     : project,
            recur       : recur,
            scheduled   : scheduled,
            start       : start,
            tags        : tags,
            until       : until,
            wait        : wait,
        }
    }

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

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

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

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

    pub fn annotation(&self) -> Option<&Vec<String>> {
        self.annotation.as_ref()
    }

    pub fn depends(&self) -> Option<&String> {
        self.depends.as_ref()
    }

    pub fn due(&self) -> Option<&Date> {
        self.due.as_ref()
    }

    pub fn end(&self) -> Option<&Date> {
        self.end.as_ref()
    }

    pub fn imask(&self) -> Option<&i64> {
        self.imask.as_ref()
    }

    pub fn mask(&self) -> Option<&String> {
        self.mask.as_ref()
    }

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

    pub fn parent(&self) -> Option<&Uuid> {
        self.parent.as_ref()
    }

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

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

    pub fn recur(&self) -> Option<&String> {
        self.recur.as_ref()
    }

    pub fn scheduled(&self) -> Option<&Date> {
        self.scheduled.as_ref()
    }

    pub fn start(&self) -> Option<&Date> {
        self.start.as_ref()
    }

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

    pub fn until(&self) -> Option<&Date> {
        self.until.as_ref()
    }

    pub fn wait(&self) -> Option<&Date> {
        self.wait.as_ref()
    }

}

impl Serialize for Task {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_struct("Task", TaskVisitor {
            value: self,
            state: 0,
        })
    }

}

struct TaskVisitor<'a> {
    value: &'a Task,
    state: u8,
}

impl<'a> MapVisitor for TaskVisitor<'a> {

    fn visit<S>(&mut self, serializer: &mut S) -> RResult<Option<()>, S::Error>
        where S: Serializer
    {
        match self.state {
            0 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("status", &self.value.status))))
            },
            1 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("uuid", &self.value.uuid))))
            },
            2 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("entry", &self.value.entry))))
            },
            3 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("description", &self.value.description))))
            },
            4 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("annotation", &self.value.annotation))))
            },
            5 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("depends", &self.value.depends))))
            },
            6 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("due", &self.value.due))))
            },
            7 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("end", &self.value.end))))
            },
            8 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("imask", &self.value.imask))))
            },
            9 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("mask", &self.value.mask))))
            },
            10 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("modified", &self.value.modified))))
            },
            11 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("parent", &self.value.parent))))
            },
            12 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("priority", &self.value.priority))))
            },
            13 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("project", &self.value.project))))
            },
            14 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("recur", &self.value.recur))))
            },
            15 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("scheduled", &self.value.scheduled))))
            },
            16 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("start", &self.value.start))))
            },
            17 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("tags", &self.value.tags))))
            },
            18 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("until", &self.value.until))))
            },
            19 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("wait", &self.value.wait))))
            },
            _ => {
                Ok(None)
            }
        }
    }

}

impl Deserialize for Task {

    fn deserialize<D>(deserializer: &mut D) -> RResult<Task, D::Error>
        where D: Deserializer
    {
        static FIELDS: &'static [&'static str] = &[
            "status",
            "uuid",
            "entry",
            "description",

            "annotation",
            "depends",
            "due",
            "end",
            "imask",
            "mask",
            "modified",
            "parent",
            "priority",
            "project",
            "recur",
            "scheduled",
            "start",
            "tags",
            "until",
            "wait"
        ];
        deserializer.deserialize_struct("Task", FIELDS, TaskDeserializeVisitor)
    }

}

struct TaskDeserializeVisitor;

impl Visitor for TaskDeserializeVisitor {
    type Value = Task;

    fn visit_map<V>(&mut self, mut visitor: V) -> RResult<Task, V::Error>
        where V: DeserializeMapVisitor
    {
        let mut status      = None;
        let mut uuid        = None;
        let mut entry       = None;
        let mut description = None;

        let mut annotation  = None;
        let mut depends     = None;
        let mut due         = None;
        let mut end         = None;
        let mut imask       = None;
        let mut mask        = None;
        let mut modified    = None;
        let mut parent      = None;
        let mut priority    = None;
        let mut project     = None;
        let mut recur       = None;
        let mut scheduled   = None;
        let mut start       = None;
        let mut tags        = None;
        let mut until       = None;
        let mut wait        = None;

        loop {
            let key : Option<String> = try!(visitor.visit_key());
            if key.is_none() {
                break;
            }
            let key = key.unwrap();

            match &key[..] {
                "status" => {
                    status = Some(try!(visitor.visit_value()));
                },
                "uuid" => {
                    uuid = Some(try!(visitor.visit_value()));
                },
                "entry" => {
                    entry = Some(try!(visitor.visit_value()));
                },
                "description" => {
                    description = Some(try!(visitor.visit_value()));
                },

                "annotation" => {
                    annotation = Some(try!(visitor.visit_value()));
                },
                "depends" => {
                    depends = Some(try!(visitor.visit_value()));
                },
                "due" => {
                    due = Some(try!(visitor.visit_value()));
                },
                "end" => {
                    end = Some(try!(visitor.visit_value()));
                },
                "imask" => {
                    imask = Some(try!(visitor.visit_value()));
                },
                "mask" => {
                    mask = Some(try!(visitor.visit_value()));
                },
                "modified" => {
                    modified = Some(try!(visitor.visit_value()));
                },
                "parent" => {
                    parent = Some(try!(visitor.visit_value()));
                },
                "priority" => {
                    priority = Some(try!(visitor.visit_value()));
                },
                "project" => {
                    project = Some(try!(visitor.visit_value()));
                },
                "recur" => {
                    recur = Some(try!(visitor.visit_value()));
                },
                "scheduled" => {
                    scheduled = Some(try!(visitor.visit_value()));
                },
                "start" => {
                    start = Some(try!(visitor.visit_value()));
                },
                "tags" => {
                    tags = Some(try!(visitor.visit_value()));
                },
                "until" => {
                    until = Some(try!(visitor.visit_value()));
                },
                "wait" => {
                    wait = Some(try!(visitor.visit_value()));
                },

                field => debug!("field '{}' ignored", field),
            }
        }

        let status = match status {
            Some(status) => status,
            None => try!(visitor.missing_field("status")),
        };

        let uuid = match uuid {
            Some(uuid) => uuid,
            None => try!(visitor.missing_field("uuid")),
        };

        let entry = match entry {
            Some(entry) => entry,
            None => try!(visitor.missing_field("entry")),
        };

        let description = match description {
            Some(description) => description,
            None => try!(visitor.missing_field("description")),
        };

        try!(visitor.end());

        let task = Task::new(
            status,
            uuid,
            entry,
            description,

            annotation,
            depends,
            due,
            end,
            imask,
            mask,
            modified,
            parent,
            priority,
            project,
            recur,
            scheduled,
            start,
            tags,
            until,
            wait
        );

        Ok(task)
    }
}

<commit_msg>Add a test<commit_after>use std::collections::BTreeMap;
use std::result::Result as RResult;

use serde_json::value::Value;
use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Visitor;
use serde::de::Error as SerdeError;
use serde::ser::MapVisitor;
use serde::de::MapVisitor as DeserializeMapVisitor;
use uuid::Uuid;

use error::TaskError;
use error::TaskErrorKind;
use priority::TaskPriority;
use result::Result;
use status::TaskStatus;
use project::Project;
use tag::Tag;
use date::Date;

#[derive(Debug, Clone)]
pub struct Task {
    status      : TaskStatus,
    uuid        : Uuid,
    entry       : Date,
    description : String,

    annotation  : Option<Vec<String>>,
    depends     : Option<String>,
    due         : Option<Date>,
    end         : Option<Date>,
    imask       : Option<i64>,
    mask        : Option<String>,
    modified    : Option<Date>,
    parent      : Option<Uuid>,
    priority    : Option<TaskPriority>,
    project     : Option<Project>,
    recur       : Option<String>,
    scheduled   : Option<Date>,
    start       : Option<Date>,
    tags        : Option<Vec<Tag>>,
    until       : Option<Date>,
    wait        : Option<Date>,
}

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

    pub fn new(
        status      : TaskStatus,
        uuid        : Uuid,
        entry       : Date,
        description : String,

        annotation  : Option<Vec<String>>,
        depends     : Option<String>,
        due         : Option<Date>,
        end         : Option<Date>,
        imask       : Option<i64>,
        mask        : Option<String>,
        modified    : Option<Date>,
        parent      : Option<Uuid>,
        priority    : Option<TaskPriority>,
        project     : Option<Project>,
        recur       : Option<String>,
        scheduled   : Option<Date>,
        start       : Option<Date>,
        tags        : Option<Vec<Tag>>,
        until       : Option<Date>,
        wait        : Option<Date>,
    ) -> Task
    {
        Task {
            status      : status,
            uuid        : uuid,
            entry       : entry,
            description : description,

            annotation  : annotation,
            depends     : depends,
            due         : due,
            end         : end,
            imask       : imask,
            mask        : mask,
            modified    : modified,
            parent      : parent,
            priority    : priority,
            project     : project,
            recur       : recur,
            scheduled   : scheduled,
            start       : start,
            tags        : tags,
            until       : until,
            wait        : wait,
        }
    }

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

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

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

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

    pub fn annotation(&self) -> Option<&Vec<String>> {
        self.annotation.as_ref()
    }

    pub fn depends(&self) -> Option<&String> {
        self.depends.as_ref()
    }

    pub fn due(&self) -> Option<&Date> {
        self.due.as_ref()
    }

    pub fn end(&self) -> Option<&Date> {
        self.end.as_ref()
    }

    pub fn imask(&self) -> Option<&i64> {
        self.imask.as_ref()
    }

    pub fn mask(&self) -> Option<&String> {
        self.mask.as_ref()
    }

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

    pub fn parent(&self) -> Option<&Uuid> {
        self.parent.as_ref()
    }

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

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

    pub fn recur(&self) -> Option<&String> {
        self.recur.as_ref()
    }

    pub fn scheduled(&self) -> Option<&Date> {
        self.scheduled.as_ref()
    }

    pub fn start(&self) -> Option<&Date> {
        self.start.as_ref()
    }

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

    pub fn until(&self) -> Option<&Date> {
        self.until.as_ref()
    }

    pub fn wait(&self) -> Option<&Date> {
        self.wait.as_ref()
    }

}

impl Serialize for Task {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_struct("Task", TaskVisitor {
            value: self,
            state: 0,
        })
    }

}

struct TaskVisitor<'a> {
    value: &'a Task,
    state: u8,
}

impl<'a> MapVisitor for TaskVisitor<'a> {

    fn visit<S>(&mut self, serializer: &mut S) -> RResult<Option<()>, S::Error>
        where S: Serializer
    {
        match self.state {
            0 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("status", &self.value.status))))
            },
            1 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("uuid", &self.value.uuid))))
            },
            2 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("entry", &self.value.entry))))
            },
            3 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("description", &self.value.description))))
            },
            4 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("annotation", &self.value.annotation))))
            },
            5 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("depends", &self.value.depends))))
            },
            6 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("due", &self.value.due))))
            },
            7 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("end", &self.value.end))))
            },
            8 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("imask", &self.value.imask))))
            },
            9 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("mask", &self.value.mask))))
            },
            10 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("modified", &self.value.modified))))
            },
            11 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("parent", &self.value.parent))))
            },
            12 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("priority", &self.value.priority))))
            },
            13 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("project", &self.value.project))))
            },
            14 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("recur", &self.value.recur))))
            },
            15 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("scheduled", &self.value.scheduled))))
            },
            16 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("start", &self.value.start))))
            },
            17 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("tags", &self.value.tags))))
            },
            18 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("until", &self.value.until))))
            },
            19 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("wait", &self.value.wait))))
            },
            _ => {
                Ok(None)
            }
        }
    }

}

impl Deserialize for Task {

    fn deserialize<D>(deserializer: &mut D) -> RResult<Task, D::Error>
        where D: Deserializer
    {
        static FIELDS: &'static [&'static str] = &[
            "status",
            "uuid",
            "entry",
            "description",

            "annotation",
            "depends",
            "due",
            "end",
            "imask",
            "mask",
            "modified",
            "parent",
            "priority",
            "project",
            "recur",
            "scheduled",
            "start",
            "tags",
            "until",
            "wait"
        ];
        deserializer.deserialize_struct("Task", FIELDS, TaskDeserializeVisitor)
    }

}

struct TaskDeserializeVisitor;

impl Visitor for TaskDeserializeVisitor {
    type Value = Task;

    fn visit_map<V>(&mut self, mut visitor: V) -> RResult<Task, V::Error>
        where V: DeserializeMapVisitor
    {
        let mut status      = None;
        let mut uuid        = None;
        let mut entry       = None;
        let mut description = None;

        let mut annotation  = None;
        let mut depends     = None;
        let mut due         = None;
        let mut end         = None;
        let mut imask       = None;
        let mut mask        = None;
        let mut modified    = None;
        let mut parent      = None;
        let mut priority    = None;
        let mut project     = None;
        let mut recur       = None;
        let mut scheduled   = None;
        let mut start       = None;
        let mut tags        = None;
        let mut until       = None;
        let mut wait        = None;

        loop {
            let key : Option<String> = try!(visitor.visit_key());
            if key.is_none() {
                break;
            }
            let key = key.unwrap();

            match &key[..] {
                "status" => {
                    status = Some(try!(visitor.visit_value()));
                },
                "uuid" => {
                    uuid = Some(try!(visitor.visit_value()));
                },
                "entry" => {
                    entry = Some(try!(visitor.visit_value()));
                },
                "description" => {
                    description = Some(try!(visitor.visit_value()));
                },

                "annotation" => {
                    annotation = Some(try!(visitor.visit_value()));
                },
                "depends" => {
                    depends = Some(try!(visitor.visit_value()));
                },
                "due" => {
                    due = Some(try!(visitor.visit_value()));
                },
                "end" => {
                    end = Some(try!(visitor.visit_value()));
                },
                "imask" => {
                    imask = Some(try!(visitor.visit_value()));
                },
                "mask" => {
                    mask = Some(try!(visitor.visit_value()));
                },
                "modified" => {
                    modified = Some(try!(visitor.visit_value()));
                },
                "parent" => {
                    parent = Some(try!(visitor.visit_value()));
                },
                "priority" => {
                    priority = Some(try!(visitor.visit_value()));
                },
                "project" => {
                    project = Some(try!(visitor.visit_value()));
                },
                "recur" => {
                    recur = Some(try!(visitor.visit_value()));
                },
                "scheduled" => {
                    scheduled = Some(try!(visitor.visit_value()));
                },
                "start" => {
                    start = Some(try!(visitor.visit_value()));
                },
                "tags" => {
                    tags = Some(try!(visitor.visit_value()));
                },
                "until" => {
                    until = Some(try!(visitor.visit_value()));
                },
                "wait" => {
                    wait = Some(try!(visitor.visit_value()));
                },

                field => debug!("field '{}' ignored", field),
            }
        }

        let status = match status {
            Some(status) => status,
            None => try!(visitor.missing_field("status")),
        };

        let uuid = match uuid {
            Some(uuid) => uuid,
            None => try!(visitor.missing_field("uuid")),
        };

        let entry = match entry {
            Some(entry) => entry,
            None => try!(visitor.missing_field("entry")),
        };

        let description = match description {
            Some(description) => description,
            None => try!(visitor.missing_field("description")),
        };

        try!(visitor.end());

        let task = Task::new(
            status,
            uuid,
            entry,
            description,

            annotation,
            depends,
            due,
            end,
            imask,
            mask,
            modified,
            parent,
            priority,
            project,
            recur,
            scheduled,
            start,
            tags,
            until,
            wait
        );

        Ok(task)
    }
}

#[cfg(test)]
mod test {
    use date::Date;
    use date::TASKWARRIOR_DATETIME_TEMPLATE;
    use priority::TaskPriority;
    use project::Project;
    use status::TaskStatus;
    use tag::Tag;
    use task::Task;

    use uuid::Uuid;
    use chrono::naive::datetime::NaiveDateTime;
    use serde_json;

    #[test]
    fn test_deser() {
        let s =
r#"{
"id": 1,
"description": "test",
"entry": "20150619T165438Z",
"status": "waiting",
"uuid": "8ca953d5-18b4-4eb9-bd56-18f2e5b752f0"
}"#;

        println!("{}", s);

        let task = serde_json::from_str(s);
        println!("{:?}", task);
        assert!(task.is_ok());
        let task : Task = task.unwrap();

        assert!(task.status().clone() == TaskStatus::Waiting);
        assert!(task.description() == "test");
        assert!(task.entry().clone() == Date::from(NaiveDateTime::parse_from_str("20150619T165438Z", TASKWARRIOR_DATETIME_TEMPLATE).unwrap()));
        assert!(task.uuid().clone() == Uuid::parse_str("8ca953d5-18b4-4eb9-bd56-18f2e5b752f0").unwrap());

        let back = serde_json::to_string(&task).unwrap();

        assert!(back.contains("description"));
        assert!(back.contains("test"));
        assert!(back.contains("entry"));
        assert!(back.contains("20150619T165438Z"));
        assert!(back.contains("status"));
        assert!(back.contains("waiting"));
        assert!(back.contains("uuid"));
        assert!(back.contains("8ca953d5-18b4-4eb9-bd56-18f2e5b752f0"));
    }

}

<|endoftext|>