<commit_before>//! Definition of Thinkerbell scripts.
//!
//! Typical applications will not interact with script
//! objects. Rather, they will use module `parse` to parse a script
//! and module `run` to execute it.

use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::*;

use std::marker::PhantomData;

/// A thinkerbell scrip"t.
#[derive(Debug)]
pub struct Script<Ctx> where Ctx: Context {
    pub name: String,

    /// A set of rules, stating what must be done in which circumstance.
    pub rules: Vec<Rule<Ctx>>,

    pub phantom: PhantomData<Ctx>,
}

impl Parser<Script<UncheckedCtx>> for Script<UncheckedCtx> {
    fn description() -> String {
        "Script".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let name =  try!(path.push("", |path| String::take(path, source, "name")));
        let rules = try!(path.push("", |path| Rule::take_vec(path, source, "rules")));
        Ok(Script {
            name: name,
            rules: rules,
            phantom: PhantomData
        })
    }
}

/// A single rule, i.e. "when some condition becomes true, do
/// something".
///
/// # JSON
///
/// A single rule is represented as an object with the following fields:
///
/// - conditions (array of Match): the conditions in which to execute
///   the code – *all* conditions must be met;
/// - execute (array of Statement): the code to execute once all conditions
///   are met.
///
/// ```
/// extern crate foxbox_thinkerbell;
/// extern crate foxbox_taxonomy;
///
/// use foxbox_thinkerbell::ast::*;
/// use foxbox_taxonomy::parse::*;
///
/// # fn main() {
/// let source = r#"{
///   "conditions": [{
///     "source": [{"id": "my getter"}],
///     "kind": "OvenTemperature",
///     "range": {"Geq": {"Temperature": {"C": 300}}},
///     "duration": 3600
///   }],
///   "execute": [{
///     "destination": [{"id": "my setter"}],
///     "value": {"OnOff": "Off"},
///     "kind": "LightOn"
///   }]
/// }"#;
///
/// Rule::<UncheckedCtx>::from_str(&source).unwrap();
/// # }
/// ```
#[derive(Debug)]
pub struct Rule<Ctx> where Ctx: Context {
    /// The condition in which to execute the trigger. The condition
    /// is matched once *all* the `Match` branches are true. Whenever
    /// `conditions` was false and becomes true, we execute `execute`.
    pub conditions: Vec<Match<Ctx>>,

    /// Stuff to do once `condition` is met.
    pub execute: Vec<Statement<Ctx>>,

    pub phantom: PhantomData<Ctx>,
}
impl Parser<Rule<UncheckedCtx>> for Rule<UncheckedCtx> {
    fn description() -> String {
        "Rule".to_owned()
    }

    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let conditions = try!(path.push("conditions",
            |path| Match::take_vec(path, source, "conditions"))
        );
        let execute = try!(path.push("execute",
            |path| Statement::take_vec(path, source, "execute"))
        );
        Ok(Rule {
            conditions: conditions,
            execute: execute,
            phantom: PhantomData,
        })
    }
}

/// An individual match.
///
/// Matchs always take the form: "data received from getter channel
/// enters given range".
///
/// A condition is true if *any* of the corresponding getter channels
/// yielded a value that enters the given range.
///
/// # JSON
///
/// A match is represented as an object with the following fields:
///
/// - source (array of GetterSelector) - the selector for getters that will
///   provide the data;
/// - kind (ChannelKind) - the kind of getters;
/// - range (Range) - the condition in whih the match is considered met –
///   a match becomes met when any of the sources *enters* the range;
/// - duration (Duration, optional) - if provided, the match is only considered
///   met if any of the sources *enters* and *remains* in the range
///   for `duration`
///
/// ```
/// extern crate foxbox_thinkerbell;
/// extern crate foxbox_taxonomy;
///
/// use foxbox_thinkerbell::ast::*;
/// use foxbox_taxonomy::services::*;
/// use foxbox_taxonomy::parse::*;
///
/// # fn main() {
/// let source = r#"{
///   "source": [{"id": "my getter"}],
///   "kind": "OvenTemperature",
///   "range": {"Geq": {"Temperature": {"C": 300}}},
///   "duration": 3600
/// }"#;
///
/// let match_ = Match::<UncheckedCtx>::from_str(&source).unwrap();
/// assert_eq!(match_.kind, ChannelKind::OvenTemperature);
/// # }
/// ```
#[derive(Debug)]
pub struct Match<Ctx> where Ctx: Context {
    /// The set of getters to watch. Note that the set of getters may
    /// change (e.g. when devices are added/removed) without rebooting
    /// the script.
    pub source: Vec<GetterSelector>,

    /// The kind of channel expected from `source`, e.g. "the current
    /// time of day", "is the door opened?", etc. During compilation,
    /// we make sure that we restrict to the elements of `source` that
    /// offer `kind`.
    pub kind: ChannelKind,

    /// The range of values for which the condition is considered met.
    /// During compilation, we check that the type of `range` is
    /// compatible with that of `getter`.
    pub range: Range,

    /// If specified, the values must remain in the `range` for at least
    /// `duration` before the match is considered valid. This is useful
    /// for sensors that may oscillate around a threshold or for detecting
    /// e.g. that a door has been forgotten open.
    pub duration: Option<Duration>,

    pub phantom: PhantomData<Ctx>,
}
impl Parser<Match<UncheckedCtx>> for Match<UncheckedCtx> {
    fn description() -> String {
        "Match".to_owned()
    }

    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let sources = try!(path.push("source",
            |path| GetterSelector::take_vec(path, source, "source"))
        );
        let kind = try!(path.push("kind",
            |path| ChannelKind::take(path, source, "kind"))
        );
        let range = try!(path.push("range",
            |path| Range::take(path, source, "range"))
        );
        let duration = match path.push("range",
            |path| Duration::take(path, source, "duration"))
        {
            Err(ParseError::MissingField {..}) => None,
            Err(err) => return Err(err),
            Ok(ok) => Some(ok)
        };
        Ok(Match {
            source: sources,
            kind: kind,
            range: range,
            duration: duration,
            phantom: PhantomData,
        })
    }
}

/// Stuff to actually do. In practice, this means placing calls to devices.
///
/// # JSON
///
/// A statement is represented as an object with the following fields:
/// - destination (array of SetterSelector);
/// - value (Value);
/// - kind (ChannelKind);
///
/// ```
/// extern crate foxbox_thinkerbell;
/// extern crate foxbox_taxonomy;
///
/// use foxbox_thinkerbell::ast::*;
/// use foxbox_taxonomy::values::*;
/// use foxbox_taxonomy::services::*;
/// use foxbox_taxonomy::parse::*;
///
/// # fn main() {
/// let source = r#"{
///   "destination": [{"id": "my setter"}],
///   "value": {"OnOff": "Off"},
///   "kind": "LightOn"
/// }"#;
///
/// let statement = Statement::<UncheckedCtx>::from_str(&source).unwrap();
/// assert_eq!(statement.value, Value::OnOff(OnOff::Off));
/// assert_eq!(statement.kind, ChannelKind::LightOn);
/// # }
/// ```
#[derive(Debug)]
pub struct Statement<Ctx> where Ctx: Context {
    /// The set of setters to which to send a command. Note that the
    /// set of setters may change (e.g. when devices are
    /// added/removed) without rebooting the script.
    pub destination: Vec<SetterSelector>,

    /// Data to send to the resource. During compilation, we check
    /// that the type of `value` is compatible with that of
    /// `destination`.
    pub value: Value,

    /// The kind of channel expected from `destination`, e.g. "close
    /// the door", "set the temperature", etc. During compilation, we
    /// make sure that we restrict to the elements of `destination` that
    /// offer `kind`.
    pub kind: ChannelKind,

    pub phantom: PhantomData<Ctx>,
}
impl Parser<Statement<UncheckedCtx>> for Statement<UncheckedCtx> {
    fn description() -> String {
        "Parser".to_owned()
    }

    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let destination = try!(path.push("destination",
            |path| SetterSelector::take_vec(path, source, "destination"))
        );
        let kind = try!(path.push("kind",
            |path| ChannelKind::take(path, source, "kind"))
        );
        let value = try!(path.push("value",
            |path| Value::take(path, source, "value"))
        );
        Ok(Statement {
            destination: destination,
            value: value,
            kind: kind,
            phantom: PhantomData,
        })
    }
}

/// A manner of representing internal nodes.
///
/// Two data structures implement `Context`:
///
/// - `UncheckedCtx`, designed to mark the fact that a script has not
/// been compiled/checked yet and must not be executed;
/// - `compile::CompiledCtx`, designed to mark the fact that a script
/// has been compiled and can be executed.
pub trait Context {
}

/// A Context used to represent a script that hasn't been compiled
/// yet.
#[derive(Debug)]
pub struct UncheckedCtx;
impl Context for UncheckedCtx {
}

<commit_msg>Improved error messages<commit_after>//! Definition of Thinkerbell scripts.
//!
//! Typical applications will not interact with script
//! objects. Rather, they will use module `parse` to parse a script
//! and module `run` to execute it.

use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::*;

use std::marker::PhantomData;

/// A thinkerbell scrip"t.
#[derive(Debug)]
pub struct Script<Ctx> where Ctx: Context {
    pub name: String,

    /// A set of rules, stating what must be done in which circumstance.
    pub rules: Vec<Rule<Ctx>>,

    pub phantom: PhantomData<Ctx>,
}

impl Parser<Script<UncheckedCtx>> for Script<UncheckedCtx> {
    fn description() -> String {
        "Script".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let name =  try!(path.push("recipe", |path| String::take(path, source, "name")));
        let rules = try!(path.push("recipe", |path| Rule::take_vec(path, source, "rules")));
        Ok(Script {
            name: name,
            rules: rules,
            phantom: PhantomData
        })
    }
}

/// A single rule, i.e. "when some condition becomes true, do
/// something".
///
/// # JSON
///
/// A single rule is represented as an object with the following fields:
///
/// - conditions (array of Match): the conditions in which to execute
///   the code – *all* conditions must be met;
/// - execute (array of Statement): the code to execute once all conditions
///   are met.
///
/// ```
/// extern crate foxbox_thinkerbell;
/// extern crate foxbox_taxonomy;
///
/// use foxbox_thinkerbell::ast::*;
/// use foxbox_taxonomy::parse::*;
///
/// # fn main() {
/// let source = r#"{
///   "conditions": [{
///     "source": [{"id": "my getter"}],
///     "kind": "OvenTemperature",
///     "range": {"Geq": {"Temperature": {"C": 300}}},
///     "duration": 3600
///   }],
///   "execute": [{
///     "destination": [{"id": "my setter"}],
///     "value": {"OnOff": "Off"},
///     "kind": "LightOn"
///   }]
/// }"#;
///
/// Rule::<UncheckedCtx>::from_str(&source).unwrap();
/// # }
/// ```
#[derive(Debug)]
pub struct Rule<Ctx> where Ctx: Context {
    /// The condition in which to execute the trigger. The condition
    /// is matched once *all* the `Match` branches are true. Whenever
    /// `conditions` was false and becomes true, we execute `execute`.
    pub conditions: Vec<Match<Ctx>>,

    /// Stuff to do once `condition` is met.
    pub execute: Vec<Statement<Ctx>>,

