<commit_before>pub mod grid;
pub mod engine;
pub mod repr;

mod examples;

pub mod traits {

    use std::collections::HashMap;

    use repr::GridRepr;

    pub trait Cell: Default + Clone {
        fn step<'a, I>(&'a self, neighbors: I) -> Self
            where I: Iterator<Item=Option<&'a Self>>;
        fn repr(&self, meta: &mut HashMap<&str, &str>);
        fn from_repr(&mut self, meta: &HashMap<&str, &str>);
    }

    pub trait Nhood {
        type Coord: Coord;

        fn neighbors(&self, coord: &Self::Coord) -> Vec<Self::Coord>;
        fn neighbors_count(&self) -> usize;
    }

    pub trait Coord {
        fn from_2d(x: i32, y: i32) -> Self;

        fn x(&self) -> i32;
        fn y(&self) -> i32;
        fn z(&self) -> i32 { 0 }
    }

    pub trait Grid {
        type Coord: Coord;

        fn step(&mut self);
        fn repr(&self) -> &GridRepr<Self::Coord>;
        fn from_repr<'a: 'b, 'b, C: Coord>(&'a mut self, &GridRepr<'b, C>);
    }

    pub trait ReprConsumer {
        fn consume<C: Coord>(&mut self, repr: &GridRepr<C>);
    }

    pub trait Engine {
        fn run_times(&mut self, times: i64);
    }
}

<commit_msg>Get rid of old repr system.<commit_after>pub mod grid;
pub mod engine;

mod examples;

pub mod traits {

    pub trait Cell: Default + Clone + Binary {

        fn step<'a, I>(&'a self, neighbors: I) -> Self
            where I: Iterator<Item=Option<&'a Self>>;
    }

    pub trait Nhood {
        type Coord: Coord;

        fn neighbors(&self, &Self::Coord) -> Vec<Self::Coord>;

        fn neighbors_count(&self) -> usize;
    }

    pub trait Coord: PartialEq + Clone {
        fn from_2d(x: i32, y: i32) -> Self;

        fn x(&self) -> i32;
        fn y(&self) -> i32;
        fn z(&self) -> i32 { 0 }
    }

    pub trait Grid {
        type Cell: Cell;
        type Coord: Coord;

        fn step(&mut self);

        fn cells(&self) -> &Vec<Self::Cell>;
        fn dimensions(&self) -> Self::Coord;

        fn restore<G: Grid>(&mut self, &G);
    }

    pub trait ReprConsumer {
        fn consume<G: Grid>(&mut self, repr: &G);
    }

    pub trait Engine {
        fn run_times(&mut self, times: i64);
    }

    pub trait Binary: From<Vec<u8>> {
        fn bytes(&self) -> &[u8];
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate maplit;
extern crate env_logger;
extern crate uuid;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate handlebars;
#[macro_use]
extern crate log;
#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use config::action::ActionType;
pub use dispatcher::Response;
pub use message::Message;

pub mod conditions;
pub mod config;
pub mod action;
pub mod condition;
mod context;
mod correlator;
pub mod dispatcher;
pub mod message;
pub mod reactor;
mod state;
pub mod test_utils;
mod timer;

pub type MiliSec = u32;
<commit_msg>lib: make correlation module public<commit_after>#[macro_use]
extern crate maplit;
extern crate env_logger;
extern crate uuid;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate handlebars;
#[macro_use]
extern crate log;
#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use config::action::ActionType;
pub use dispatcher::Response;
pub use message::Message;

pub mod conditions;
pub mod config;
pub mod action;
pub mod condition;
mod context;
pub mod correlator;
pub mod dispatcher;
pub mod message;
pub mod reactor;
mod state;
pub mod test_utils;
mod timer;

pub type MiliSec = u32;
<|endoftext|>


<commit_before>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//! Alternatively, specify the program to open something with. It should expect to receive the path or URL as first argument.
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```

use std::{ffi::OsStr, io, process::ExitStatus, thread};

#[cfg(target_os = "windows")]
pub use windows::{that, with};

#[cfg(target_os = "macos")]
pub use macos::{that, with};

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use unix::{that, with};

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::ffi::OsStr;
    use std::io;
    use std::os::windows::{ffi::OsStrExt, process::ExitStatusExt};
    use std::process::{Command, ExitStatus};
    use std::ptr;

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn with<T: AsRef<OsStr> + Sized>(
        path: T,
        app: impl Into<String>,
    ) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(target_os = "macos")]
mod macos {

    use std::{
        ffi::OsStr,
        io::Result,
        process::{Command, ExitStatus, Stdio},
    };

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        Command::new("open")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path.as_ref())
            .spawn()?
            .wait()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new("open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .spawn()?
            .wait()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod unix {

    use std::{
        ffi::OsStr,
        io::{Error, Result},
        process::{Command, ExitStatus, Stdio},
    };

    use which::which;

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        ["xdg-open", "gnome-open", "kde-open", "wslview"] // Open handlers
            .iter()
            .find(|it| which(it).is_ok()) // find the first handler that exists
            .ok_or(Error::from_raw_os_error(0)) // If not found, return err
            .and_then(|program| {
                // If found run the handler
                Command::new(program)
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .arg(path.as_ref())
                    .spawn()?
                    .wait()
            })
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
    }
}
<commit_msg>Revert "Add missing Command import"<commit_after>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//! Alternatively, specify the program to open something with. It should expect to receive the path or URL as first argument.
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```

use std::{ffi::OsStr, io, process::ExitStatus, thread};

#[cfg(target_os = "windows")]
pub use windows::{that, with};

#[cfg(target_os = "macos")]
pub use macos::{that, with};

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use unix::{that, with};

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::ffi::OsStr;
    use std::io;
    use std::os::windows::{ffi::OsStrExt, process::ExitStatusExt};
    use std::process::ExitStatus;
    use std::ptr;

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn with<T: AsRef<OsStr> + Sized>(
        path: T,
        app: impl Into<String>,
    ) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(target_os = "macos")]
mod macos {