    pub phantom: PhantomData<Ctx>,
}
impl Parser<Rule<UncheckedCtx>> for Rule<UncheckedCtx> {
    fn description() -> String {
        "Rule".to_owned()
    }

    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let conditions = try!(path.push("conditions",
            |path| Match::take_vec(path, source, "conditions"))
        );
        let execute = try!(path.push("execute",
            |path| Statement::take_vec(path, source, "execute"))
        );
        Ok(Rule {
            conditions: conditions,
            execute: execute,
            phantom: PhantomData,
        })
    }
}

/// An individual match.
///
/// Matchs always take the form: "data received from getter channel
/// enters given range".
///
/// A condition is true if *any* of the corresponding getter channels
/// yielded a value that enters the given range.
///
/// # JSON
///
/// A match is represented as an object with the following fields:
///
/// - source (array of GetterSelector) - the selector for getters that will
///   provide the data;
/// - kind (ChannelKind) - the kind of getters;
/// - range (Range) - the condition in whih the match is considered met –
///   a match becomes met when any of the sources *enters* the range;
/// - duration (Duration, optional) - if provided, the match is only considered
///   met if any of the sources *enters* and *remains* in the range
///   for `duration`
///
/// ```
/// extern crate foxbox_thinkerbell;
/// extern crate foxbox_taxonomy;
///
/// use foxbox_thinkerbell::ast::*;
/// use foxbox_taxonomy::services::*;
/// use foxbox_taxonomy::parse::*;
///
/// # fn main() {
/// let source = r#"{
///   "source": [{"id": "my getter"}],
///   "kind": "OvenTemperature",
///   "range": {"Geq": {"Temperature": {"C": 300}}},
///   "duration": 3600
/// }"#;
///
/// let match_ = Match::<UncheckedCtx>::from_str(&source).unwrap();
/// assert_eq!(match_.kind, ChannelKind::OvenTemperature);
/// # }
/// ```
#[derive(Debug)]
pub struct Match<Ctx> where Ctx: Context {
    /// The set of getters to watch. Note that the set of getters may
    /// change (e.g. when devices are added/removed) without rebooting
    /// the script.
    pub source: Vec<GetterSelector>,

    /// The kind of channel expected from `source`, e.g. "the current
    /// time of day", "is the door opened?", etc. During compilation,
    /// we make sure that we restrict to the elements of `source` that
    /// offer `kind`.
    pub kind: ChannelKind,

    /// The range of values for which the condition is considered met.
    /// During compilation, we check that the type of `range` is
    /// compatible with that of `getter`.
    pub range: Range,

    /// If specified, the values must remain in the `range` for at least
    /// `duration` before the match is considered valid. This is useful
    /// for sensors that may oscillate around a threshold or for detecting
    /// e.g. that a door has been forgotten open.
    pub duration: Option<Duration>,

    pub phantom: PhantomData<Ctx>,
}
impl Parser<Match<UncheckedCtx>> for Match<UncheckedCtx> {
    fn description() -> String {
        "Match".to_owned()
    }

    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let sources = try!(path.push("source",
            |path| GetterSelector::take_vec(path, source, "source"))
        );
        let kind = try!(path.push("kind",
            |path| ChannelKind::take(path, source, "kind"))
        );
        let range = try!(path.push("range",
            |path| Range::take(path, source, "range"))
        );
        let duration = match path.push("range",
            |path| Duration::take(path, source, "duration"))
        {
            Err(ParseError::MissingField {..}) => None,
            Err(err) => return Err(err),
            Ok(ok) => Some(ok)
        };
        Ok(Match {
            source: sources,
            kind: kind,
            range: range,
            duration: duration,
            phantom: PhantomData,
        })
    }
}

/// Stuff to actually do. In practice, this means placing calls to devices.
///
/// # JSON
///
/// A statement is represented as an object with the following fields:
/// - destination (array of SetterSelector);
/// - value (Value);
/// - kind (ChannelKind);
///
/// ```
/// extern crate foxbox_thinkerbell;
/// extern crate foxbox_taxonomy;
///
/// use foxbox_thinkerbell::ast::*;
/// use foxbox_taxonomy::values::*;
/// use foxbox_taxonomy::services::*;
/// use foxbox_taxonomy::parse::*;
///
/// # fn main() {
/// let source = r#"{
///   "destination": [{"id": "my setter"}],
///   "value": {"OnOff": "Off"},
///   "kind": "LightOn"
/// }"#;
///
/// let statement = Statement::<UncheckedCtx>::from_str(&source).unwrap();
/// assert_eq!(statement.value, Value::OnOff(OnOff::Off));
/// assert_eq!(statement.kind, ChannelKind::LightOn);
/// # }
/// ```
#[derive(Debug)]
pub struct Statement<Ctx> where Ctx: Context {
    /// The set of setters to which to send a command. Note that the
    /// set of setters may change (e.g. when devices are
    /// added/removed) without rebooting the script.
    pub destination: Vec<SetterSelector>,

    /// Data to send to the resource. During compilation, we check
    /// that the type of `value` is compatible with that of
    /// `destination`.
    pub value: Value,

    /// The kind of channel expected from `destination`, e.g. "close
    /// the door", "set the temperature", etc. During compilation, we
    /// make sure that we restrict to the elements of `destination` that
    /// offer `kind`.
    pub kind: ChannelKind,

    pub phantom: PhantomData<Ctx>,
}
impl Parser<Statement<UncheckedCtx>> for Statement<UncheckedCtx> {
    fn description() -> String {
        "Parser".to_owned()
    }

    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        let destination = try!(path.push("destination",
            |path| SetterSelector::take_vec(path, source, "destination"))
        );
        let kind = try!(path.push("kind",
            |path| ChannelKind::take(path, source, "kind"))
        );
        let value = try!(path.push("value",
            |path| Value::take(path, source, "value"))
        );
        Ok(Statement {
            destination: destination,
            value: value,
            kind: kind,
            phantom: PhantomData,
        })
    }
}

/// A manner of representing internal nodes.
///
/// Two data structures implement `Context`:
///
/// - `UncheckedCtx`, designed to mark the fact that a script has not
/// been compiled/checked yet and must not be executed;
/// - `compile::CompiledCtx`, designed to mark the fact that a script
/// has been compiled and can be executed.
pub trait Context {
}

/// A Context used to represent a script that hasn't been compiled
/// yet.
#[derive(Debug)]
pub struct UncheckedCtx;
impl Context for UncheckedCtx {
}

<|endoftext|>


<commit_before>extern crate glutin;
extern crate trdl;

use std::os::raw::c_void;

fn make_shape(off_x: f32, off_y: f32) -> (trdl::FilledPath) {
    let a0 = (150f32 + off_x, 150f32 + off_y);
    let b0 = (300f32 + off_x, 200f32 + off_y);
    let bc1 = (350f32 + off_x, 250f32 + off_y);
    let bc2 = (200f32 + off_x, 250f32 + off_y);
    let c0 = (200f32 + off_x, 300f32 + off_y);
    let d0 = (50f32 + off_x, 100f32 + off_y);
    let de1 = (0f32 + off_x, 50f32 + off_y);
    let de2 = (50f32 + off_x, 0f32 + off_y);
    let e0 = (150f32 + off_x, 0f32 + off_y);

    trdl::FilledPath::with_num_vertices(5).
        add_straight_line(a0).
        add_bezier_curve(b0, bc1, bc2).
        add_straight_line(c0).
        add_bezier_curve(d0, de1, de2).
        add_straight_line(e0).
        set_fill_color(1f32, 1f32, 0f32).
        set_stroke(0f32, 0f32, 1f32, 2)
}

struct Window {
    w: glutin::Window
}

impl trdl::Window for Window {
    fn set_context(&self) {
        unsafe { self.w.make_current().unwrap() };
    }
    fn load_fn(&self, addr: &str) -> *const c_void {
        self.w.get_proc_address(addr) as *const c_void
    }
 }

fn main() {
    let window_size = (1024, 768);
    let window = Window {
        w: glutin::WindowBuilder::new().
        with_dimensions(window_size.0, window_size.1).
        with_title("TRDL Test").
        build().unwrap() };

    let mut drawing = trdl::Drawing::new(&window, window_size.0, window_size.1);

    let mut depth_idx = 0u32;
    let sqrt_size = 10u32;
    let num_shapes = sqrt_size * sqrt_size;
    let wx = window_size.0 as i32 - 300i32;
    let wy = window_size.1 as i32 - 300i32;
    for i in 0..sqrt_size {
        let delta_x = wx * (i as i32) / (sqrt_size as i32);
        for j in 0..sqrt_size {
            let delta_y = wy * (j as i32) / (sqrt_size as i32);
            let depth = 1.0f32 - 2.0f32 * (depth_idx as f32) / (num_shapes as f32);
            depth_idx += 1;
            drawing.add_filled_path(make_shape(delta_x as f32, delta_y as f32), depth).unwrap();
        }
    }
    drawing.draw();
    for event in window.w.wait_events() {
        if let glutin::Event::Closed = event {
            break;
        }
        drawing.draw();
        window.w.swap_buffers().unwrap();
    }
}<commit_msg>added unwrap in main due to previous change<commit_after>extern crate glutin;
extern crate trdl;

use std::os::raw::c_void;

fn make_shape(off_x: f32, off_y: f32) -> (trdl::FilledPath) {
    let a0 = (150f32 + off_x, 150f32 + off_y);
    let b0 = (300f32 + off_x, 200f32 + off_y);
    let bc1 = (350f32 + off_x, 250f32 + off_y);
    let bc2 = (200f32 + off_x, 250f32 + off_y);
    let c0 = (200f32 + off_x, 300f32 + off_y);
    let d0 = (50f32 + off_x, 100f32 + off_y);
    let de1 = (0f32 + off_x, 50f32 + off_y);
    let de2 = (50f32 + off_x, 0f32 + off_y);
    let e0 = (150f32 + off_x, 0f32 + off_y);

    trdl::FilledPath::with_num_vertices(5).
        add_straight_line(a0).
        add_bezier_curve(b0, bc1, bc2).
        add_straight_line(c0).
        add_bezier_curve(d0, de1, de2).
        add_straight_line(e0).
        set_fill_color(1f32, 1f32, 0f32).
        set_stroke(0f32, 0f32, 1f32, 2)
}

struct Window {
    w: glutin::Window
}

impl trdl::Window for Window {
    fn set_context(&self) {
        unsafe { self.w.make_current().unwrap() };
    }
    fn load_fn(&self, addr: &str) -> *const c_void {
        self.w.get_proc_address(addr) as *const c_void
    }
 }

fn main() {
    let window_size = (1024, 768);
    let window = Window {
        w: glutin::WindowBuilder::new().
        with_dimensions(window_size.0, window_size.1).
        with_title("TRDL Test").
        build().unwrap() };

    let mut drawing = trdl::Drawing::new(&window, window_size.0, window_size.1).unwrap();

    let mut depth_idx = 0u32;
    let sqrt_size = 10u32;
    let num_shapes = sqrt_size * sqrt_size;
    let wx = window_size.0 as i32 - 300i32;
    let wy = window_size.1 as i32 - 300i32;
    for i in 0..sqrt_size {
        let delta_x = wx * (i as i32) / (sqrt_size as i32);
        for j in 0..sqrt_size {
            let delta_y = wy * (j as i32) / (sqrt_size as i32);
            let depth = 1.0f32 - 2.0f32 * (depth_idx as f32) / (num_shapes as f32);
            depth_idx += 1;
            drawing.add_filled_path(make_shape(delta_x as f32, delta_y as f32), depth).unwrap();
        }
    }
    drawing.draw();
    for event in window.w.wait_events() {
        if let glutin::Event::Closed = event {
            break;
        }
        drawing.draw();
        window.w.swap_buffers().unwrap();
    }
}<|endoftext|>


<commit_before>use std::io::{BufRead, ErrorKind, Result, Write};

/// Extends any type that implements BufRead with a stream_until_token() function.
pub trait BufReadExt: BufRead {
    /// Streams all bytes to `out` until the `token` delimiter is reached.
    ///
    /// This function will continue to read (and stream) bytes from the underlying stream until the
    /// token or end-of-file byte is found. Once found, all bytes up to the token (if found) will
    /// have been streamed to `out` and this input stream will advance past the token (the token
    /// will be discarded).
    ///
    /// This function will return `Ok(n)` where `n` is the number of bytes which were read,
    /// including the token if it was found. If the token was not found, it will still return
    /// `Ok(n)`.
    ///
    /// # Errors
    ///
    /// This function will ignore all instances of `ErrorKind::Interrupted` and will otherwise
    /// return any errors returned by `fill_buf`.
    fn stream_until_token<W: Write>(&mut self, token: &[u8], out: &mut W) -> Result<usize> {
        stream_until_token(self, token, out)
    }
}

// Implement BufReadExt for everything that implements BufRead.
impl<T: BufRead> BufReadExt for T { }

fn stream_until_token<R: BufRead + ?Sized, W: Write>(stream: &mut R, token: &[u8], mut out: &mut W)
                                                     -> Result<usize> {
    let mut read = 0;
    // Represents the size of a token prefix found at the end of a buffer, usually 0. If not 0, the
    // beginning of the next buffer is checked for the suffix to find matches that straddle two
    // buffers.
    let mut partial: usize = 0;

    loop {
        let (found, used) = {
            let buffer = match stream.fill_buf() {
                Ok(n) => n,
                Err(ref err) if err.kind() == ErrorKind::Interrupted => continue,
                Err(err) => return Err(err)
            };

            // If last buffer ended in a token prefix, check if this one starts with the matching
            // suffix.
            if partial > 0 && buffer[..token.len() - partial] == token[partial..] {
                (true, token.len() - partial)
            } else {
                if partial > 0 {
                    // Last buffer ended in a token prefix, but it didn't pan out, so we need to
                    // push it along.
                    try!( out.write_all(&token[..partial]) );
                }

                let index = buffer
                    .windows(token.len())
                    .enumerate()
                    .filter(|&(_, t)| t == token)
                    .map(|(i, _)| i)
                    .next();

                // Search for the token.
                match index {
                    Some(index) => {
                        try!(out.write_all(&buffer[..index]));
                        (true, index + token.len())
                    },
                    None => {
                        // Check for partial matches at the end of the buffer
                        let mut window = token.len() - 1;
                        if buffer.len() < window {
                            window = buffer.len();
                        }

                        partial = (1..window+1)
                            .rev()
                            .filter(|&w| token[..w] == buffer[buffer.len() - w..])
                            .next()
                            .unwrap_or(0);

                        // Push all except the partial token at the end (if any)
                        try!(out.write_all(&buffer[..buffer.len()-partial]));
                        // Mark it all as consumed.
                        (false, buffer.len())
                    }
                }
            }
        };

        stream.consume(used);
        read += used;

        if found || used == 0 {
            break;
        }
    }

    Ok(read)
}

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

    use std::io::{BufReader, Cursor};

    #[test]
    fn stream_until_token() {
        let mut buf = Cursor::new(&b"123456"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 6);
        assert_eq!(result, b"123456");
        let mut buf = Cursor::new(&b"12345678"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"34", &mut result).unwrap(), 4);
        assert_eq!(result, b"12");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 4);
        assert_eq!(result, b"56");

        let mut buf = Cursor::new(&b"bananas for nana"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 5);
        assert_eq!(result, b"ba");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 10);
        assert_eq!(result, b"as for ");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 1);
        assert_eq!(result, b"a");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 0);
        assert_eq!(result, b"");
    }

    #[test]
    fn stream_until_token_straddle_test() {
        let cursor = Cursor::new(&b"12345TOKEN345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 10);
        assert_eq!(result, b"12345");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 6);
        assert_eq!(result, b"345678");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 0);
        assert_eq!(result, b"");

        let cursor = Cursor::new(&b"12345TOKE23456781TOKEN78"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 22);
        assert_eq!(result, b"12345TOKE23456781");
    }

    #[test]
    fn stream_until_token_large_token_test() {
        let cursor = Cursor::new(&b"IAMALARGETOKEN7812345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 14);
        assert_eq!(v, b"");
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 10);
        assert_eq!(v, b"7812345678");

        let cursor = Cursor::new(&b"0IAMALARGERTOKEN12345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 16);
        assert_eq!(v, b"0");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 8);
        assert_eq!(v, b"12345678");
    }
}
<commit_msg>add tests demonstrating issues #11 and #12 (currently failing tests)<commit_after>use std::io::{BufRead, ErrorKind, Result, Write};

/// Extends any type that implements BufRead with a stream_until_token() function.
pub trait BufReadExt: BufRead {
    /// Streams all bytes to `out` until the `token` delimiter is reached.
    ///
    /// This function will continue to read (and stream) bytes from the underlying stream until the
    /// token or end-of-file byte is found. Once found, all bytes up to the token (if found) will
    /// have been streamed to `out` and this input stream will advance past the token (the token
    /// will be discarded).
    ///
    /// This function will return `Ok(n)` where `n` is the number of bytes which were read,
    /// including the token if it was found. If the token was not found, it will still return
    /// `Ok(n)`.
    ///
    /// # Errors
    ///
    /// This function will ignore all instances of `ErrorKind::Interrupted` and will otherwise
    /// return any errors returned by `fill_buf`.
    fn stream_until_token<W: Write>(&mut self, token: &[u8], out: &mut W) -> Result<usize> {
        stream_until_token(self, token, out)
    }
}

// Implement BufReadExt for everything that implements BufRead.
impl<T: BufRead> BufReadExt for T { }

fn stream_until_token<R: BufRead + ?Sized, W: Write>(stream: &mut R, token: &[u8], mut out: &mut W)
                                                     -> Result<usize> {
    let mut read = 0;
    // Represents the size of a token prefix found at the end of a buffer, usually 0. If not 0, the
    // beginning of the next buffer is checked for the suffix to find matches that straddle two
    // buffers.
    let mut partial: usize = 0;

    loop {
        let (found, used) = {
            let buffer = match stream.fill_buf() {
                Ok(n) => n,
                Err(ref err) if err.kind() == ErrorKind::Interrupted => continue,
                Err(err) => return Err(err)
            };

            // If last buffer ended in a token prefix, check if this one starts with the matching
            // suffix.
            if partial > 0 && buffer[..token.len() - partial] == token[partial..] {
                (true, token.len() - partial)
            } else {
                if partial > 0 {
                    // Last buffer ended in a token prefix, but it didn't pan out, so we need to
                    // push it along.
                    try!( out.write_all(&token[..partial]) );
                }

                let index = buffer
                    .windows(token.len())
                    .enumerate()
                    .filter(|&(_, t)| t == token)
                    .map(|(i, _)| i)
                    .next();

                // Search for the token.
                match index {
                    Some(index) => {
                        try!(out.write_all(&buffer[..index]));
                        (true, index + token.len())
                    },
                    None => {
                        // Check for partial matches at the end of the buffer
                        let mut window = token.len() - 1;
                        if buffer.len() < window {
                            window = buffer.len();
                        }

                        partial = (1..window+1)
                            .rev()
                            .filter(|&w| token[..w] == buffer[buffer.len() - w..])
                            .next()
                            .unwrap_or(0);

                        // Push all except the partial token at the end (if any)
                        try!(out.write_all(&buffer[..buffer.len()-partial]));
                        // Mark it all as consumed.
                        (false, buffer.len())
                    }
                }
            }
        };

        stream.consume(used);
        read += used;

        if found || used == 0 {
            break;
        }
    }

    Ok(read)
}

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

    use std::io::{BufReader, Cursor};

    #[test]
    fn stream_until_token() {
        let mut buf = Cursor::new(&b"123456"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 6);
        assert_eq!(result, b"123456");
        let mut buf = Cursor::new(&b"12345678"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"34", &mut result).unwrap(), 4);
        assert_eq!(result, b"12");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 4);
        assert_eq!(result, b"56");

        let mut buf = Cursor::new(&b"bananas for nana"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 5);
        assert_eq!(result, b"ba");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 10);
        assert_eq!(result, b"as for ");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 1);
        assert_eq!(result, b"a");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 0);
        assert_eq!(result, b"");
    }

    #[test]
    fn stream_until_token_straddle_test() {
        let cursor = Cursor::new(&b"12345TOKEN345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 10);
        assert_eq!(result, b"12345");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 6);
        assert_eq!(result, b"345678");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 0);
        assert_eq!(result, b"");

        let cursor = Cursor::new(&b"12345TOKE23456781TOKEN78"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 22);
        assert_eq!(result, b"12345TOKE23456781");
    }

    // This tests against github issue #1
    #[test]
    fn stream_until_token_large_token_test() {
        let cursor = Cursor::new(&b"IAMALARGETOKEN7812345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 14);
        assert_eq!(v, b"");
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 10);
        assert_eq!(v, b"7812345678");

        let cursor = Cursor::new(&b"0IAMALARGERTOKEN12345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 16);
        assert_eq!(v, b"0");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 8);
        assert_eq!(v, b"12345678");
    }

    // This tests against github issue #11
    #[test]
    fn stream_until_token_double_straddle_test() {
        let cursor = Cursor::new(&b"12345IAMALARGETOKEN4567"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 5+14);
        assert_eq!(v, b"12345");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 4);
        assert_eq!(v, b"4567");
    }

    // This tests against github issue #12
    #[test]
    fn stream_until_token_multiple_prefix_text() {
        let cursor = Cursor::new(&b"12barbarian4567"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"barbarian", &mut v).unwrap(), 2+9);
        assert_eq!(v, b"12");

        let cursor = Cursor::new(&b"12barbarbarian7812"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"barbarian", &mut v).unwrap(), 5+9);
        assert_eq!(v, b"12bar");
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use basicblock::{BasicBlock, BasicBlockEdge};
use instruction::Instruction;
use petgraph::graph::{Graph, NodeIndex};

/// A [control flow graph].
///
/// [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
pub struct CFG<'f> {
    /// The [`Graph`] that stores the actual CFG
    ///
    /// [`Graph`]: ../petgraph/graph/struct.Graph.html
    pub graph: Graph<BasicBlock<'f>, BasicBlockEdge>,
    /// The [`NodeIndex`] for the entry [`BasicBlock`] for this function.
    ///
    /// [`BasicBlock`]: struct.BasicBlock.html
    /// [`NodeIndex`]: ../petgraph/graph/struct.NodeIndex.html
    pub entry_block: Option<NodeIndex>,
}