    use std::{
        ffi::OsStr,
        io::Result,
        process::{Command, ExitStatus, Stdio},
    };

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        Command::new("open")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path.as_ref())
            .spawn()?
            .wait()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new("open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .spawn()?
            .wait()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod unix {

    use std::{
        ffi::OsStr,
        io::{Error, Result},
        process::{Command, ExitStatus, Stdio},
    };

    use which::which;

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        ["xdg-open", "gnome-open", "kde-open", "wslview"] // Open handlers
            .iter()
            .find(|it| which(it).is_ok()) // find the first handler that exists
            .ok_or(Error::from_raw_os_error(0)) // If not found, return err
            .and_then(|program| {
                // If found run the handler
                Command::new(program)
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .arg(path.as_ref())
                    .spawn()?
                    .wait()
            })
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
    }
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a sheared context.
    #[inline(always)]
    pub fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear: [f64, ..6] = [1.0, sx, 0.0,
                                         sy, 1.0, 0.0];
            multiply(&shear, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<commit_msg>Added BackEnd trait<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if 2d triangle list with color assigned per vertex is supported.
    fn supports_tri_list_xy_rgba(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba(&mut self, _vertices: &[f64], _colors: &[f64]) {}
}

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a sheared context.
    #[inline(always)]
    pub fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear: [f64, ..6] = [1.0, sx, 0.0,
                                         sy, 1.0, 0.0];
            multiply(&shear, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<|endoftext|>


<commit_before>//! kaiseki -- literate programming preprocessing

#[macro_use] extern crate error_chain;
extern crate regex;

pub mod input;
pub mod list;

mod parsing;

pub mod processing_errors {
  error_chain! {
    errors {
      NotUTF8(file: String, lineno: usize) {
        description("line is not valid UTF-8")
        display("error: '{}', line {}: not valid UTF-8", file, lineno)
      }

      MalformedAnchor(file: String, lineno: usize, anchor: String) {
        description("could not parse anchor tag")
        display("warn: '{}', line {}: ignoring malformed anchor: '{}'", file, lineno, anchor)
      }

      DuplicateAnchor(file: String, lineno: usize, tag: String) {
        description("found a duplicate anchor tag")
        display("warn: '{}', line {}: ignoring duplicate anchor tag: '{}'", file, lineno, tag)
      }

      MissingTag(file: String, lineno: usize, tag: String) {
        description("nonexistent tag name")
        display("warn: '{}', line {}: nonexistent tag name: '{}'", file, lineno, tag)
      }
    }
  }
}

use std::rc::Rc;
use std::io;
use std::result;
use std::default::Default;

use std::collections::BTreeMap;

use input::File;
use list::List;

pub struct OutputOptions {
  pub comment: Option<String>
}

impl Default for OutputOptions {
  fn default() -> Self {
    OutputOptions {
      comment: None
    }
  }
}

struct Block {
  lines: Vec<String>,
  file: Rc<String>,
  lineno: usize
}

impl Block {
  fn new(file: Rc<String>, lineno: usize) -> Self {
    Block {
      lines: Vec::new(),
      file: file,
      lineno: lineno
    }
  }
}

struct Anchor {
  indentation: usize,  // The *absolute* level of indentation.
  tangled: Tangled
}

impl Anchor {
  fn new(indentation: usize) -> Self {
    Anchor {
      indentation: indentation,
      tangled: List::new()
    }
  }
}

/// Essentially a Result. But it makes the types more intuitive to read.
enum Either<T, U> {
  Left(T),
  Right(U)
}

struct AnchorRef(String);

type Tangled = List<Either<Block, AnchorRef>>;

enum OutputTarget {
  Insert,
  Before(AnchorRef),
  After(AnchorRef)
}

/// Process all the literate programming directives in the contents of the
/// given files, return a Vec of output lines (suitable for immediate
/// printing to, say, `stdout`)
pub fn tangle_output(inputs: Vec<File>, options: OutputOptions) -> (Vec<String>, Vec<processing_errors::Error>) {
  use std::io::{BufReader, BufRead};

  use parsing::Anchor;
  use processing_errors::ErrorKind;

  let mut tangled = List::new();
  let mut anchors = BTreeMap::new();
  let mut errors = Vec::new();  // Errors that we accrue during processing.

  for input in inputs {
    let filename = Rc::new(input.name);

    let mut lines = BufReader::new(input.contents)
      .lines()
      .enumerate()
      .map(|(lineno, line)| (lineno + 1, line));
    let mut state = OutputTarget::Insert;
    let mut tangled_section = List::new();
    let mut block = Block::new(filename.clone(), 1);

    macro_rules! emplace_section {
      () => {
        match state {
          OutputTarget::Insert => tangled.append_back(&mut tangled_section),
          OutputTarget::Before(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_front(&mut tangled_section);
          },
          OutputTarget::After(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_back(&mut tangled_section);
          }
        }
      }
    }

    loop {
      let next_anchor = process_block_lines(&mut lines, &mut block, &mut errors);

      if !block.lines.is_empty() {
        tangled_section.push_back(Either::Left(block));
      }

      match next_anchor {
        Some((lineno, indentation, anchor)) => {
          macro_rules! has_anchor {
            ($anchor_name:expr) => {{
              if anchors.contains_key($anchor_name) {
                true
              } else {
                let filename: &String = &filename;
                let error = ErrorKind::MissingTag(filename.clone(), lineno, $anchor_name.clone()).into();
                errors.push(error);
                false
              }
            }}
          }

          block = Block::new(filename.clone(), lineno);
          match anchor {
            Anchor::Insert => {
              emplace_section!();
              tangled_section = List::new();
              state = OutputTarget::Insert;
            },
            Anchor::Before(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::Before(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::After(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::After(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::Label(anchor_name) => {
              let anchor = ::Anchor::new(indentation);
              anchors.insert(anchor_name.clone(), anchor);
              tangled_section.push_back(Either::Right(AnchorRef(anchor_name)));
            }
          };
        },
        None => {
          emplace_section!();
          break;
        }
      };
    }
  }

  (collect_tangled_output(tangled, anchors, options), errors)
}

fn collect_tangled_output(tangled: Tangled,
                          mut anchors: BTreeMap<String, Anchor>,
                          options: OutputOptions) -> Vec<String>
{
  let mut lines = Vec::new();
  collect_anchor_lines(tangled, &mut anchors, &mut lines, 0, &options);
  lines
}

fn maybe_block_header(block: &Block, options: &OutputOptions) -> Option<String> {
  match &options.comment {
    &Some(ref comment_prefix) => {
      let header = format!(
        "{} '{}', line {}",
        comment_prefix,
        &block.file,
        block.lineno
      );

      Some(header)
    }
    &None => None
  }
}

fn collect_anchor_lines(tangled: Tangled,
                        anchors: &mut BTreeMap<String, Anchor>,
                        lines: &mut Vec<String>,
                        indentation: usize,
                        options: &OutputOptions)
{
  use std::iter;

  let indent_prefix = iter::repeat(' ').take(indentation).collect::<String>();

  for knot in tangled {
    match knot {
      Either::Left(block) => {
        if let Some(comment) = maybe_block_header(&block, options) {
          lines.push(indent_prefix.clone() + &comment);
        }

        for line in block.lines {
          lines.push(indent_prefix.clone() + &line);
        }
      },
      Either::Right(AnchorRef(ref anchor_name)) => {
        let anchor = anchors.remove(anchor_name)
          .expect("invariant violated: anchor name does not exist");

        collect_anchor_lines(
          anchor.tangled,
          anchors,
          lines,
          indentation + anchor.indentation,
          options
        );
      }
    };
  }
}

/// We scan through each file block by block.
/// Each block will end in either an anchor tag, or the end of the file.
fn process_block_lines<I>(lines: &mut I, block: &mut Block, errors: &mut Vec<processing_errors::Error>) -> Option<(usize, usize, parsing::Anchor)> where
  I: Iterator<Item=(usize, result::Result<String, io::Error>)>
{
  use processing_errors::ErrorKind;
  use std::ops::Deref;

  let filename = block.file.deref();

  for (lineno, line) in lines {
    match line {
      Ok(line) => {
        let result = parsing::might_be_anchor(&line)
          .ok_or(None)
          .and_then(|found| {
            parsing::parse(found.as_str())
              .map_err(|_| Some(ErrorKind::MalformedAnchor(
                filename.clone(),
                lineno,
                found.as_str().to_string()
              ).into()))
          });

        match result {
          Ok(anchor) => return Some((lineno, indentation_level(&line), anchor)),
          Err(Some(error)) => {
            errors.push(error);
            block.lines.push(line);
          },
          Err(None) => {
            block.lines.push(line);
          }
        };
      },
      Err(_) => errors.push(ErrorKind::NotUTF8(filename.clone(), lineno).into())
    };
  }

  None
}

/// Index of first non-whitespace character.
fn indentation_level(line: &str) -> usize {
  use regex::Regex;

  let nonwhitespace = Regex::new(r"[^\s]").unwrap();
  match nonwhitespace.find(line) {
    Some(found) => found.start(),
    None => 0
  }
}
<commit_msg>meh random comment<commit_after>//! kaiseki -- literate programming preprocessing

#[macro_use] extern crate error_chain;
extern crate regex;

pub mod input;
pub mod list;

mod parsing;

pub mod processing_errors {
  error_chain! {
    errors {
      NotUTF8(file: String, lineno: usize) {
        description("line is not valid UTF-8")
        display("error: '{}', line {}: not valid UTF-8", file, lineno)
      }

      MalformedAnchor(file: String, lineno: usize, anchor: String) {
        description("could not parse anchor tag")
        display("warn: '{}', line {}: ignoring malformed anchor: '{}'", file, lineno, anchor)
      }

      DuplicateAnchor(file: String, lineno: usize, tag: String) {
        description("found a duplicate anchor tag")
        display("warn: '{}', line {}: ignoring duplicate anchor tag: '{}'", file, lineno, tag)
      }

      MissingTag(file: String, lineno: usize, tag: String) {
        description("nonexistent tag name")
        display("warn: '{}', line {}: nonexistent tag name: '{}'", file, lineno, tag)
      }
    }
  }
}

use std::rc::Rc;
use std::io;
use std::result;
use std::default::Default;

use std::collections::BTreeMap;

use input::File;
use list::List;

pub struct OutputOptions {
  pub comment: Option<String>
}

impl Default for OutputOptions {
  fn default() -> Self {
    OutputOptions {
      comment: None
    }
  }
}

struct Block {
  lines: Vec<String>,
  file: Rc<String>,
  lineno: usize
}

impl Block {
  fn new(file: Rc<String>, lineno: usize) -> Self {
    Block {
      lines: Vec::new(),
      file: file,
      lineno: lineno
    }
  }
}

struct Anchor {
  indentation: usize,  // The *absolute* level of indentation.
  tangled: Tangled
}

impl Anchor {
  fn new(indentation: usize) -> Self {
    Anchor {
      indentation: indentation,
      tangled: List::new()
    }
  }
}

/// An `Either` represents the situation when *either* arm is a valid
/// value, as opposed to a `Result`, where one arm designates an error.
enum Either<T, U> {
  Left(T),
  Right(U)
}

struct AnchorRef(String);

type Tangled = List<Either<Block, AnchorRef>>;

enum OutputTarget {
  Insert,
  Before(AnchorRef),
  After(AnchorRef)
}

/// Process all the literate programming directives in the contents of the
/// given files, return a Vec of output lines (suitable for immediate
/// printing to, say, `stdout`)
pub fn tangle_output(inputs: Vec<File>, options: OutputOptions) -> (Vec<String>, Vec<processing_errors::Error>) {
  use std::io::{BufReader, BufRead};

  use parsing::Anchor;
  use processing_errors::ErrorKind;

  let mut tangled = List::new();
  let mut anchors = BTreeMap::new();
  let mut errors = Vec::new();  // Errors that we accrue during processing.

  for input in inputs {
    let filename = Rc::new(input.name);

    let mut lines = BufReader::new(input.contents)
      .lines()
      .enumerate()
      .map(|(lineno, line)| (lineno + 1, line));
    let mut state = OutputTarget::Insert;
    let mut tangled_section = List::new();
    let mut block = Block::new(filename.clone(), 1);

    macro_rules! emplace_section {
      () => {
        match state {
          OutputTarget::Insert => tangled.append_back(&mut tangled_section),
          OutputTarget::Before(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_front(&mut tangled_section);
          },
          OutputTarget::After(AnchorRef(anchor_name)) => {
            let anchor: &mut ::Anchor = anchors.get_mut(&anchor_name)
              .expect("invariant violated: anchor name does not exist");
            anchor.tangled.append_back(&mut tangled_section);
          }
        }
      }
    }

    loop {
      let next_anchor = process_block_lines(&mut lines, &mut block, &mut errors);

      if !block.lines.is_empty() {
        tangled_section.push_back(Either::Left(block));
      }

      match next_anchor {
        Some((lineno, indentation, anchor)) => {
          macro_rules! has_anchor {
            ($anchor_name:expr) => {{
              if anchors.contains_key($anchor_name) {
                true
              } else {
                let filename: &String = &filename;
                let error = ErrorKind::MissingTag(filename.clone(), lineno, $anchor_name.clone()).into();
                errors.push(error);
                false
              }
            }}
          }

          block = Block::new(filename.clone(), lineno);
          match anchor {
            Anchor::Insert => {
              emplace_section!();
              tangled_section = List::new();
              state = OutputTarget::Insert;
            },
            Anchor::Before(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::Before(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::After(anchor_name) => {
              emplace_section!();
              tangled_section = List::new();
              if has_anchor!(&anchor_name) {
                state = OutputTarget::After(AnchorRef(anchor_name));
              } else {
                state = OutputTarget::Insert;
              }
            },
            Anchor::Label(anchor_name) => {
              let anchor = ::Anchor::new(indentation);
              anchors.insert(anchor_name.clone(), anchor);
              tangled_section.push_back(Either::Right(AnchorRef(anchor_name)));
            }
          };
        },
        None => {
          emplace_section!();
          break;
        }
      };
    }
  }

  (collect_tangled_output(tangled, anchors, options), errors)
}

fn collect_tangled_output(tangled: Tangled,
                          mut anchors: BTreeMap<String, Anchor>,
                          options: OutputOptions) -> Vec<String>
{
  let mut lines = Vec::new();
  collect_anchor_lines(tangled, &mut anchors, &mut lines, 0, &options);
  lines
}

fn maybe_block_header(block: &Block, options: &OutputOptions) -> Option<String> {
  match &options.comment {
    &Some(ref comment_prefix) => {
      let header = format!(
        "{} '{}', line {}",
        comment_prefix,
        &block.file,
        block.lineno
      );

      Some(header)
    }
    &None => None
  }
}

fn collect_anchor_lines(tangled: Tangled,
                        anchors: &mut BTreeMap<String, Anchor>,
                        lines: &mut Vec<String>,
                        indentation: usize,
                        options: &OutputOptions)
{
  use std::iter;

  let indent_prefix = iter::repeat(' ').take(indentation).collect::<String>();

  for knot in tangled {
    match knot {
      Either::Left(block) => {
        if let Some(comment) = maybe_block_header(&block, options) {
          lines.push(indent_prefix.clone() + &comment);
        }

        for line in block.lines {
          lines.push(indent_prefix.clone() + &line);
        }
      },
      Either::Right(AnchorRef(ref anchor_name)) => {
        let anchor = anchors.remove(anchor_name)
          .expect("invariant violated: anchor name does not exist");

        collect_anchor_lines(
          anchor.tangled,
          anchors,
          lines,
          indentation + anchor.indentation,
          options
        );
      }
    };
  }
}

/// We scan through each file block by block.
/// Each block will end in either an anchor tag, or the end of the file.
fn process_block_lines<I>(lines: &mut I, block: &mut Block, errors: &mut Vec<processing_errors::Error>) -> Option<(usize, usize, parsing::Anchor)> where
  I: Iterator<Item=(usize, result::Result<String, io::Error>)>
{
  use processing_errors::ErrorKind;
  use std::ops::Deref;

  let filename = block.file.deref();

  for (lineno, line) in lines {
    match line {
      Ok(line) => {
        let result = parsing::might_be_anchor(&line)
          .ok_or(None)
          .and_then(|found| {
            parsing::parse(found.as_str())
              .map_err(|_| Some(ErrorKind::MalformedAnchor(
                filename.clone(),
                lineno,
                found.as_str().to_string()
              ).into()))
          });

        match result {
          Ok(anchor) => return Some((lineno, indentation_level(&line), anchor)),
          Err(Some(error)) => {
            errors.push(error);
            block.lines.push(line);
          },
          Err(None) => {
            block.lines.push(line);
          }
        };
      },
      Err(_) => errors.push(ErrorKind::NotUTF8(filename.clone(), lineno).into())
    };
  }

  None
}

/// Index of first non-whitespace character.
fn indentation_level(line: &str) -> usize {
  use regex::Regex;

  let nonwhitespace = Regex::new(r"[^\s]").unwrap();
  match nonwhitespace.find(line) {
    Some(found) => found.start(),
    None => 0
  }
}
<|endoftext|>


<commit_before>extern crate bit_vec;

use self::bit_vec::BitVec;
use std::fmt;

pub const DFA_START: usize = 0; // Same as nfa::NFA_START!
pub const DFA_STUCK: usize = 1;

#[derive(Debug)]
pub struct DFAState {
    transitions: Box<[usize]>,
}

#[derive(Debug)]
pub struct DFA {
    states: Box<[DFAState]>,
    finals: BitVec,
}

pub struct DDFA {
    states: Box<[DDFAState]>,
}

// Living dangerously: raw pointers baby
#[derive(Clone, PartialEq)]
struct DDFAState {
    transitions: Box<[*const DDFAState]>,
    is_final: bool,
}

impl DFAState {
    pub fn new(transitions: Box<[usize]>) -> Self {
        DFAState { transitions: transitions }
    }
}

impl DFA {
    pub fn new(states: Box<[DFAState]>, finals: BitVec) -> Self {
        DFA {
            states: states,
            finals: finals,
        }
    }

    pub fn into_ddfa(self) -> Result<DDFA, ()> {
        let len = self.states.len();
        let mut states = vec![DDFAState { transitions: Box::new([]), is_final: false }; len]
            .into_boxed_slice();

        let states_start: *mut DDFAState = (*states).as_mut_ptr();

        for (i, ref st) in self.states.iter().enumerate() {
            let mut v: Vec<*const DDFAState> = Vec::with_capacity(st.transitions.len());
            for &offset in st.transitions.iter() {
                if offset >= len {
                    return Err(());
                }
                unsafe {
                    v.push(states_start.offset(offset as isize) as *const DDFAState);
                }
            }
            states[i].transitions = v.into_boxed_slice();
            states[i].is_final = self.finals[i];
        }
        Ok(DDFA { states: states })
    }

    pub fn apply(&self, input: &[u8]) -> bool {
        let mut cur_state = DFA_START;
        for &byte in input {
            cur_state = self.states[cur_state].transitions[byte as usize];
            if cur_state == DFA_STUCK {
                break;
            }
        }
        self.finals[cur_state]
    }
}

impl fmt::Display for DFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, state) in (*self.states).into_iter().enumerate() {
            if i == DFA_STUCK {
                try!(writeln!(f, "{} -- stuck state,", DFA_STUCK));
                continue;
            }
            try!(write!(f, "{} -> [", i));
            if !state.transitions.is_empty() {
                try!(writeln!(f, ""));
            }
            let mut last_c = 0;
            let mut iter = (*state.transitions)
                .into_iter()
                .enumerate()
                .peekable();
            while let Some((c, tr)) = iter.next() {
                if let Some(&(c2, tr2)) = iter.peek() {
                    if tr == tr2 {
                        continue;
                    }
                    if c == last_c {
                        try!(writeln!(f, "  {:?} -> {:?},", c as u8 as char, tr));
                    } else {
                        try!(writeln!(f,
                                      "  [{:?}-{:?}] -> {:?},",
                                      last_c as u8 as char,
                                      (c as u8) as char,
                                      tr));
                    }
                    last_c = c2;
                }
            }
            try!(write!(f, "]"));
            if i == DFA_START {
                try!(write!(f, " -- start state"));
            }
            if self.finals[i] {
                try!(write!(f, " -- final state"));
            }
            try!(writeln!(f, ","));
        }
        Ok(())
    }
}

impl DDFA {
    pub fn apply(&self, input: &[u8]) -> bool {
        let mut cur_state: *const DDFAState = &self.states[DFA_START];
        let stuck = &self.states[DFA_STUCK];
        for &byte in input {
            cur_state = unsafe { (*cur_state).transitions[byte as usize] };
            if cur_state == stuck {
                break;
            }
        }
        unsafe { (*cur_state).is_final }
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Added display method for DDFA that outputs the same as the DFA version. Added Debug derivations. Not sure if the Display implementations are better suited for Debug<commit_after>extern crate bit_vec;

use self::bit_vec::BitVec;
use std::mem;
use std::fmt;

pub const DFA_START: usize = 0; // Same as nfa::NFA_START!
pub const DFA_STUCK: usize = 1;

#[derive(Debug)]
pub struct DFAState {
    transitions: Box<[usize]>,
}

#[derive(Debug)]
pub struct DFA {
    states: Box<[DFAState]>,
    finals: BitVec,
}

#[derive(Debug)]
pub struct DDFA {
    states: Box<[DDFAState]>,
}

// Living dangerously: raw pointers baby
#[derive(Clone, PartialEq, Debug)]
struct DDFAState {
    transitions: Box<[*const DDFAState]>,
    is_final: bool,
}

impl DFAState {
    pub fn new(transitions: Box<[usize]>) -> Self {
        DFAState { transitions: transitions }
    }
}

impl DFA {
    pub fn new(states: Box<[DFAState]>, finals: BitVec) -> Self {
        DFA {
            states: states,
            finals: finals,
        }
    }

    pub fn into_ddfa(self) -> Result<DDFA, ()> {
        let len = self.states.len();
        let mut states = vec![DDFAState { transitions: Box::new([]), is_final: false }; len]
            .into_boxed_slice();

        let states_start: *mut DDFAState = (*states).as_mut_ptr();

        for (i, ref st) in self.states.iter().enumerate() {
            let mut v: Vec<*const DDFAState> = Vec::with_capacity(st.transitions.len());
            for &offset in st.transitions.iter() {
                if offset >= len {
                    return Err(());
                }
                unsafe {
                    v.push(states_start.offset(offset as isize) as *const DDFAState);
                }
            }
            states[i].transitions = v.into_boxed_slice();
            states[i].is_final = self.finals[i];
        }
        Ok(DDFA { states: states })
    }

    pub fn apply(&self, input: &[u8]) -> bool {
        let mut cur_state = DFA_START;
        for &byte in input {
            cur_state = self.states[cur_state].transitions[byte as usize];
            if cur_state == DFA_STUCK {
                break;
            }
        }
        self.finals[cur_state]
    }
}

impl fmt::Display for DFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, state) in (*self.states).into_iter().enumerate() {
            if i == DFA_STUCK {
                try!(writeln!(f, "{} -- stuck state,", DFA_STUCK));
                continue;
            }
            try!(write!(f, "{} -> [", i));
            if !state.transitions.is_empty() {
                try!(writeln!(f, ""));
            }
            let mut last_c = 0;
            let mut iter = (*state.transitions)
                .into_iter()
                .enumerate()
                .peekable();
            while let Some((c, tr)) = iter.next() {
                if let Some(&(c2, tr2)) = iter.peek() {
                    if tr == tr2 {
                        continue;
                    }
                    if c == last_c {
                        try!(writeln!(f, "  {:?} -> {:?},", c as u8 as char, tr));
                    } else {
                        try!(writeln!(f,
                                      "  [{:?}-{:?}] -> {:?},",
                                      last_c as u8 as char,
                                      (c as u8) as char,
                                      tr));
                    }
                    last_c = c2;
                }
            }
            try!(write!(f, "]"));
            if i == DFA_START {
                try!(write!(f, " -- start state"));
            }
            if self.finals[i] {
                try!(write!(f, " -- final state"));
            }
            try!(writeln!(f, ","));
        }
        Ok(())
    }
}

impl DDFA {
    pub fn apply(&self, input: &[u8]) -> bool {
        let mut cur_state: *const DDFAState = &self.states[DFA_START];
        let stuck = &self.states[DFA_STUCK];
        for &byte in input {
            cur_state = unsafe { (*cur_state).transitions[byte as usize] };
            if cur_state == stuck {
                break;
            }
        }
        unsafe { (*cur_state).is_final }
    }
}

impl fmt::Display for DDFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let start = &self.states[0] as *const DDFAState;
        for (i, state) in (*self.states).into_iter().enumerate() {
            if i == DFA_STUCK {
                try!(writeln!(f, "{} -- stuck state,", DFA_STUCK));
                continue;
            }
            try!(write!(f, "{} -> [", i));
            if !state.transitions.is_empty() {
                try!(writeln!(f, ""));
            }
            let mut last_c = 0;
            let mut iter = (*state.transitions)
                .into_iter()
                .enumerate()
                .peekable();
            while let Some((c, tr)) = iter.next() {
                if let Some(&(c2, tr2)) = iter.peek() {
                    if tr == tr2 {
                        continue;
                    }
                    let tr_no = (*tr as usize - start as usize) / mem::size_of::<DDFAState>();
                    if c == last_c {
                        try!(writeln!(f, "  {:?} -> {:?},", c as u8 as char, tr_no));
                    } else {
                        try!(writeln!(f,
                                      "  [{:?}-{:?}] -> {:?},",
                                      last_c as u8 as char,
                                      (c as u8) as char,
                                      tr_no));
                    }
                    last_c = c2;
                }
            }
            try!(write!(f, "]"));
            if i == DFA_START {
                try!(write!(f, " -- start state"));
            }
            if state.is_final {
                try!(write!(f, " -- final state"));
            }
            try!(writeln!(f, ","));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>//! A simple cross-platform library loader.
//!
//! ([crates.io](https://crates.io/crates/sharedlib)) ([github](https://github.com/Tyleo/sharedlib))
//!
//! Based on [libloading](https://crates.io/crates/libloading) by Simonas Kazlauskas.
//!
//! # Loading a library
//! To load a library you can use any of the [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), or [LibUnsafe](struct.LibUnsafe.html) `structs`. Each of these `struct`s provides different guarantees. For more information about the guarantees they provide, see the [chosing your guarantees](index.html#choosing-your-guarantees) section, below. We use [Lib](struct.Lib.html) for the examples below.
//!
//! ### Calling a function in another library
//! ```norun
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let hello_world_symbol: Func<extern "C" fn()> = try!(lib.find_func("hello_world"));
//!     let hello_world = hello_world_symbol.get();
//!     hello_world();
//! }
//! ```
//!
//! ### Accessing data in another library
//! ```norun
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let my_usize_symbol: Data<usize> = try!(lib.find_data("my_usize"));
//!     let my_usize = my_usize_symbol.get();
//!     assert_eq!(*my_usize, 0);
//! }
//! ```
//!
//! ### Choosing your guarantees
//! A common problem when loading a shared library at runtime is that a symbol may be accessed after its library has been unloaded. [sharedlib](index.html) attempts to prevent this by allowing the lifetime of the library to be tracked. Each of the different libraries, [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), or [LibUnsafe](struct.LibUnsafe.html), provides a different tracking mechanism. Below is a small overview. For more information, see the struct level documentation.
//!
//! * [LibUnsafe](struct.LibUnsafe.html) does not provide any tracking at all. This requires no overhead but responsibility falls on the client to be sure that the library is still alive when its symbols are used.
//!
//! * [Lib](struct.Lib.html) attaches its own lifetime to each symbol it returns. This requires no overhead but it can be difficult to store the returned symbol in a `struct` because the `struct` must have a trackable lifetime which outlives the [Lib](struct.Lib.html). In other words, a struct containing a symbol must parameterize around some lifetime `a`, where `a` is less than or equal to the lifetime of the library.
//!
//! * [LibTracked](struct.LibTracked.html) returns symbols with ref-counts to the library. This requires overhead but it allows the returned symbol to be stored easily. Additionally, this `struct` is generic and can be used with `Rc`, `Arc`, or a user provided ref-count type.
//!
//! # Pitfalls
//! While [sharedlib](index.html) attempts to prevent undefined behavior, loading shared libraries is inherently unsafe. Below are some tips which you may find helpful so that your code is not exposed to undefined behavior.
//!
//! ### Avoid copying or moving data returned from `get()`
//! The [get](trait.Symbol.html#method.get) method on [Symbol](trait.Symbol.html) returns a transmuted pointer to something in a loaded library. While [sharedlib](index.html) tries to make sure that this pointer cannot outlive the library it is from, full protection is impossible. In particular: if a loaded `struct` contains pointers to things in the loaded library, and the loaded `struct` implements `Clone`, clients can clone the `struct` and make it to live longer than the library it is from. If this happens the pointers in the `struct` dangle. The example below demonstrate:
//!
//! ```norun
//! unsafe {
//!     let some_func = {
//!         let lib = try!(Lib::new("examplelib.dll"));
//!         let some_func_symbol: Func<extern "C" fn()> = try!(lib.find_func(b"some_func"));
//!         // All func pointers implement `Copy` so we can duplicate one.
//!         some_func_symbol.get()
//!         // lib goes out of scope here.
//!     };
//!     // Undefined behavior
//!     some_func();
//! }
//! ```
//! ### Use the correct method when getting functions or data
//! Each library provides two different ways to get symbols from shared libraries. One way is `find_func`, and the other is `find_data`. Two functions are provded because `find_data` needs to return a reference to a `T` rather than a `T` itself, while `find_func` just needs to return a `T` itself. Returning the wrong thing can cause some complications. For instance: suppose we only have the `find_data` method, and we want to get a function pointer with the signature `fn()`. We are inclined to call `lib.find_data::<fn()>(b"some_func")`. This searches the memory of the loaded binary and finds the address of the first line of the function `some_func`. Next, the *contents* of the first line of `some_func` are treated as a function pointer rather than the *address* of the first line of `some_func`. When the first line of `some_func` is returned it is incorrectly cast into a function pointer. Calling it produces undefined behavior. The example below demonstrates:
//!
//! ```norun
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     let some_func_symbol: Data<extern "C" fn()> = try!(lib.find_data(b"some_func"));
//!     // some_func actually points to a function but rust thinks it points to a function pointer.
//!     let some_func = some_func_symbol.get();
//!     // Undefined behavior
//!     some_func();
//! }
//! ```
//!
//! The correct way to do this with `find_data` is as follows:
//!
//! ```norun
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     // Get a pointer to the block of memory at "some_func", this is the function itself.
//!     let some_func_symbol: Data<u8> = try!(lib.find_data(b"some_func"));
//!     // The type of some_func is &u8, a reference to the first byte of `some_func`. We can convert this into a function pointer.
//!     let some_func = some_func_symbol.get();
//!     let some_func_ptr: extern "C" fn() = std::mem::transmute(some_func);
//!     // This works now.
//!     some_func_ptr();
//! }
//! ```
//!
//! For convienience, the second example is provided as the `find_func` method, which does this error-prone conversion behind the scenes.
//!
//! # Comparison with other crates for loabing shared libraries
//! sharedlib was created out of frusteration with the existing crates for loading shared libraries. Below is a list of some of these crates with some information abuot how sharedlib improves upon them.
//!
//! * [dylib](https://crates.io/crates/dylib) provides an extremely simple interface for loading shared libraries. For awhile, this was the standard for loading shared libraries at runtime. Unfortunately, development on dylib has been mostly abandoned and it is no longer supported on the latest versions of the rust compiler.
//!
//! * [libloading](https://crates.io/crates/libloading) provides some additional safety guarantees on top of [dylib](https://crates.io/crates/dylib). [sharedlib](index.html) even started as a fork of [libloading](https://crates.io/crates/libloading). Unfortunately the interface [libloading](https://crates.io/crates/libloading) provides is extremely inflexible, requiring clients to transmute symbols so they can be used in `struct`s. Additionally, loading data does not work with this library which is a non-starter for many projects.
//!
//! # Frequently asked questions
//!
//! ### What is a shared library?
//! A shared library is a set of functions and variables which can be loaded after a program has been compiled. By loading a library after compilation, the library can be recompiled or changed without recompiling the main program. Shared libraries can even be loaded at runtime. Common shared library filetypes are *.dll* for windows, *.so* for unix, and *.dylib* for osx. For more information about what a shared library is, see [wikipedia](https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries).
//!
//! ### Doesn't rust already provide linking against shared libraries?
//! While rust provides linking against shared libraries, it does not provide the ability to load them at runtime. If you only want to use shared libraries that you know about before runtime, you may find not find this crate very useful. On the other hand, if you wish to load something at runtime, like a plugin, you are in the right place.

#[macro_use]
extern crate define_error;

#[macro_use]
extern crate lazy_static;

#[cfg(windows)]
extern crate kernel32;

#[cfg(windows)]
extern crate winapi;

pub mod error;

mod os;

mod lib_impl;

mod string;

mod symbol;

#[cfg(test)]
mod test;

mod util;

pub use error::SharedlibError;

pub use error::SharedlibResult;

pub use lib_impl::Lib;

pub use lib_impl::LibArc;

pub use lib_impl::LibRc;

pub use lib_impl::LibTracked;

pub use lib_impl::LibUnsafe;

pub use symbol::Data;

pub use symbol::DataArc;

pub use symbol::DataRc;

pub use symbol::DataTracked;

pub use symbol::DataUnsafe;

pub use symbol::Func;

pub use symbol::FuncArc;

pub use symbol::FuncRc;

pub use symbol::FuncTracked;

pub use symbol::FuncUnsafe;

pub use symbol::Symbol;
<commit_msg>Update doc tests so that they compile.<commit_after>//! A simple cross-platform library loader.
//!
//! ([crates.io](https://crates.io/crates/sharedlib)) ([github](https://github.com/Tyleo/sharedlib))
//!
//! Based on [libloading](https://crates.io/crates/libloading) by Simonas Kazlauskas.
//!
//! # Loading a library
//! To load a library you can use any of the [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), or [LibUnsafe](struct.LibUnsafe.html) `structs`. Each of these `struct`s provides different guarantees. For more information about the guarantees they provide, see the [chosing your guarantees](index.html#choosing-your-guarantees) section, below. We use [Lib](struct.Lib.html) for the examples below.
//!
//! ### Calling a function in another library
//! ``` no_run
//! # use sharedlib::Func;
//! # use sharedlib::Lib;
//! # use sharedlib::SharedlibResult as R;
//! # use sharedlib::Symbol;
//! # fn test() -> R<()> {
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let hello_world_symbol: Func<extern "C" fn()> = try!(lib.find_func("hello_world"));
//!     let hello_world = hello_world_symbol.get();
//!     hello_world();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Accessing data in another library
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::Lib;
//! # use sharedlib::SharedlibResult as R;
//! # use sharedlib::Symbol;
//! # fn test() -> R<()> {
//! unsafe {
//!     let path_to_lib = "examplelib.dll";
//!     let lib = try!(Lib::new(path_to_lib));
//!     let my_usize_symbol: Data<usize> = try!(lib.find_data("my_usize"));
//!     let my_usize = my_usize_symbol.get();
//!     assert_eq!(*my_usize, 0);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Choosing your guarantees
//! A common problem when loading a shared library at runtime is that a symbol may be accessed after its library has been unloaded. [sharedlib](index.html) attempts to prevent this by allowing the lifetime of the library to be tracked. Each of the different libraries, [Lib](struct.Lib.html), [LibTracked](struct.LibTracked.html), or [LibUnsafe](struct.LibUnsafe.html), provides a different tracking mechanism. Below is a small overview. For more information, see the struct level documentation.
//!
//! * [LibUnsafe](struct.LibUnsafe.html) does not provide any tracking at all. This requires no overhead but responsibility falls on the client to be sure that the library is still alive when its symbols are used.
//!
//! * [Lib](struct.Lib.html) attaches its own lifetime to each symbol it returns. This requires no overhead but it can be difficult to store the returned symbol in a `struct` because the `struct` must have a trackable lifetime which outlives the [Lib](struct.Lib.html). In other words, a struct containing a symbol must parameterize around some lifetime `a`, where `a` is less than or equal to the lifetime of the library.
//!
//! * [LibTracked](struct.LibTracked.html) returns symbols with ref-counts to the library. This requires overhead but it allows the returned symbol to be stored easily. Additionally, this `struct` is generic and can be used with `Rc`, `Arc`, or a user provided ref-count type.
//!
//! # Pitfalls
//! While [sharedlib](index.html) attempts to prevent undefined behavior, loading shared libraries is inherently unsafe. Below are some tips which you may find helpful so that your code is not exposed to undefined behavior.
//!
//! ### Avoid copying or moving data returned from `get()`
//! The [get](trait.Symbol.html#method.get) method on [Symbol](trait.Symbol.html) returns a transmuted pointer to something in a loaded library. While [sharedlib](index.html) tries to make sure that this pointer cannot outlive the library it is from, full protection is impossible. In particular: if a loaded `struct` contains pointers to things in the loaded library, and the loaded `struct` implements `Clone`, clients can clone the `struct` and make it to live longer than the library it is from. If this happens the pointers in the `struct` dangle. The example below demonstrate:
//!
//! ``` no_run
//! # use sharedlib::Func;
//! # use sharedlib::Lib;
//! # use sharedlib::SharedlibResult as R;
//! # use sharedlib::Symbol;
//! # fn test() -> R<()> {
//! unsafe {
//!     let some_func = {
//!         let lib = try!(Lib::new("examplelib.dll"));
//!         let some_func_symbol: Func<extern "C" fn()> = try!(lib.find_func("some_func"));
//!         // All func pointers implement `Copy` so we can duplicate one.
//!         some_func_symbol.get()
//!         // lib goes out of scope here.
//!     };
//!     // Undefined behavior
//!     some_func();
//! }
//! # Ok(())
//! # }
//! ```
//! ### Use the correct method when getting functions or data
//! Each library provides two different ways to get symbols from shared libraries. One way is `find_func`, and the other is `find_data`. Two functions are provded because `find_data` needs to return a reference to a `T` rather than a `T` itself, while `find_func` just needs to return a `T` itself. Returning the wrong thing can cause some complications. For instance: suppose we only have the `find_data` method, and we want to get a function pointer with the signature `fn()`. We are inclined to call `lib.find_data::<fn()>(b"some_func")`. This searches the memory of the loaded binary and finds the address of the first line of the function `some_func`. Next, the *contents* of the first line of `some_func` are treated as a function pointer rather than the *address* of the first line of `some_func`. When the first line of `some_func` is returned it is incorrectly cast into a function pointer. Calling it produces undefined behavior. The example below demonstrates:
//!
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::Lib;
//! # use sharedlib::SharedlibResult as R;
//! # use sharedlib::Symbol;
//! # fn test() -> R<()> {
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     let some_func_symbol: Data<extern "C" fn()> = try!(lib.find_data("some_func"));
//!     // some_func actually points to a function but rust thinks it points to a function pointer.
//!     let some_func = some_func_symbol.get();
//!     // Undefined behavior
//!     some_func();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! The correct way to do this with `find_data` is as follows:
//!
//! ``` no_run
//! # use sharedlib::Data;
//! # use sharedlib::Lib;
//! # use sharedlib::SharedlibResult as R;
//! # use sharedlib::Symbol;
//! # fn test() -> R<()> {
//! unsafe {
//!     let lib = try!(Lib::new("examplelib.dll"));
//!     // Get a pointer to the block of memory at "some_func", this is the function itself.
//!     let some_func_symbol: Data<u8> = try!(lib.find_data("some_func"));
//!     // The type of some_func is &u8, a reference to the first byte of `some_func`. We can convert this into a function pointer.
//!     let some_func = some_func_symbol.get();
//!     let some_func_ptr: extern "C" fn() = std::mem::transmute(some_func);
//!     // This works now.
//!     some_func_ptr();
//! }
//! # Ok(())
//! # }
//! ```
//!
//! For convienience, the second example is provided as the `find_func` method, which does this error-prone conversion behind the scenes.
//!
//! # Comparison with other crates for loabing shared libraries
//! sharedlib was created out of frusteration with the existing crates for loading shared libraries. Below is a list of some of these crates with some information abuot how sharedlib improves upon them.
//!
//! * [dylib](https://crates.io/crates/dylib) provides an extremely simple interface for loading shared libraries. For awhile, this was the standard for loading shared libraries at runtime. Unfortunately, development on dylib has been mostly abandoned and it is no longer supported on the latest versions of the rust compiler.
//!
//! * [libloading](https://crates.io/crates/libloading) provides some additional safety guarantees on top of [dylib](https://crates.io/crates/dylib). [sharedlib](index.html) even started as a fork of [libloading](https://crates.io/crates/libloading). Unfortunately the interface [libloading](https://crates.io/crates/libloading) provides is extremely inflexible, requiring clients to transmute symbols so they can be used in `struct`s. Additionally, loading data does not work with this library which is a non-starter for many projects.
//!
//! # Frequently asked questions
//!
//! ### What is a shared library?
//! A shared library is a set of functions and variables which can be loaded after a program has been compiled. By loading a library after compilation, the library can be recompiled or changed without recompiling the main program. Shared libraries can even be loaded at runtime. Common shared library filetypes are *.dll* for windows, *.so* for unix, and *.dylib* for osx. For more information about what a shared library is, see [wikipedia](https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries).
//!
//! ### Doesn't rust already provide linking against shared libraries?
//! While rust provides linking against shared libraries, it does not provide the ability to load them at runtime. If you only want to use shared libraries that you know about before runtime, you may find not find this crate very useful. On the other hand, if you wish to load something at runtime, like a plugin, you are in the right place.

#[macro_use]
extern crate define_error;

#[macro_use]
extern crate lazy_static;

#[cfg(windows)]
extern crate kernel32;

#[cfg(windows)]
extern crate winapi;

pub mod error;

mod os;

mod lib_impl;

mod string;

mod symbol;

#[cfg(test)]
mod test;

mod util;

pub use error::SharedlibError;

pub use error::SharedlibResult;

pub use lib_impl::Lib;

pub use lib_impl::LibArc;

pub use lib_impl::LibRc;

pub use lib_impl::LibTracked;

pub use lib_impl::LibUnsafe;

pub use symbol::Data;

pub use symbol::DataArc;

pub use symbol::DataRc;

pub use symbol::DataTracked;

pub use symbol::DataUnsafe;

pub use symbol::Func;

pub use symbol::FuncArc;

pub use symbol::FuncRc;

pub use symbol::FuncTracked;

pub use symbol::FuncUnsafe;

pub use symbol::Symbol;
<|endoftext|>