impl<'f> CFG<'f> {
    /// Construct a new CFG
    pub fn new() -> Self {
        CFG {
            graph: Graph::new(),
            entry_block: None,
        }
    }
    pub fn build(&mut self, _instructions: &Vec<Box<Instruction>>) {}
}
<commit_msg>Stub CFG::build.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use basicblock::{BasicBlock, BasicBlockEdge};
use instruction::Instruction;
use petgraph::graph::{Graph, NodeIndex};

/// A [control flow graph].
///
/// [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
pub struct CFG<'f> {
    /// The [`Graph`] that stores the actual CFG
    ///
    /// [`Graph`]: ../petgraph/graph/struct.Graph.html
    pub graph: Graph<BasicBlock<'f>, BasicBlockEdge>,
    /// The [`NodeIndex`] for the entry [`BasicBlock`] for this function.
    ///
    /// [`BasicBlock`]: struct.BasicBlock.html
    /// [`NodeIndex`]: ../petgraph/graph/struct.NodeIndex.html
    pub entry_block: Option<NodeIndex>,
}

impl<'f> CFG<'f> {
    /// Construct a new CFG
    pub fn new() -> Self {
        CFG {
            graph: Graph::new(),
            entry_block: None,
        }
    }
    /// Build the CFG from the [`instructions`].
    ///
    /// [`instructions`]: trait.Instruction.html
    pub fn build(&mut self, instructions: &Vec<Box<Instruction>>) {
        if !instructions.is_empty() {
            let bb = BasicBlock::new(None, instructions[0].address());
            self.entry_block = Some(self.graph.add_node(bb));
        }
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use address::Address;
use basicblock::{BasicBlock, BasicBlockEdge, EdgeType};
use disassembler::Disassembler;
use instruction::Instruction;
use petgraph::graph::{Graph, NodeIndex};
use std::collections::BTreeMap;

/// A [control flow graph].
///
/// [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
pub struct ControlFlowGraph<'f, I: 'f + Instruction> {
    /// The [`Graph`] that stores the actual ControlFlowGraph
    ///
    /// [`Graph`]: ../petgraph/graph/struct.Graph.html
    pub graph: Graph<BasicBlock<'f, I>, BasicBlockEdge>,
    /// The [`NodeIndex`] for the entry [`BasicBlock`] for this function.
    ///
    /// [`BasicBlock`]: struct.BasicBlock.html
    /// [`NodeIndex`]: ../petgraph/graph/struct.NodeIndex.html
    pub entry_block: Option<NodeIndex>,
    /// Map an [address] to the corresponding [basic block].
    ///
    /// [address]: struct.Address.html
    /// [basic block]: struct.BasicBlock.html
    pub block_finder: BTreeMap<Address, NodeIndex>,
}

impl<'f, I: Instruction> ControlFlowGraph<'f, I> {
    /// Build the ControlFlowGraph from the [`instructions`].
    ///
    /// This is conducted in a 2 step process:
    ///
    /// * First, each instruction is examined to identify block boundaries.
    /// * Then, we go through each instruction again, looking for the
    ///   previously identified block boundaries and build the edges.
    ///
    /// This two step process prevents us from having to construct and then
    /// subsequently split blocks as we find backward edges.
    ///
    /// [`instructions`]: trait.Instruction.html
    pub fn new(instructions: &'f [I], disassembler: &Disassembler) -> Self {
        let mut cfg = ControlFlowGraph {
            graph: Graph::new(),
            entry_block: None,
            block_finder: BTreeMap::new(),
        };
        if !instructions.is_empty() {
            cfg.identify_blocks(instructions, disassembler);
            cfg.build_edges(instructions, disassembler);
        }
        cfg
    }

    /// Identify basic blocks by their boundaries.
    ///
    /// Inspect each instruction to see if it is a 'leader' or the start of
    /// a new basic block. An instruction is a leader if:
    ///
    /// * It is the first instruction in the basic block.
    /// * It comes after a branch of any sort. We identify these as things
    ///   for which `Instruction::is_block_terminator` returns `true`.
    /// * It is the target of a jump (conditional or unconditional) within
    ///   the function.
    fn identify_blocks(&mut self, instructions: &[I], disassembler: &Disassembler) {
        let start_addr = instructions[0].address(disassembler);
        let end_addr = instructions.last().map(|i| i.address(disassembler)).unwrap();
        let mut next_is_leader: bool = true;
        for inst in instructions {
            if next_is_leader {
                let idx = self.graph.add_node(BasicBlock::new(inst.address(disassembler)));
                self.block_finder.insert(inst.address(disassembler), idx);
                next_is_leader = false;
            }
            if inst.is_block_terminator(disassembler) {
                if let Some(target_addr) = inst.target_address(disassembler) {
                    if !self.block_finder.contains_key(&target_addr) &&
                       target_addr >= start_addr && target_addr <= end_addr {
                        let idx = self.graph.add_node(BasicBlock::new(target_addr));
                        self.block_finder.insert(target_addr, idx);
                    }
                }
                // The next instruction, if any, will be the start of a new block.
                next_is_leader = true;
            }
        }
        self.entry_block =
            Some(*self.block_finder.get(&instructions[0].address(disassembler)).unwrap());
    }

    /// Build an edge between 2 basic blocks.
    fn build_edge(&mut self,
                  current_block_idx: NodeIndex,
                  next_block_idx: NodeIndex,
                  current_inst: &I,
                  disassembler: &Disassembler) {
        if current_inst.is_local_conditional_jump(disassembler) {
            // We have one edge for the jump target and one for the fallthrough.
            // We jump through some hoops here to keep the borrow checker happy.
            if let Some(target_addr) = current_inst.target_address(disassembler) {
                if let Some(target_block_idx) = self.block_finder.get(&target_addr) {
                    let edge = BasicBlockEdge { edge_type: EdgeType::ConditionalTaken };
                    self.graph.add_edge(current_block_idx, *target_block_idx, edge);
                }
                let edge = BasicBlockEdge { edge_type: EdgeType::ConditionalFallthrough };
                self.graph.add_edge(current_block_idx, next_block_idx, edge);
            }
        } else if current_inst.is_local_jump(disassembler) || current_inst.is_call(disassembler) {
            let edge = BasicBlockEdge { edge_type: EdgeType::Unconditional };
            self.graph.add_edge(current_block_idx, next_block_idx, edge);
        } else if current_inst.is_return(disassembler) {
            // Do we want to record this exit anywhere?
        }
    }

    /// Build edges after having identified the basic blocks.
    ///
    /// After the basic blocks have been identified, we can go back and
    /// connect the basic blocks with their appropriate edges.
    ///
    /// We do this by iterating through the instructions looking for
    /// boundaries between the basic blocks and then setting up the
    /// new edges.
    fn build_edges(&mut self, instructions: &'f [I], disassembler: &Disassembler) {
        // Here, we're going to walk through the instructions again,
        // looking at the current instruction, while also maintaining
        // a separate iterator giving us the next instruction (if there
        // is one.
        let current_inst_iter = instructions.iter();
        let mut next_inst_iter = current_inst_iter.clone();
        // Skip the first one so that we're actually working with the next one.
        next_inst_iter.next();
        let mut current_block_idx = self.entry_block.unwrap();
        for current_inst in current_inst_iter {
            // Add this instruction to the current block
            if let Some(current_block) = self.graph.node_weight_mut(current_block_idx) {
                current_block.instructions.push(current_inst);
            }
            if let Some(next_inst) = next_inst_iter.next() {
                // Does the next instruction begin a basic block?
                let next_block_idx = *self.block_finder
                                          .get(&next_inst.address(disassembler))
                                          .unwrap_or(&current_block_idx);
                // If we're at a block boundary, create an edge between the
                // current and next blocks. The type of the edge is determined
                // by looking at the current instruction.
                if next_block_idx != current_block_idx {
                    self.build_edge(current_block_idx,
                                    next_block_idx,
                                    current_inst,
                                    disassembler);
                    current_block_idx = next_block_idx;
                }
            } else {
                // No next instruction, so we're at the end.
                // Do we want to record this exit anywhere?
            }
        }
    }
}

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

    #[test]
    fn construct() {
        let insts: Vec<TestInstruction> = vec![];
        let disasm = TestDisassembler::new();
        let cfg = ControlFlowGraph::new(&insts, &disasm);
        assert!(cfg.entry_block.is_none());
        assert_eq!(cfg.graph.node_count(), 0);
    }

    #[test]
    fn build_one_basic_block() {
        let insts = [TestInstruction::new(0, Opcode::Add),
                     TestInstruction::new(1, Opcode::Add),
                     TestInstruction::new(2, Opcode::Ret)];
        let disasm = TestDisassembler::new();
        let cfg = ControlFlowGraph::new(&insts, &disasm);
        assert!(cfg.entry_block.is_some());
        assert_eq!(cfg.graph.node_count(), 1);

        let inbound = cfg.graph.externals(EdgeDirection::Incoming);
        assert_eq!(inbound.count(), 1);

        let outbound = cfg.graph.externals(EdgeDirection::Outgoing);
        assert_eq!(outbound.count(), 1);
    }
}
<commit_msg>Clippy fix.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use address::Address;
use basicblock::{BasicBlock, BasicBlockEdge, EdgeType};
use disassembler::Disassembler;
use instruction::Instruction;
use petgraph::graph::{Graph, NodeIndex};
use std::collections::BTreeMap;

/// A [control flow graph].
///
/// [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
pub struct ControlFlowGraph<'f, I: 'f + Instruction> {
    /// The [`Graph`] that stores the actual ControlFlowGraph
    ///
    /// [`Graph`]: ../petgraph/graph/struct.Graph.html
    pub graph: Graph<BasicBlock<'f, I>, BasicBlockEdge>,
    /// The [`NodeIndex`] for the entry [`BasicBlock`] for this function.
    ///
    /// [`BasicBlock`]: struct.BasicBlock.html
    /// [`NodeIndex`]: ../petgraph/graph/struct.NodeIndex.html
    pub entry_block: Option<NodeIndex>,
    /// Map an [address] to the corresponding [basic block].
    ///
    /// [address]: struct.Address.html
    /// [basic block]: struct.BasicBlock.html
    pub block_finder: BTreeMap<Address, NodeIndex>,
}

impl<'f, I: Instruction> ControlFlowGraph<'f, I> {
    /// Build the ControlFlowGraph from the [`instructions`].
    ///
    /// This is conducted in a 2 step process:
    ///
    /// * First, each instruction is examined to identify block boundaries.
    /// * Then, we go through each instruction again, looking for the
    ///   previously identified block boundaries and build the edges.
    ///
    /// This two step process prevents us from having to construct and then
    /// subsequently split blocks as we find backward edges.
    ///
    /// [`instructions`]: trait.Instruction.html
    pub fn new(instructions: &'f [I], disassembler: &Disassembler) -> Self {
        let mut cfg = ControlFlowGraph {
            graph: Graph::new(),
            entry_block: None,
            block_finder: BTreeMap::new(),
        };
        if !instructions.is_empty() {
            cfg.identify_blocks(instructions, disassembler);
            cfg.build_edges(instructions, disassembler);
        }
        cfg
    }

    /// Identify basic blocks by their boundaries.
    ///
    /// Inspect each instruction to see if it is a 'leader' or the start of
    /// a new basic block. An instruction is a leader if:
    ///
    /// * It is the first instruction in the basic block.
    /// * It comes after a branch of any sort. We identify these as things
    ///   for which `Instruction::is_block_terminator` returns `true`.
    /// * It is the target of a jump (conditional or unconditional) within
    ///   the function.
    fn identify_blocks(&mut self, instructions: &[I], disassembler: &Disassembler) {
        let start_addr = instructions[0].address(disassembler);
        let end_addr = instructions.last().map(|i| i.address(disassembler)).unwrap();
        let mut next_is_leader: bool = true;
        for inst in instructions {
            if next_is_leader {
                let idx = self.graph.add_node(BasicBlock::new(inst.address(disassembler)));
                self.block_finder.insert(inst.address(disassembler), idx);
                next_is_leader = false;
            }
            if inst.is_block_terminator(disassembler) {
                if let Some(target_addr) = inst.target_address(disassembler) {
                    if !self.block_finder.contains_key(&target_addr) &&
                       target_addr >= start_addr && target_addr <= end_addr {
                        let idx = self.graph.add_node(BasicBlock::new(target_addr));
                        self.block_finder.insert(target_addr, idx);
                    }
                }
                // The next instruction, if any, will be the start of a new block.
                next_is_leader = true;
            }
        }
        self.entry_block = Some(self.block_finder[&instructions[0].address(disassembler)]);
    }

    /// Build an edge between 2 basic blocks.
    fn build_edge(&mut self,
                  current_block_idx: NodeIndex,
                  next_block_idx: NodeIndex,
                  current_inst: &I,
                  disassembler: &Disassembler) {
        if current_inst.is_local_conditional_jump(disassembler) {
            // We have one edge for the jump target and one for the fallthrough.
            // We jump through some hoops here to keep the borrow checker happy.
            if let Some(target_addr) = current_inst.target_address(disassembler) {
                if let Some(target_block_idx) = self.block_finder.get(&target_addr) {
                    let edge = BasicBlockEdge { edge_type: EdgeType::ConditionalTaken };
                    self.graph.add_edge(current_block_idx, *target_block_idx, edge);
                }
                let edge = BasicBlockEdge { edge_type: EdgeType::ConditionalFallthrough };
                self.graph.add_edge(current_block_idx, next_block_idx, edge);
            }
        } else if current_inst.is_local_jump(disassembler) || current_inst.is_call(disassembler) {
            let edge = BasicBlockEdge { edge_type: EdgeType::Unconditional };
            self.graph.add_edge(current_block_idx, next_block_idx, edge);
        } else if current_inst.is_return(disassembler) {
            // Do we want to record this exit anywhere?
        }
    }

    /// Build edges after having identified the basic blocks.
    ///
    /// After the basic blocks have been identified, we can go back and
    /// connect the basic blocks with their appropriate edges.
    ///
    /// We do this by iterating through the instructions looking for
    /// boundaries between the basic blocks and then setting up the
    /// new edges.
    fn build_edges(&mut self, instructions: &'f [I], disassembler: &Disassembler) {
        // Here, we're going to walk through the instructions again,
        // looking at the current instruction, while also maintaining
        // a separate iterator giving us the next instruction (if there
        // is one.
        let current_inst_iter = instructions.iter();
        let mut next_inst_iter = current_inst_iter.clone();
        // Skip the first one so that we're actually working with the next one.
        next_inst_iter.next();
        let mut current_block_idx = self.entry_block.unwrap();
        for current_inst in current_inst_iter {
            // Add this instruction to the current block
            if let Some(current_block) = self.graph.node_weight_mut(current_block_idx) {
                current_block.instructions.push(current_inst);
            }
            if let Some(next_inst) = next_inst_iter.next() {
                // Does the next instruction begin a basic block?
                let next_block_idx = *self.block_finder
                                          .get(&next_inst.address(disassembler))
                                          .unwrap_or(&current_block_idx);
                // If we're at a block boundary, create an edge between the
                // current and next blocks. The type of the edge is determined
                // by looking at the current instruction.
                if next_block_idx != current_block_idx {
                    self.build_edge(current_block_idx,
                                    next_block_idx,
                                    current_inst,
                                    disassembler);
                    current_block_idx = next_block_idx;
                }
            } else {
                // No next instruction, so we're at the end.
                // Do we want to record this exit anywhere?
            }
        }
    }
}

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

    #[test]
    fn construct() {
        let insts: Vec<TestInstruction> = vec![];
        let disasm = TestDisassembler::new();
        let cfg = ControlFlowGraph::new(&insts, &disasm);
        assert!(cfg.entry_block.is_none());
        assert_eq!(cfg.graph.node_count(), 0);
    }

    #[test]
    fn build_one_basic_block() {
        let insts = [TestInstruction::new(0, Opcode::Add),
                     TestInstruction::new(1, Opcode::Add),
                     TestInstruction::new(2, Opcode::Ret)];
        let disasm = TestDisassembler::new();
        let cfg = ControlFlowGraph::new(&insts, &disasm);
        assert!(cfg.entry_block.is_some());
        assert_eq!(cfg.graph.node_count(), 1);

        let inbound = cfg.graph.externals(EdgeDirection::Incoming);
        assert_eq!(inbound.count(), 1);

        let outbound = cfg.graph.externals(EdgeDirection::Outgoing);
        assert_eq!(outbound.count(), 1);
    }
}
<|endoftext|>


<commit_before>use std::io::{File, Open, Read};
use opcode::{Opcode, to_opcode};
use std::io::Timer;
use std::time::Duration;

pub fn join_bytes(hh: i8, ll: i8) -> i16 {
	((((hh as u8) as u16) << 8) + (ll as u8) as u16) as i16
}

pub fn separate_word(word: i16) -> (i8, i8) {
	let word = word as u16;
	let hh = (word >> 8) as u8;
	let ll = (word & 0xff) as u8;
	(hh as i8, ll as i8)
}

pub fn separate_byte(byte: i8) -> (i8, i8) {
	let byte = byte as u8;
	let hh = (byte >> 4) as u8;
	let ll = byte & 0xf;
	(hh as i8, ll as i8)
}

enum Flags {
    Carry = 1 << 1,
   	Zero = 1 << 2,
   	Overflow = 1 << 6,
	Negative = 1 << 7,
}

struct Graphics {
    state: StateRegister,
	palette: [u32, ..16],
	screen: [[u8, ..320], ..240],
}

struct StateRegister {
    bg: u8,
	fg: u8,
	spritew: u8,
	spriteh: u8,
	hflip: bool,
	vflip: bool,
}

struct Memory {
    memory: [i8, ..65536],
}

pub struct Cpu {
    pub pc: i16,
	pub sp: i16,
	rx: [i16, ..16],
	flags: i8,
	pub vblank: bool,
	graphics: Graphics,
	pub memory: Memory,
}

impl Memory {
    pub fn new() -> Memory {
	    Memory { memory: [0, ..65536] }
	}

	pub fn read_byte(self, dir: uint) -> i8 {
		self.memory[dir]
	}

	pub fn write_byte(&mut self, dir: uint, value: i8) -> () {
		self.memory[dir] = value;
	}

	pub fn read_word(self, dir: uint) -> i16 {
		let ll = self.memory[dir];
		let hh = self.memory[dir + 1];
		join_bytes(hh, ll)
	}

	pub fn write_word(&mut self, dir: uint, value: i16) -> () {
		let (hh, ll) = separate_word(value);
		self.memory[dir] = ll;
		self.memory[dir + 1] = hh;
	}
}

impl StateRegister {
    pub fn new() -> StateRegister{
	    StateRegister { bg: 0, fg: 0, spritew: 0, spriteh: 0, hflip: false, vflip: false,}
	}

	fn clear(self: &mut StateRegister) {
		self.fg = 0;
		self.bg = 0;
	}
}

impl Graphics {
    pub fn new() -> Graphics {
	    Graphics {
		    state: StateRegister::new(),
		    palette: [0x000000, 0x000000, 0x888888, 0xBF3932, 0xDE7AAE, 0x4C3D21, 0x905F25, 0xE49452,
		        0xEAD979, 0x537A3B, 0xABD54A, 0x252E38, 0x00467F, 0x68ABCC, 0xBCDEE4, 0xFFFFFF],
		    screen: [[0, ..320], ..240],
		}
	}

	fn clear(self: &mut Graphics) {
	    self.state.clear();
	}

	pub fn set_bg(&mut self, byte: u8) -> () {
		self.state.bg = byte;
	}
}

impl Cpu {
    pub fn new(file_path: Path) -> Cpu {
    	let file = match File::open_mode(&file_path, Open, Read) {
		    Ok(file) => file,
   		    Err(e) => fail!("{} {}", e.desc, file_path.display()),
	    };
        let mut cpu = Cpu {pc: 0, sp: 0, rx: [0, ..16], flags: 0,
	    	vblank: false, graphics: Graphics::new(), memory: Memory::new(),};
		cpu.load_program(file);
	    cpu
    }

	fn load_program(&mut self, mut file: File) -> () {
		//TODO: add loading of .c16 files
		let mut i: uint = 0;
		for byte in file.bytes() {
			let byte = match byte {
				Ok(number) => number as i8,
				Err(e) => fail!("{}", e.desc),
			};
			self.memory.write_byte(i, byte);
			i += 1;
		}
	}

	pub fn load_pal(&mut self, dir: i16) -> () {
		for i in range(0, 15) {
			let dir = dir as uint;
			let high: u32 = (self.memory.read_byte(dir + (i * 3)) as i32 as u32) << 16;
			let middle: u32 = (self.memory.read_byte(dir + (i * 3) + 1) as i32 as u32) << 8;
			let low: u32 = self.memory.read_byte(dir + (i * 3) + 2) as i32 as u32;
			self.graphics.palette[i] = high + middle + low;
		}
	}

	pub fn clear_fg_bg(&mut self) {
		self.graphics.clear()
	}

	pub fn set_bg(&mut self, byte: u8) -> () {
		self.graphics.set_bg(byte);
	}

	pub fn set_spr_wh(&mut self, ll: u8, hh: u8) -> () {
		self.graphics.state.spritew = ll;
		self.graphics.state.spriteh = hh;
	}

	pub fn get_rx(&mut self, rx: i8) -> i16 {
		self.rx[rx as uint]
	}

	pub fn set_rx(&mut self, rx: i8, value: i16) -> () {
		self.rx[rx as uint] = value;
	}

	pub fn pop_stack(&mut self) -> i16 {
		self.sp = self.sp - 2;
		let word = self.memory.read_word(self.sp as uint);
		word
	}

	pub fn push_stack(&mut self, word: i16) -> () {
		self.memory.write_word(self.sp as uint, word);
		self.sp = self.sp + 2;
	}

	pub fn pushall(&mut self) -> () {
		let vec = self.rx;
		for rx in vec.iter() {
			self.push_stack(*rx);
		}
	}

	pub fn popall(&mut self) -> () {
		for i in range(15i8, 1i8) {
			let val = self.pop_stack();
			self.set_rx(i, val);
		}
	}

	pub fn pushf(&mut self) -> () {
		let value = ((self.flags as u8) as u16) as i16;
		self.push_stack(value);
	}

	pub fn popf(&mut self) -> () {
		let value = self.pop_stack();
		self.flags = ((value as u16) as u8) as i8;
	}

	pub fn flip(&mut self, hor: bool, ver: bool) -> () {
		self.graphics.state.hflip = hor;
		self.graphics.state.vflip = ver;
	}

	pub fn has_carry(&self) -> bool {
		(Carry as i8 & self.flags) != 0
	}

	pub fn has_zero(&self) -> bool {
		(Zero as i8 & self.flags) != 0
	}

	pub fn has_overflow(&self) -> bool {
		(Overflow as i8 & self.flags) != 0
	}

	pub fn has_negative(&self) -> bool {
		(Negative as i8 & self.flags) != 0
	}

	pub fn put_carry(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Carry as i8 | self.flags
		} else {
			self.flags = Carry as i8 ^ self.flags
		}
	}

	pub fn put_zero(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Zero as i8 | self.flags
		} else {
			self.flags = Zero as i8 ^ self.flags
		}
	}

	pub fn put_overflow(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Overflow as i8 | self.flags
		} else {
			self.flags = Overflow as i8 ^ self.flags
		}
	}

	pub fn put_negative(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Negative as i8 | self.flags
		} else {
			self.flags = Negative as i8 ^ self.flags
		}
	}

	pub fn check_flags(&self, index: i8) -> bool {
		match index {
			0 => self.has_zero(),
			1 => !self.has_zero(),
			2 => self.has_negative(),
			3 => !self.has_negative(),
			4 => !self.has_negative() && !self.has_zero(),
			5 => self.has_overflow(),
			6 => !self.has_overflow(),
			7 => !self.has_carry() && !self.has_zero(),
			8 => !self.has_carry(),
			9 => self.has_carry(),
			0xA => self.has_carry() || self.has_zero(),
			0xB => (self.has_overflow() == self.has_negative()) && !self.has_zero(),
			0xC => (self.has_overflow() == self.has_negative()),
			0xD => (self.has_overflow() != self.has_negative()),
			0xE => (self.has_overflow() != self.has_negative()) || !self.has_zero(),
			_ => fail!(),
		}
	}

	pub fn step(&mut self) -> () {
		let opcode: Opcode = to_opcode(self.memory.read_byte(self.pc as uint));
		let byte1 = self.memory.read_byte((self.pc + 1) as uint);
		let byte2 = self.memory.read_byte((self.pc + 2) as uint);
		let byte3 = self.memory.read_byte((self.pc + 3) as uint);
		self.pc = self.pc + 4;
		opcode.execute(self, byte1, byte2, byte3);
	}

	pub fn start_program(&mut self) -> () {
	    let mut timer = Timer::new().unwrap();
		let timer = timer.periodic(Duration::microseconds(1));
		loop {
			timer.recv();
			self.step();
			//TODO: missing vblank event
		}
	}
}<commit_msg>Implemented vblank event<commit_after>use std::io::{File, Open, Read};
use opcode::{Opcode, to_opcode};
use std::io::Timer;
use std::time::Duration;
use std::iter::Iterator;

pub fn join_bytes(hh: i8, ll: i8) -> i16 {
	((((hh as u8) as u16) << 8) + (ll as u8) as u16) as i16
}

pub fn separate_word(word: i16) -> (i8, i8) {
	let word = word as u16;
	let hh = (word >> 8) as u8;
	let ll = (word & 0xff) as u8;
	(hh as i8, ll as i8)
}

pub fn separate_byte(byte: i8) -> (i8, i8) {
	let byte = byte as u8;
	let hh = (byte >> 4) as u8;
	let ll = byte & 0xf;
	(hh as i8, ll as i8)
}

struct VblankEventIter {
	counter: u32,
	max: u32,
}

impl VblankEventIter {
	fn new(max: u32) -> VblankEventIter {
		VblankEventIter { counter: 0, max: max}
	}
}

impl Iterator<bool> for VblankEventIter {
	fn next(&mut self) -> Option<bool> {
		let count = self.counter;
		let next = (count+1) % self.max;
		self.counter += 1;
		Some(next == 0)
	}
}

enum Flags {
    Carry = 1 << 1,
   	Zero = 1 << 2,
   	Overflow = 1 << 6,
	Negative = 1 << 7,
}

struct Graphics {
    state: StateRegister,
	palette: [u32, ..16],
	screen: [[u8, ..320], ..240],
}

struct StateRegister {
    bg: u8,
	fg: u8,
	spritew: u8,
	spriteh: u8,
	hflip: bool,
	vflip: bool,
}

struct Memory {
    memory: [i8, ..65536],
}

pub struct Cpu {
    pub pc: i16,
	pub sp: i16,
	rx: [i16, ..16],
	flags: i8,
	pub vblank: bool,
	graphics: Graphics,
	pub memory: Memory,
}

impl Memory {
    pub fn new() -> Memory {
	    Memory { memory: [0, ..65536] }
	}

	pub fn read_byte(self, dir: uint) -> i8 {
		self.memory[dir]
	}

	pub fn write_byte(&mut self, dir: uint, value: i8) -> () {
		self.memory[dir] = value;
	}

	pub fn read_word(self, dir: uint) -> i16 {
		let ll = self.memory[dir];
		let hh = self.memory[dir + 1];
		join_bytes(hh, ll)
	}

	pub fn write_word(&mut self, dir: uint, value: i16) -> () {
		let (hh, ll) = separate_word(value);
		self.memory[dir] = ll;
		self.memory[dir + 1] = hh;
	}
}

impl StateRegister {
    pub fn new() -> StateRegister{
	    StateRegister { bg: 0, fg: 0, spritew: 0, spriteh: 0, hflip: false, vflip: false,}
	}

	fn clear(self: &mut StateRegister) {
		self.fg = 0;
		self.bg = 0;
	}
}

impl Graphics {
    pub fn new() -> Graphics {
	    Graphics {
		    state: StateRegister::new(),
		    palette: [0x000000, 0x000000, 0x888888, 0xBF3932, 0xDE7AAE, 0x4C3D21, 0x905F25, 0xE49452,
		        0xEAD979, 0x537A3B, 0xABD54A, 0x252E38, 0x00467F, 0x68ABCC, 0xBCDEE4, 0xFFFFFF],
		    screen: [[0, ..320], ..240],
		}
	}

	fn clear(self: &mut Graphics) {
	    self.state.clear();
	}

	pub fn set_bg(&mut self, byte: u8) -> () {
		self.state.bg = byte;
	}
}

impl Cpu {
    pub fn new(file_path: Path) -> Cpu {
    	let file = match File::open_mode(&file_path, Open, Read) {
		    Ok(file) => file,
   		    Err(e) => fail!("{} {}", e.desc, file_path.display()),
	    };
        let mut cpu = Cpu {pc: 0, sp: 0, rx: [0, ..16], flags: 0,
	    	vblank: false, graphics: Graphics::new(), memory: Memory::new(),};
		cpu.load_program(file);
	    cpu
    }

	fn load_program(&mut self, mut file: File) -> () {
		//TODO: add loading of .c16 files
		let mut i: uint = 0;
		for byte in file.bytes() {
			let byte = match byte {
				Ok(number) => number as i8,
				Err(e) => fail!("{}", e.desc),
			};
			self.memory.write_byte(i, byte);
			i += 1;
		}
	}

	pub fn load_pal(&mut self, dir: i16) -> () {
		for i in range(0, 15) {
			let dir = dir as uint;
			let high: u32 = (self.memory.read_byte(dir + (i * 3)) as i32 as u32) << 16;
			let middle: u32 = (self.memory.read_byte(dir + (i * 3) + 1) as i32 as u32) << 8;
			let low: u32 = self.memory.read_byte(dir + (i * 3) + 2) as i32 as u32;
			self.graphics.palette[i] = high + middle + low;
		}
	}

	pub fn clear_fg_bg(&mut self) {
		self.graphics.clear()
	}

	pub fn set_bg(&mut self, byte: u8) -> () {
		self.graphics.set_bg(byte);
	}

	pub fn set_spr_wh(&mut self, ll: u8, hh: u8) -> () {
		self.graphics.state.spritew = ll;
		self.graphics.state.spriteh = hh;
	}

	pub fn get_rx(&mut self, rx: i8) -> i16 {
		self.rx[rx as uint]
	}

	pub fn set_rx(&mut self, rx: i8, value: i16) -> () {
		self.rx[rx as uint] = value;
	}

	pub fn pop_stack(&mut self) -> i16 {
		self.sp = self.sp - 2;
		let word = self.memory.read_word(self.sp as uint);
		word
	}

	pub fn push_stack(&mut self, word: i16) -> () {
		self.memory.write_word(self.sp as uint, word);
		self.sp = self.sp + 2;
	}

	pub fn pushall(&mut self) -> () {
		let vec = self.rx;
		for rx in vec.iter() {
			self.push_stack(*rx);
		}
	}

	pub fn popall(&mut self) -> () {
		for i in range(15i8, 1i8) {
			let val = self.pop_stack();
			self.set_rx(i, val);
		}
	}

	pub fn pushf(&mut self) -> () {
		let value = ((self.flags as u8) as u16) as i16;
		self.push_stack(value);
	}

	pub fn popf(&mut self) -> () {
		let value = self.pop_stack();
		self.flags = ((value as u16) as u8) as i8;
	}

	pub fn flip(&mut self, hor: bool, ver: bool) -> () {
		self.graphics.state.hflip = hor;
		self.graphics.state.vflip = ver;
	}

	pub fn has_carry(&self) -> bool {
		(Carry as i8 & self.flags) != 0
	}

	pub fn has_zero(&self) -> bool {
		(Zero as i8 & self.flags) != 0
	}

	pub fn has_overflow(&self) -> bool {
		(Overflow as i8 & self.flags) != 0
	}

	pub fn has_negative(&self) -> bool {
		(Negative as i8 & self.flags) != 0
	}

	pub fn put_carry(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Carry as i8 | self.flags
		} else {
			self.flags = Carry as i8 ^ self.flags
		}
	}

	pub fn put_zero(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Zero as i8 | self.flags
		} else {
			self.flags = Zero as i8 ^ self.flags
		}
	}

	pub fn put_overflow(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Overflow as i8 | self.flags
		} else {
			self.flags = Overflow as i8 ^ self.flags
		}
	}

	pub fn put_negative(&mut self, new_state: bool) -> () {
		if new_state {
			self.flags = Negative as i8 | self.flags
		} else {
			self.flags = Negative as i8 ^ self.flags
		}
	}

	pub fn check_flags(&self, index: i8) -> bool {
		match index {
			0 => self.has_zero(),
			1 => !self.has_zero(),
			2 => self.has_negative(),
			3 => !self.has_negative(),
			4 => !self.has_negative() && !self.has_zero(),
			5 => self.has_overflow(),
			6 => !self.has_overflow(),
			7 => !self.has_carry() && !self.has_zero(),
			8 => !self.has_carry(),
			9 => self.has_carry(),
			0xA => self.has_carry() || self.has_zero(),
			0xB => (self.has_overflow() == self.has_negative()) && !self.has_zero(),
			0xC => (self.has_overflow() == self.has_negative()),
			0xD => (self.has_overflow() != self.has_negative()),
			0xE => (self.has_overflow() != self.has_negative()) || !self.has_zero(),
			_ => fail!(),
		}
	}

	pub fn step(&mut self) -> () {
		let opcode: Opcode = to_opcode(self.memory.read_byte(self.pc as uint));
		let byte1 = self.memory.read_byte((self.pc + 1) as uint);
		let byte2 = self.memory.read_byte((self.pc + 2) as uint);
		let byte3 = self.memory.read_byte((self.pc + 3) as uint);
		self.pc = self.pc + 4;
		opcode.execute(self, byte1, byte2, byte3);
	}

	pub fn start_program(&mut self) -> () {
	    let mut timer = Timer::new().unwrap();
		let timer = timer.periodic(Duration::microseconds(1));
		let mut vblank_event = VblankEventIter::new(16000);
		for event in vblank_event {
			self.vblank = event;
			timer.recv();
			self.step();
		}
	}
}<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Updated as per tutorial<commit_after>use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}<|endoftext|>


<commit_before>use scaly::memory::bucket::BUCKET_PAGES;
use scaly::memory::pool::Pool;

pub struct Heap {
    map: usize,
    pools: [*mut Pool; BUCKET_PAGES],
}

impl Heap {}
<commit_msg>Heap creates itself and allocates a page.<commit_after>use scaly::memory::bucket::Bucket;
use scaly::memory::bucket::BUCKET_PAGES;
use scaly::memory::page::Page;
use scaly::memory::pool::Pool;
use std::ptr::null_mut;
use std::usize::MAX;

pub struct Heap {
    map: usize,
    pools: [*mut Pool; BUCKET_PAGES],
}

impl Heap {
    pub fn create() -> Heap {
        Heap {
            map: MAX,
            pools: [null_mut(); BUCKET_PAGES],
        }
    }

    pub fn allocate_page(&mut self) -> *mut Page {
        // println!("Heap map before allocation: {:X}.", self.map);
        if self.map == 0 {
            panic!("Not more than one heap supported currently.");
        }

        let position = Bucket::find_least_position(self.map);
        if self.pools[position] == null_mut() {
            self.pools[position] = Pool::create();
            println!(
                "Heap allocated pool at: {:X}.",
                self.pools[position] as usize
            );
        }
        unsafe { (*self.pools[position]).allocate_page() }
    }
}

#[test]
fn test_heap() {
    let mut heap = Heap::create();
    let page = heap.allocate_page();
    for i in 0..1000 {
        unsafe {
            (*page).allocate(i);
        }
    }
}
<|endoftext|>


<commit_before>//! Extension traits to provide parsing methods on foreign types.
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

use proc_macro2::Ident;

use parse::{ParseStream, Result};

/// Additional parsing methods for `Ident`.
///
/// This trait is sealed and cannot be implemented for types outside of Syn.
///
/// *This trait is available if Syn is built with the `"parsing"` feature.*
pub trait IdentExt: Sized + private::Sealed {
    /// Parses any identifier including keywords.
    ///
    /// This is useful when parsing a DSL which allows Rust keywords as
    /// identifiers.
    ///
    /// ```edition2018
    /// use syn::{Error, Ident, Result, Token};
    /// use syn::ext::IdentExt;
    /// use syn::parse::ParseStream;
    ///
    /// // Parses input that looks like `name = NAME` where `NAME` can be
    /// // any identifier.
    /// //
    /// // Examples:
    /// //
    /// //     name = anything
    /// //     name = impl
    /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let name = input.call(Ident::parse_any)?;
    ///     Ok(name)
    /// }
    /// ```
    fn parse_any(input: ParseStream) -> Result<Self>;
}

impl IdentExt for Ident {
    fn parse_any(input: ParseStream) -> Result<Self> {
        input.step(|cursor| match cursor.ident() {
            Some((ident, rest)) => Ok((ident, rest)),
            None => Err(cursor.error("expected ident")),
        })
    }
}

mod private {
    use proc_macro2::Ident;

    pub trait Sealed {}

    impl Sealed for Ident {}
}
<commit_msg>Extension method to unraw an ident<commit_after>//! Extension traits to provide parsing methods on foreign types.
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

use proc_macro2::Ident;

use parse::{ParseStream, Result};

/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
///
/// This trait is sealed and cannot be implemented for types outside of Syn. It
/// is implemented only for `proc_macro2::Ident`.
///
/// *This trait is available if Syn is built with the `"parsing"` feature.*
pub trait IdentExt: Sized + private::Sealed {
    /// Parses any identifier including keywords.
    ///
    /// This is useful when parsing a DSL which allows Rust keywords as
    /// identifiers.
    ///
    /// # Example
    ///
    /// ```edition2018
    /// use syn::{Error, Ident, Result, Token};
    /// use syn::ext::IdentExt;
    /// use syn::parse::ParseStream;
    ///
    /// // Parses input that looks like `name = NAME` where `NAME` can be
    /// // any identifier.
    /// //
    /// // Examples:
    /// //
    /// //     name = anything
    /// //     name = impl
    /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let name = input.call(Ident::parse_any)?;
    ///     Ok(name)
    /// }
    /// ```
    fn parse_any(input: ParseStream) -> Result<Self>;

    /// Strips the raw marker `r#`, if any, from the beginning of an ident.
    ///
    ///   - unraw(`x`) = `x`
    ///   - unraw(`move`) = `move`
    ///   - unraw(`r#move`) = `move`
    ///
    /// # Example
    ///
    /// In the case of interop with other languages like Python that have a
    /// different set of keywords than Rust, we might come across macro input
    /// that involves raw identifiers to refer to ordinary variables in the
    /// other language with a name that happens to be a Rust keyword.
    ///
    /// The function below appends an identifier from the caller's input onto a
    /// fixed prefix. Without using `unraw()`, this would tend to produce
    /// invalid identifiers like `__pyo3_get_r#move`.
    ///
    /// ```edition2018
    /// use proc_macro2::Span;
    /// use syn::Ident;
    /// use syn::ext::IdentExt;
    ///
    /// fn ident_for_getter(variable: &Ident) -> Ident {
    ///     let getter = format!("__pyo3_get_{}", variable.unraw());
    ///     Ident::new(&getter, Span::call_site())
    /// }
    /// ```
    fn unraw(&self) -> Ident;
}

impl IdentExt for Ident {
    fn parse_any(input: ParseStream) -> Result<Self> {
        input.step(|cursor| match cursor.ident() {
            Some((ident, rest)) => Ok((ident, rest)),
            None => Err(cursor.error("expected ident")),
        })
    }

    fn unraw(&self) -> Ident {
        let string = self.to_string();
        if string.starts_with("r#") {
            Ident::new(&string[2..], self.span())
        } else {
            self.clone()
        }
    }
}

mod private {
    use proc_macro2::Ident;

    pub trait Sealed {}

    impl Sealed for Ident {}
}
<|endoftext|>


<commit_before>use std::mem;
use libc;

use {Nl,NlSerState,NlDeState};
use err::{SerError,DeError};

macro_rules! eval_safety {
    (unsafe $expr:expr) => { unsafe { $expr } };
    (safe $expr:expr) => { $expr };
}

macro_rules! impl_var {
    ( $name:ident, $ty:ty, $var_def:ident => $val_def:expr,
      $( $var:ident => $val:expr ),* ) => (
          impl_var!($name, $ty, safe, $var_def => $val_def,
            $( $var => $val ),* );
      );

    ( $name:ident, $ty:ty, $safety:ident, $var_def:ident => $val_def:expr,
      $( $var:ident => $val:expr ),* ) => (
        /// Enum representing C constants for netlink packets
        #[derive(Clone,Debug,Eq,PartialEq)]
        pub enum $name {
            #[allow(missing_docs)]
            $var_def,
            $(
                #[allow(missing_docs)]
                $var,
            )*
            /// Variant that signifies an invalid value while deserializing
            UnrecognizedVariant($ty),
        }

        impl From<$ty> for $name {
            fn from(v: $ty) -> Self {
                match v {
                    i if i == eval_safety!{ $safety $val_def } => $name::$var_def,
                    $( i if i == eval_safety!{ $safety $val } => $name::$var,)*
                    i => $name::UnrecognizedVariant(i)
                }
            }
        }

        impl From<$name> for $ty {
            fn from(v: $name) -> Self {
                match v {
                    $name::$var_def => eval_safety!{ $safety $val_def },
                    $( $name::$var => eval_safety!{ $safety $val }, )*
                    $name::UnrecognizedVariant(i) => i,
                }
            }
        }

        impl Nl for $name {
            fn serialize(&self, state: &mut NlSerState) -> Result<(), SerError> {
                let mut v: $ty = self.clone().into();
                try!(Nl::serialize(&mut v, state));
                Ok(())
            }

            fn deserialize(state: &mut NlDeState) -> Result<Self, DeError> {
                let v: $ty = try!(<$ty as Nl>::deserialize(state));
                Ok(v.into())
            }

            fn size(&self) -> usize {
                mem::size_of::<$ty>()
            }
        }
    );
}

#[link(name = "netlink")]
extern {
    pub static nla_alignto: usize;

    pub static ctrl_cmd_unspec: u8;
    pub static ctrl_cmd_newfamily: u8;
    pub static ctrl_cmd_delfamily: u8;
    pub static ctrl_cmd_getfamily: u8;
    pub static ctrl_cmd_newops: u8;
    pub static ctrl_cmd_delops: u8;
    pub static ctrl_cmd_getops: u8;
    pub static ctrl_cmd_newmcast_grp: u8;
    pub static ctrl_cmd_delmcast_grp: u8;
    pub static ctrl_cmd_getmcast_grp: u8;

    pub static ctrl_attr_unspec: u16;
    pub static ctrl_attr_family_id: u16;
    pub static ctrl_attr_family_name: u16;
    pub static ctrl_attr_version: u16;
    pub static ctrl_attr_hdrsize: u16;
    pub static ctrl_attr_maxattr: u16;
    pub static ctrl_attr_ops: u16;
    pub static ctrl_attr_mcast_groups: u16;

    pub static genl_id_generate: u16;
    pub static genl_id_ctrl: u16;
    pub static genl_id_vfs_dquot: u16;
    pub static genl_id_pmcraid: u16;

    pub static ctrl_attr_mcast_grp_unspec: u16;
    pub static ctrl_attr_mcast_grp_name: u16;
    pub static ctrl_attr_mcast_grp_id: u16;
}

/// Reimplementation of alignto macro in C
pub fn alignto(len: usize) -> usize {
    (len + unsafe { nla_alignto } - 1) & !(unsafe { nla_alignto } - 1)
}

/// Values for `nl_family` in `NlSocket`
impl_var!(NlFamily, libc::c_int,
    Route => libc::NETLINK_ROUTE,
    Unused => libc::NETLINK_UNUSED,
    Usersock => libc::NETLINK_USERSOCK,
    Firewall => libc::NETLINK_FIREWALL,
    SockDiag => libc::NETLINK_SOCK_DIAG,
    Nflog => libc::NETLINK_NFLOG,
    Xfrm => libc::NETLINK_XFRM,
    Selinux => libc::NETLINK_SELINUX,
    Iscsi => libc::NETLINK_ISCSI,
    Audit => libc::NETLINK_AUDIT,
    FibLookup => libc::NETLINK_FIB_LOOKUP,
    Connector => libc::NETLINK_CONNECTOR,
    Netfilter => libc::NETLINK_NETFILTER,
    Ip6Fw => libc::NETLINK_IP6_FW,
    Dnrtmsg => libc::NETLINK_DNRTMSG,
    KobjectUevent => libc::NETLINK_KOBJECT_UEVENT,
    Generic => libc::NETLINK_GENERIC,
    Scsitransport => libc::NETLINK_SCSITRANSPORT,
    Ecryptfs => libc::NETLINK_ECRYPTFS,
    Rdma => libc::NETLINK_RDMA,
    Crypto => libc::NETLINK_CRYPTO,
    InetDiag => libc::NETLINK_SOCK_DIAG
);

/// Values for `nl_type` in `NlHdr`
impl_var!(Nlmsg, u16,
    Noop => libc::NLMSG_NOOP as u16,
    Error => libc::NLMSG_ERROR as u16,
    Done => libc::NLMSG_DONE as u16,
    Overrun => libc::NLMSG_OVERRUN as u16
);

/// Values for `nl_flags` in `NlHdr`
impl_var!(NlFlags, u16,
    Request => libc::NLM_F_REQUEST as u16,
    Multi => libc::NLM_F_MULTI as u16,
    Ack => libc::NLM_F_ACK as u16,
    Echo => libc::NLM_F_ECHO as u16,
    DumpIntr => libc::NLM_F_DUMP_INTR as u16,
    DumpFiltered => libc::NLM_F_DUMP_FILTERED as u16,
    Root => libc::NLM_F_ROOT as u16,
    Match => libc::NLM_F_MATCH as u16,
    Atomic => libc::NLM_F_ATOMIC as u16,
    Dump => libc::NLM_F_DUMP as u16,
    Replace => libc::NLM_F_REPLACE as u16,
    Excl => libc::NLM_F_EXCL as u16,
    Create => libc::NLM_F_CREATE as u16,
    Append => libc::NLM_F_APPEND as u16
);

impl_var!(GenlId, u16, unsafe,
    Generate => genl_id_generate,
    Ctrl => genl_id_ctrl,
    VfsDquot => genl_id_vfs_dquot,
    Pmcraid => genl_id_pmcraid
);

/// Values for `cmd` in `GenlHdr`
impl_var!(CtrlCmd, u8, unsafe,
    Unspec => ctrl_cmd_unspec,
    Newfamily => ctrl_cmd_newfamily,
    Delfamily => ctrl_cmd_delfamily,
    Getfamily => ctrl_cmd_getfamily,
    Newops => ctrl_cmd_newops,
    Delops => ctrl_cmd_delops,
    Getops => ctrl_cmd_getops,
    NewmcastGrp => ctrl_cmd_newmcast_grp,
    DelmcastGrp => ctrl_cmd_delmcast_grp,
    GetmcastGrp => ctrl_cmd_getmcast_grp
);

/// Values for `nla_type` in `NlaAttrHdr`
impl_var!(CtrlAttr, u16, unsafe,
    Unspec => ctrl_attr_unspec,
    FamilyId => ctrl_attr_family_id,
    FamilyName => ctrl_attr_family_name,
    Version => ctrl_attr_version,
    Hdrsize => ctrl_attr_hdrsize,
    Maxattr => ctrl_attr_maxattr,
    Ops => ctrl_attr_ops,
    McastGroups => ctrl_attr_mcast_groups
);

/// Values for `nla_type` in `NlaAttrHdr`
impl_var!(CtrlAttrMcastGrp, u16, unsafe,
    Unspec => ctrl_attr_mcast_grp_unspec,
    Name => ctrl_attr_mcast_grp_name,
    Id => ctrl_attr_mcast_grp_id
);
<commit_msg>Make SOCK_DIAG and INET_DIAG one variant as INET_DIAG is a #define of SOCK_DIAG<commit_after>use std::mem;
use libc;

use {Nl,NlSerState,NlDeState};
use err::{SerError,DeError};

macro_rules! eval_safety {
    (unsafe $expr:expr) => { unsafe { $expr } };
    (safe $expr:expr) => { $expr };
}

macro_rules! impl_var {
    ( $name:ident, $ty:ty, $var_def:ident => $val_def:expr,
      $( $var:ident => $val:expr ),* ) => (
          impl_var!($name, $ty, safe, $var_def => $val_def,
            $( $var => $val ),* );
      );

    ( $name:ident, $ty:ty, $safety:ident, $var_def:ident => $val_def:expr,
      $( $var:ident => $val:expr ),* ) => (
        /// Enum representing C constants for netlink packets
        #[derive(Clone,Debug,Eq,PartialEq)]
        pub enum $name {
            #[allow(missing_docs)]
            $var_def,
            $(
                #[allow(missing_docs)]
                $var,
            )*
            /// Variant that signifies an invalid value while deserializing
            UnrecognizedVariant($ty),
        }

        impl From<$ty> for $name {
            fn from(v: $ty) -> Self {
                match v {
                    i if i == eval_safety!{ $safety $val_def } => $name::$var_def,
                    $( i if i == eval_safety!{ $safety $val } => $name::$var,)*
                    i => $name::UnrecognizedVariant(i)
                }
            }
        }

        impl From<$name> for $ty {
            fn from(v: $name) -> Self {
                match v {
                    $name::$var_def => eval_safety!{ $safety $val_def },
                    $( $name::$var => eval_safety!{ $safety $val }, )*
                    $name::UnrecognizedVariant(i) => i,
                }
            }
        }

        impl Nl for $name {
            fn serialize(&self, state: &mut NlSerState) -> Result<(), SerError> {
                let mut v: $ty = self.clone().into();
                try!(Nl::serialize(&mut v, state));
                Ok(())
            }

            fn deserialize(state: &mut NlDeState) -> Result<Self, DeError> {
                let v: $ty = try!(<$ty as Nl>::deserialize(state));
                Ok(v.into())
            }

            fn size(&self) -> usize {
                mem::size_of::<$ty>()
            }
        }
    );
}

#[link(name = "netlink")]
extern {
    pub static nla_alignto: usize;

    pub static ctrl_cmd_unspec: u8;
    pub static ctrl_cmd_newfamily: u8;
    pub static ctrl_cmd_delfamily: u8;
    pub static ctrl_cmd_getfamily: u8;
    pub static ctrl_cmd_newops: u8;
    pub static ctrl_cmd_delops: u8;
    pub static ctrl_cmd_getops: u8;
    pub static ctrl_cmd_newmcast_grp: u8;
    pub static ctrl_cmd_delmcast_grp: u8;
    pub static ctrl_cmd_getmcast_grp: u8;

    pub static ctrl_attr_unspec: u16;
    pub static ctrl_attr_family_id: u16;
    pub static ctrl_attr_family_name: u16;
    pub static ctrl_attr_version: u16;
    pub static ctrl_attr_hdrsize: u16;
    pub static ctrl_attr_maxattr: u16;
    pub static ctrl_attr_ops: u16;
    pub static ctrl_attr_mcast_groups: u16;

    pub static genl_id_generate: u16;
    pub static genl_id_ctrl: u16;
    pub static genl_id_vfs_dquot: u16;
    pub static genl_id_pmcraid: u16;

    pub static ctrl_attr_mcast_grp_unspec: u16;
    pub static ctrl_attr_mcast_grp_name: u16;
    pub static ctrl_attr_mcast_grp_id: u16;
}

/// Reimplementation of alignto macro in C
pub fn alignto(len: usize) -> usize {
    (len + unsafe { nla_alignto } - 1) & !(unsafe { nla_alignto } - 1)
}

/// Values for `nl_family` in `NlSocket`
impl_var!(NlFamily, libc::c_int,
    Route => libc::NETLINK_ROUTE,
    Unused => libc::NETLINK_UNUSED,
    Usersock => libc::NETLINK_USERSOCK,
    Firewall => libc::NETLINK_FIREWALL,
    SockOrInetDiag => libc::NETLINK_SOCK_DIAG,
    Nflog => libc::NETLINK_NFLOG,
    Xfrm => libc::NETLINK_XFRM,
    Selinux => libc::NETLINK_SELINUX,
    Iscsi => libc::NETLINK_ISCSI,
    Audit => libc::NETLINK_AUDIT,
    FibLookup => libc::NETLINK_FIB_LOOKUP,
    Connector => libc::NETLINK_CONNECTOR,
    Netfilter => libc::NETLINK_NETFILTER,
    Ip6Fw => libc::NETLINK_IP6_FW,
    Dnrtmsg => libc::NETLINK_DNRTMSG,
    KobjectUevent => libc::NETLINK_KOBJECT_UEVENT,
    Generic => libc::NETLINK_GENERIC,
    Scsitransport => libc::NETLINK_SCSITRANSPORT,
    Ecryptfs => libc::NETLINK_ECRYPTFS,
    Rdma => libc::NETLINK_RDMA,
    Crypto => libc::NETLINK_CRYPTO
);

/// Values for `nl_type` in `NlHdr`
impl_var!(Nlmsg, u16,
    Noop => libc::NLMSG_NOOP as u16,
    Error => libc::NLMSG_ERROR as u16,
    Done => libc::NLMSG_DONE as u16,
    Overrun => libc::NLMSG_OVERRUN as u16
);

/// Values for `nl_flags` in `NlHdr`
impl_var!(NlFlags, u16,
    Request => libc::NLM_F_REQUEST as u16,
    Multi => libc::NLM_F_MULTI as u16,
    Ack => libc::NLM_F_ACK as u16,
    Echo => libc::NLM_F_ECHO as u16,
    DumpIntr => libc::NLM_F_DUMP_INTR as u16,
    DumpFiltered => libc::NLM_F_DUMP_FILTERED as u16,
    Root => libc::NLM_F_ROOT as u16,
    Match => libc::NLM_F_MATCH as u16,
    Atomic => libc::NLM_F_ATOMIC as u16,
    Dump => libc::NLM_F_DUMP as u16,
    Replace => libc::NLM_F_REPLACE as u16,
    Excl => libc::NLM_F_EXCL as u16,
    Create => libc::NLM_F_CREATE as u16,
    Append => libc::NLM_F_APPEND as u16
);

impl_var!(GenlId, u16, unsafe,
    Generate => genl_id_generate,
    Ctrl => genl_id_ctrl,
    VfsDquot => genl_id_vfs_dquot,
    Pmcraid => genl_id_pmcraid
);

/// Values for `cmd` in `GenlHdr`
impl_var!(CtrlCmd, u8, unsafe,
    Unspec => ctrl_cmd_unspec,
    Newfamily => ctrl_cmd_newfamily,
    Delfamily => ctrl_cmd_delfamily,
    Getfamily => ctrl_cmd_getfamily,
    Newops => ctrl_cmd_newops,
    Delops => ctrl_cmd_delops,
    Getops => ctrl_cmd_getops,
    NewmcastGrp => ctrl_cmd_newmcast_grp,
    DelmcastGrp => ctrl_cmd_delmcast_grp,
    GetmcastGrp => ctrl_cmd_getmcast_grp
);

/// Values for `nla_type` in `NlaAttrHdr`
impl_var!(CtrlAttr, u16, unsafe,
    Unspec => ctrl_attr_unspec,
    FamilyId => ctrl_attr_family_id,
    FamilyName => ctrl_attr_family_name,
    Version => ctrl_attr_version,
    Hdrsize => ctrl_attr_hdrsize,
    Maxattr => ctrl_attr_maxattr,
    Ops => ctrl_attr_ops,
    McastGroups => ctrl_attr_mcast_groups
);

/// Values for `nla_type` in `NlaAttrHdr`
impl_var!(CtrlAttrMcastGrp, u16, unsafe,
    Unspec => ctrl_attr_mcast_grp_unspec,
    Name => ctrl_attr_mcast_grp_name,
    Id => ctrl_attr_mcast_grp_id
);
<|endoftext|>