<commit_before>//! # Poisson-disk distribution generation
//!
//! Generates distribution of points where:
//!
//! * For each point there is disk of certain radius which doesn't intersect
//! with any other disk of other points
//! * Samples fill the space uniformly
//!
//! # Examples
//!
//! ```
//! extern crate poisson;
//! use poisson::{Builder, Type, algorithm};
//!
//! extern crate rand;
//!
//! extern crate nalgebra as na;
//! type Vec2 = na::Vector2<f64>;
//!
//! fn main() {
//!     let poisson =
//!         Builder::<_, Vec2>::with_radius(0.1, Type::Normal)
//!             .build(rand::weak_rng(), algorithm::Ebeida);
//!     let samples = poisson.generate();
//!     println!("{:?}", samples);
//! }
//! ```
extern crate modulo;

extern crate sphere;

extern crate rand;
use rand::{Rand, Rng};

extern crate num_traits;
use num_traits::{NumCast, Zero};
use num_traits::Float as NumFloat;

extern crate alga;
use alga::general::AbstractField;
use alga::linear::{NormedSpace, FiniteDimVectorSpace};

#[macro_use]
extern crate lazy_static;

use std::marker::PhantomData;
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, Index, IndexMut};

use algorithm::{Creator, Algorithm};
use utils::math::calc_radius;

pub mod algorithm;
mod utils;

/// Describes what floats are.
pub trait Float:
    NumFloat +
    AbstractField +
    AddAssign +
    SubAssign +
    MulAssign +
    DivAssign +
    Rand
{
    /// Casts usize to float.
    fn cast(n: usize) -> Self {
        NumCast::from(n).expect("Casting usize to float should always succeed.")
    }
}
impl<T> Float for T where T: NumFloat + AbstractField + AddAssign + SubAssign + MulAssign + DivAssign + Rand
{}

/// Describes what vectors are.
pub trait Vector<F>:
    Zero +
    Rand +
    FiniteDimVectorSpace<Field=F> +
    NormedSpace<Field=F> +
    Index<usize> +
    IndexMut<usize> +
    Clone
      where F: Float,
{}
impl<T, F> Vector<F> for T
    where F: Float,
          T: Zero + Rand + FiniteDimVectorSpace<Field=F> + NormedSpace<Field=F> + Clone,
{}

/// Enum for determining the type of poisson-disk distribution.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Type {
    /// Acts like there is void all around the space placing no restrictions to sides.
    Normal,
    /// Makes the space to wrap around on edges allowing tiling of poisson-disk distribution.
    /// This makes samples next to a edge restrict samples on opposite one.
    Perioditic,
}

impl Default for Type {
    fn default() -> Type {
        Type::Normal
    }
}

/// Builder for the generator.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Builder<F, V>
    where F: Float,
          V: Vector<F>,
{
    radius: F,
    poisson_type: Type,
    _marker: PhantomData<V>,
}

impl<V, F> Builder<F, V>
    where F: Float,
          V: Vector<F>,
{
    /// New Builder with type of distribution and radius specified.
    /// The radius should be ]0, √2 / 2]
    pub fn with_radius(radius: F, poisson_type: Type) -> Self {
        assert!(F::cast(0) < radius);
        assert!(radius <=
                NumCast::from(2f64.sqrt() / 2.).expect("Casting constant should always work."));
        Builder {
            radius: radius,
            poisson_type: poisson_type,
            _marker: PhantomData,
        }
    }

    /// New Builder with type of distribution and relative radius specified.
    /// The relative radius should be ]0, 1]
    pub fn with_relative_radius(relative: F, poisson_type: Type) -> Self {
        assert!(relative >= F::cast(0));
        assert!(relative <= F::cast(1));
        Builder {
            radius: relative *
                    NumCast::from(2f64.sqrt() / 2.).expect("Casting constant should always work."),
            poisson_type: poisson_type,
            _marker: PhantomData,
        }
    }

    /// New Builder with type of distribution, approximate amount of samples and relative radius specified.
    /// The amount of samples should be larger than 0.
    /// The relative radius should be [0, 1].
    /// For non-perioditic this is supported only for 2, 3 and 4 dimensional generation.
    pub fn with_samples(samples: usize, relative: F, poisson_type: Type) -> Self {
        Builder {
            radius: calc_radius::<F, V>(samples, relative, poisson_type),
            poisson_type: poisson_type,
            _marker: PhantomData,
        }
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> F {
        self.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson_type
    }

    /// Builds generator with random number generator and algorithm specified.
    pub fn build<R, A>(self, rng: R, _algo: A) -> Generator<F, V, R, A>
        where R: Rng,
              A: Creator<F, V>
    {
        Generator::new(self, rng)
    }
}

/// Generates poisson-disk distribution for [0, 1]² area.
#[derive(Clone, Debug)]
pub struct Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Creator<F, V>,
{
    poisson: Builder<F, V>,
    rng: R,
    _algo: PhantomData<A>,
}

impl<F, V, R, A> Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Creator<F, V>,
{
    fn new(poisson: Builder<F, V>, rng: R) -> Self {
        Generator {
            rng: rng,
            poisson: poisson,
            _algo: PhantomData,
        }
    }

    /// Sets the radius of the generator.
    pub fn set_radius(&mut self, radius: F) {
        assert!(F::cast(0) < radius);
        assert!(radius <=
                NumCast::from(2f64.sqrt() / 2.).expect("Casting constant should always work."));
        self.poisson.radius = radius;
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> F {
        self.poisson.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson.poisson_type
    }
}

impl<F, V, R, A> Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng + Clone,
          A: Creator<F, V>,
{
    /// Generates Poisson-disk distribution.
    pub fn generate(&self) -> Vec<V> {
        self.clone().into_iter().collect()
    }
}

impl<F, V, R, A> IntoIterator for Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Creator<F, V>,
{
    type IntoIter = PoissonIter<F, V, R, A::Algo>;
    type Item = V;

    fn into_iter(self) -> Self::IntoIter {
        PoissonIter {
            rng: self.rng,
            algo: A::create(&self.poisson),
            poisson: self.poisson,
        }
    }
}

/// Iterator for generating poisson-disk distribution.
#[derive(Clone)]
pub struct PoissonIter<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Algorithm<F, V>,
{
    poisson: Builder<F, V>,
    rng: R,
    algo: A,
}

impl<F, V, R, A> Iterator for PoissonIter<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Algorithm<F, V>,
{
    type Item = V;

    fn next(&mut self) -> Option<Self::Item> {
        self.algo.next(&mut self.poisson, &mut self.rng)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<F, V, R, A> PoissonIter<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Algorithm<F, V>,
{
    /// Returns the radius of the generator.
    pub fn radius(&self) -> F {
        self.poisson.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson.poisson_type
    }

    /// Restricts the poisson algorithm with arbitary sample.
    pub fn restrict(&mut self, value: V) {
        self.algo.restrict(value);
    }

    /// Checks legality of sample for currrent distribution.
    pub fn stays_legal(&self, value: V) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}
<commit_msg>Added missing bounds on Vector blanket impl.<commit_after>//! # Poisson-disk distribution generation
//!
//! Generates distribution of points where:
//!
//! * For each point there is disk of certain radius which doesn't intersect
//! with any other disk of other points
//! * Samples fill the space uniformly
//!
//! # Examples
//!
//! ```
//! extern crate poisson;
//! use poisson::{Builder, Type, algorithm};
//!
//! extern crate rand;
//!
//! extern crate nalgebra as na;
//! type Vec2 = na::Vector2<f64>;
//!
//! fn main() {
//!     let poisson =
//!         Builder::<_, Vec2>::with_radius(0.1, Type::Normal)
//!             .build(rand::weak_rng(), algorithm::Ebeida);
//!     let samples = poisson.generate();
//!     println!("{:?}", samples);
//! }
//! ```
extern crate modulo;

extern crate sphere;

extern crate rand;
use rand::{Rand, Rng};

extern crate num_traits;
use num_traits::{NumCast, Zero};
use num_traits::Float as NumFloat;

extern crate alga;
use alga::general::AbstractField;
use alga::linear::{NormedSpace, FiniteDimVectorSpace};

#[macro_use]
extern crate lazy_static;

use std::marker::PhantomData;
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, Index, IndexMut};

use algorithm::{Creator, Algorithm};
use utils::math::calc_radius;

pub mod algorithm;
mod utils;

/// Describes what floats are.
pub trait Float:
    NumFloat +
    AbstractField +
    AddAssign +
    SubAssign +
    MulAssign +
    DivAssign +
    Rand
{
    /// Casts usize to float.
    fn cast(n: usize) -> Self {
        NumCast::from(n).expect("Casting usize to float should always succeed.")
    }
}
impl<T> Float for T where T: NumFloat + AbstractField + AddAssign + SubAssign + MulAssign + DivAssign + Rand
{}

/// Describes what vectors are.
pub trait Vector<F>:
    Zero +
    Rand +
    FiniteDimVectorSpace<Field=F> +
    NormedSpace<Field=F> +
    Index<usize> +
    IndexMut<usize> +
    Clone
      where F: Float,
{}
impl<T, F> Vector<F> for T
    where F: Float,
          T: Zero + Rand + FiniteDimVectorSpace<Field=F> + NormedSpace<Field=F> + Index<usize> + IndexMut<usize> + Clone,
{}

/// Enum for determining the type of poisson-disk distribution.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Type {
    /// Acts like there is void all around the space placing no restrictions to sides.
    Normal,
    /// Makes the space to wrap around on edges allowing tiling of poisson-disk distribution.
    /// This makes samples next to a edge restrict samples on opposite one.
    Perioditic,
}

impl Default for Type {
    fn default() -> Type {
        Type::Normal
    }
}

/// Builder for the generator.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Builder<F, V>
    where F: Float,
          V: Vector<F>,
{
    radius: F,
    poisson_type: Type,
    _marker: PhantomData<V>,
}

impl<V, F> Builder<F, V>
    where F: Float,
          V: Vector<F>,
{
    /// New Builder with type of distribution and radius specified.
    /// The radius should be ]0, √2 / 2]
    pub fn with_radius(radius: F, poisson_type: Type) -> Self {
        assert!(F::cast(0) < radius);
        assert!(radius <=
                NumCast::from(2f64.sqrt() / 2.).expect("Casting constant should always work."));
        Builder {
            radius: radius,
            poisson_type: poisson_type,
            _marker: PhantomData,
        }
    }

    /// New Builder with type of distribution and relative radius specified.
    /// The relative radius should be ]0, 1]
    pub fn with_relative_radius(relative: F, poisson_type: Type) -> Self {
        assert!(relative >= F::cast(0));
        assert!(relative <= F::cast(1));
        Builder {
            radius: relative *
                    NumCast::from(2f64.sqrt() / 2.).expect("Casting constant should always work."),
            poisson_type: poisson_type,
            _marker: PhantomData,
        }
    }

    /// New Builder with type of distribution, approximate amount of samples and relative radius specified.
    /// The amount of samples should be larger than 0.
    /// The relative radius should be [0, 1].
    /// For non-perioditic this is supported only for 2, 3 and 4 dimensional generation.
    pub fn with_samples(samples: usize, relative: F, poisson_type: Type) -> Self {
        Builder {
            radius: calc_radius::<F, V>(samples, relative, poisson_type),
            poisson_type: poisson_type,
            _marker: PhantomData,
        }
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> F {
        self.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson_type
    }

    /// Builds generator with random number generator and algorithm specified.
    pub fn build<R, A>(self, rng: R, _algo: A) -> Generator<F, V, R, A>
        where R: Rng,
              A: Creator<F, V>
    {
        Generator::new(self, rng)
    }
}

/// Generates poisson-disk distribution for [0, 1]² area.
#[derive(Clone, Debug)]
pub struct Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Creator<F, V>,
{
    poisson: Builder<F, V>,
    rng: R,
    _algo: PhantomData<A>,
}

impl<F, V, R, A> Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Creator<F, V>,
{
    fn new(poisson: Builder<F, V>, rng: R) -> Self {
        Generator {
            rng: rng,
            poisson: poisson,
            _algo: PhantomData,
        }
    }

    /// Sets the radius of the generator.
    pub fn set_radius(&mut self, radius: F) {
        assert!(F::cast(0) < radius);
        assert!(radius <=
                NumCast::from(2f64.sqrt() / 2.).expect("Casting constant should always work."));
        self.poisson.radius = radius;
    }

    /// Returns the radius of the generator.
    pub fn radius(&self) -> F {
        self.poisson.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson.poisson_type
    }
}

impl<F, V, R, A> Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng + Clone,
          A: Creator<F, V>,
{
    /// Generates Poisson-disk distribution.
    pub fn generate(&self) -> Vec<V> {
        self.clone().into_iter().collect()
    }
}

impl<F, V, R, A> IntoIterator for Generator<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Creator<F, V>,
{
    type IntoIter = PoissonIter<F, V, R, A::Algo>;
    type Item = V;

    fn into_iter(self) -> Self::IntoIter {
        PoissonIter {
            rng: self.rng,
            algo: A::create(&self.poisson),
            poisson: self.poisson,
        }
    }
}

/// Iterator for generating poisson-disk distribution.
#[derive(Clone)]
pub struct PoissonIter<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Algorithm<F, V>,
{
    poisson: Builder<F, V>,
    rng: R,
    algo: A,
}

impl<F, V, R, A> Iterator for PoissonIter<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Algorithm<F, V>,
{
    type Item = V;

    fn next(&mut self) -> Option<Self::Item> {
        self.algo.next(&mut self.poisson, &mut self.rng)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.algo.size_hint(&self.poisson)
    }
}

impl<F, V, R, A> PoissonIter<F, V, R, A>
    where F: Float,
          V: Vector<F>,
          R: Rng,
          A: Algorithm<F, V>,
{
    /// Returns the radius of the generator.
    pub fn radius(&self) -> F {
        self.poisson.radius
    }

    /// Returns the type of the generator.
    pub fn poisson_type(&self) -> Type {
        self.poisson.poisson_type
    }

    /// Restricts the poisson algorithm with arbitary sample.
    pub fn restrict(&mut self, value: V) {
        self.algo.restrict(value);
    }

    /// Checks legality of sample for currrent distribution.
    pub fn stays_legal(&self, value: V) -> bool {
        self.algo.stays_legal(&self.poisson, value)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

#[macro_use]
extern crate log;
extern crate time;
extern crate libc;
extern crate rand;
extern crate epoll;
extern crate errno;
extern crate openssl;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate simple_stream as ss;

use std::sync::Mutex;
use types::*;
use config::Config;

pub use ss::Stream;
pub use ss::{SRecv, CloneStream, StreamShutdown};

pub mod config;
pub mod types;

mod stats;
mod server;
mod resources;
mod workerthread;

/// Starts the server using the passed `config` options.
/// This is a blocking call for the life of the server.
pub fn begin<T>(config: Config, handler: Box<T>)
    where T: EventHandler + Send + Sync + 'static
{
    let mut data = Mutex::new(stats::Stats::new());
    stats::init(&mut data);
    server::begin(config, handler);
}
<commit_msg>Update re-exports<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

#[macro_use]
extern crate log;
extern crate time;
extern crate libc;
extern crate rand;
extern crate epoll;
extern crate errno;
extern crate openssl;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate simple_stream as ss;

use std::sync::Mutex;
use types::*;
use config::Config;

pub use ss::Stream;
pub use ss::{SSend, StreamShutdown};

pub mod config;
pub mod types;

mod stats;
mod server;
mod resources;
mod workerthread;

/// Starts the server using the passed `config` options.
/// This is a blocking call for the life of the server.
pub fn begin<T>(config: Config, handler: Box<T>)
    where T: EventHandler + Send + Sync + 'static
{
    let mut data = Mutex::new(stats::Stats::new());
    stats::init(&mut data);
    server::begin(config, handler);
}
<|endoftext|>


<commit_before>mod ffi;

pub struct SoundIo {
    context: *mut ffi::Struct_SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn channel_layout_builtin_count() -> i32 {
        let cnt = unsafe { ffi::soundio_channel_layout_builtin_count() };
        if cnt < 0 {
            panic!("Negative # of builtin channel layouts!")
        } else {
            cnt as i32
        }
    }

    pub fn connect(&self) -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self,
                           backend: ffi::Enum_SoundIoBackend)
                           -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt: i32 = unsafe { ffi::soundio_backend_count(self.context) };
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::Enum_SoundIoBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::Enum_SoundIoBackend::SoundIoBackendNone => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::Enum_SoundIoBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[test]
fn test_soundio() {
    let sio = SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.get_backend(0).is_some());
    assert!(sio.get_backend(-1).is_none());
    assert!(sio.connect().is_none());
    sio.disconnect();
    if sio.have_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa) {
        assert!(sio.connect_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa).is_none());
        sio.disconnect();
    }
    assert!(SoundIo::channel_layout_builtin_count() >= 0);
}

#[test]
fn test_enums() {
    assert_eq!("(no error)",
               format!("{}", ffi::Enum_SoundIoError::SoundIoErrorNone));
    assert_eq!("ALSA",
               format!("{}", ffi::Enum_SoundIoBackend::SoundIoBackendAlsa));
    assert_eq!("Front Left",
               format!("{}", ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft));
    assert_eq!(ffi::Enum_SoundIoChannelId::from("Front Left".to_string()),
               ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
    assert!(ffi::Enum_SoundIoChannelId::from("SomeInvalidBoredom".to_string()) !=
            ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
}
<commit_msg>Cast explicitly to `i32` (even it's equal to `c_int`)<commit_after>mod ffi;

use std::os::raw::c_int;

pub struct SoundIo {
    context: *mut ffi::Struct_SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn channel_layout_builtin_count() -> i32 {
        let cnt = unsafe { ffi::soundio_channel_layout_builtin_count() };
        if cnt < 0 {
            panic!("Negative # of builtin channel layouts!")
        } else {
            cnt as i32
        }
    }

    pub fn connect(&self) -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self,
                           backend: ffi::Enum_SoundIoBackend)
                           -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt = unsafe { ffi::soundio_backend_count(self.context) } as i32;
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::Enum_SoundIoBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::Enum_SoundIoBackend::SoundIoBackendNone => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::Enum_SoundIoBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[test]
fn test_soundio() {
    let sio = SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.get_backend(0).is_some());
    assert!(sio.get_backend(-1).is_none());
    assert!(sio.connect().is_none());
    sio.disconnect();
    if sio.have_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa) {
        assert!(sio.connect_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa).is_none());
        sio.disconnect();
    }
    assert!(SoundIo::channel_layout_builtin_count() >= 0);
}

#[test]
fn test_enums() {
    assert_eq!("(no error)",
               format!("{}", ffi::Enum_SoundIoError::SoundIoErrorNone));
    assert_eq!("ALSA",
               format!("{}", ffi::Enum_SoundIoBackend::SoundIoBackendAlsa));
    assert_eq!("Front Left",
               format!("{}", ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft));
    assert_eq!(ffi::Enum_SoundIoChannelId::from("Front Left".to_string()),
               ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
    assert!(ffi::Enum_SoundIoChannelId::from("SomeInvalidBoredom".to_string()) !=
            ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
}
<|endoftext|>


<commit_before>use std::net::{TcpStream, ToSocketAddrs};
use std::io::{Read, Write};
use std::io;
use std::time::Duration;

pub enum NeedsAck {
    Yes,
    No,
}

#[derive(Copy, Clone, PartialEq)]
pub enum State {
    Disconnected,
    Connected,
    SendingData,
    WaitingForData,
    Close,
}

pub struct GdbRemote {
    stream: Option<TcpStream>,
    temp_string: String,
    needs_ack: NeedsAck,
    hex_to_byte: [u8; 256],
}

pub struct Memory {
    pub address: u64,
    pub data: Vec<u8>
}

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

const PACKET_SIZE: usize = 1024;
static HEX_CHARS: &'static [u8; 16] = b"0123456789abcdef";

#[inline]
fn calc_checksum(data: &[u8]) -> u8 {
    let mut checksum = 0u32;
    for i in data {
        checksum += *i as u32;
    }
    (checksum & 0xff) as u8
}

#[inline]
fn get_checksum(checksum: u8) -> (u8, u8) {
    (HEX_CHARS[((checksum >> 4) & 0xf) as usize],
     HEX_CHARS[(checksum & 0xf) as usize])
}

fn from_hex(ch: u8) -> u8 {
    if (ch >= b'a') && (ch <= b'f') {
        return ch - b'a' + 10;
    }

    if (ch >= b'0') && (ch <= b'9') {
        return ch - b'0';
    }

    if (ch >= b'A') && (ch <= b'F') {
        return ch - b'A' + 10;
    }

    0
}

fn build_hex_to_byte_table() -> [u8; 256] {
    let mut table = [0; 256];
    for i in 0..256 {
        table[i] = from_hex(i as u8)
    }
    table
}

fn from_pair_hex(data: (u8, u8)) -> u8 {
    let t0 = from_hex(data.0);
    let t1 = from_hex(data.1);
    (t0 << 4) | t1
}

impl GdbRemote {
    pub fn new() -> GdbRemote {
        GdbRemote {
            needs_ack: NeedsAck::Yes,
            temp_string: String::with_capacity(PACKET_SIZE + 4), // + 4 for header and checksum
            stream: None,
            hex_to_byte: build_hex_to_byte_table(),
        }
    }

    pub fn connect<A: ToSocketAddrs>(&mut self, addr: A) -> io::Result<()> {
        let stream = try!(TcpStream::connect(addr));
        // 2 sec of time-out to make sure we never gets infitite blocked
        try!(stream.set_read_timeout(Some(Duration::from_secs(2))));
        self.stream = Some(stream);
        Ok(())
    }

    pub fn build_processed_string(dest: &mut String, source: &str) {
        let checksum = calc_checksum(source.as_bytes());
        let csum = get_checksum(checksum);

        dest.clear();
        dest.push('$');
        dest.push_str(source);
        dest.push('#');
        dest.push(csum.0 as char);
        dest.push(csum.1 as char);
    }

    pub fn send_internal(&mut self) -> io::Result<()> {
        if let Some(ref mut stream) = self.stream {
            stream.write_all(self.temp_string.as_bytes())
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "No connection with a server."))
        }
    }

    pub fn send_command(&mut self, data: &str) -> io::Result<()> {
        Self::build_processed_string(&mut self.temp_string, data);
        self.send_internal()
    }

    fn handle_send_ack(stream: &mut TcpStream, resend_data: &str, dest: &mut [u8]) -> io::Result<usize> {
        loop {
            let mut v = [0; 1];
            try!(stream.read(&mut v));

            match v[0] {
                b'+' => return stream.read(dest),
                b'-' => try!(stream.write_all(resend_data.as_bytes())),
                _ => {
                    return Err(io::Error::new(io::ErrorKind::Other, "Illegal reply from server."))
                }
            }
        }
    }

    pub fn read_reply(&mut self, dest: &mut [u8]) -> io::Result<usize> {
        if let Some(ref mut stream) = self.stream {
            match self.needs_ack {
                NeedsAck::Yes => Self::handle_send_ack(stream, &self.temp_string.clone(), dest),
                NeedsAck::No => stream.read(dest),
            }
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "No connection with a server."))
        }
    }

    fn clone_slice(dst: &mut [u8], src: &[u8]) {
        for (d, s) in dst.iter_mut().zip(src.iter()) {
            *d = *s;
        }
    }

    fn validate_checksum(data: &[u8], len: usize) -> io::Result<usize> {
        // - 3 to skip $xx in the end
        let data_len = len;
        let checksum = calc_checksum(&data[1..len - 3]);
        let data_check = from_pair_hex((data[data_len - 2], data[data_len - 1]));

        if data_check == checksum {
            Ok((data_len))
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "Checksum missmatch for data"))
        }
    }

    #[no_mangle]
    pub fn convert_hex_data_to_binary(&self, dest: &mut [u8], src: &[u8], _len: usize) {
        for (d, s) in dest.iter_mut().zip(src.chunks(2)) {
            let v0 = s[0] as usize;
            let v1 = s[1] as usize;
            *d = (self.hex_to_byte[v0] << 4) | self.hex_to_byte[v1];
        }
    }

    pub fn send_command_wait_reply_raw(&mut self, res: &mut [u8], command: &str) -> io::Result<usize> {
        let mut temp_buffer = [0; PACKET_SIZE];
        try!(self.send_command(command));
        let len = try!(self.read_reply(&mut temp_buffer));
        try!(Self::validate_checksum(&temp_buffer, len));
        Self::clone_slice(res, &temp_buffer[1..len - 3]);
        Ok((len - 4))
    }

    pub fn get_supported(&mut self, res: &mut [u8]) -> io::Result<usize> {
        self.send_command_wait_reply_raw(res, "qSupported")
    }

    pub fn step_sync(&mut self, res: &mut [u8]) -> io::Result<usize> {
        self.send_command_wait_reply_raw(res, "s")
    }

    pub fn get_registers(&mut self, res: &mut [u8]) -> io::Result<usize> {
        let mut temp_buffer = [0; PACKET_SIZE];
        let len = try!(self.send_command_wait_reply_raw(&mut temp_buffer, "g"));
        let t = String::from_utf8_lossy(&temp_buffer).into_owned();
        println!("get_regs {} len {}", t, len);
        self.convert_hex_data_to_binary(res, &temp_buffer, len);
        Ok((len / 2))
    }

    /*
    pub fn get_memory_sync(&mut self, address: u64, size: u64) -> io::Result<usize> {
        let mem_req = format!("m{:x},{:x}", address, size);

        if let Some(data) = self.send_command_sync(&mem_req) {
            let mut memory = Vec::with_capacity((data.len() - 2) / 2);
            let mut index = 1;

            for _ in 0..((data.len() - 2) / 2) {
                let v0 = data[index + 0];
                let v1 = data[index + 1];
                let v = (Self::from_hex(v0) << 4) | (Self::from_hex(v1));
                memory.push(v);
                index += 2;
            }

            Some(Memory {
                address: address as u64,
                data: memory,
            })
        } else {
            None
        }
    }
    */
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::net::{TcpStream, TcpListener};
    use std::sync::{Arc, Mutex};
    use std::io::{Read, Write};
    use std::time::Duration;

    //const NOT_STARTED: u32 = 0;
    const STARTED: u32 = 1;
    const READ_DATA: u32 = 2;
    const SHOULD_QUIT: u32 = 3;
    //const REPLY_SUPPORT: u32 = 2;

    #[test]
    fn test_checksum_calc() {
        let data: [u8; 8] = [32, 32, 32, 32, 64, 64, 64, 64];
        assert_eq!(::calc_checksum(&data), 128);
    }

    #[test]
    fn test_process_string() {
        let mut dest = String::new();
        GdbRemote::build_processed_string(&mut dest, "f");
        assert_eq!(dest, "$f#66");
    }

    fn check_mutex_complete(mutex: &Arc<Mutex<u32>>) -> bool {
        let data = mutex.lock().unwrap();
        if *data != 0 { true } else { false }
    }

    fn update_mutex(mutex: &Arc<Mutex<u32>>, value: u32) {
        let mut data = mutex.lock().unwrap();
        *data = value
    }

    fn get_mutex_value(mutex: &Arc<Mutex<u32>>) -> u32 {
        *mutex.lock().unwrap()
    }

    fn wait_for_thread_init(mutex: &Arc<Mutex<u32>>) {
        loop {
            if check_mutex_complete(mutex) {
                return;
            }

            thread::sleep(Duration::from_millis(1));
        }
    }

    fn setup_listener(server_lock: &Arc<Mutex<u32>>, state: u32, port: u16) {
        let listener = TcpListener::bind(("127.0.0.1", port)).unwrap();
        update_mutex(&server_lock, state as u32);

        loop {
            for stream in listener.incoming() {
                match stream {
                    Ok(stream) => {
                        server(stream, server_lock);
                        return;
                    }
                    _ => (),
                }
            }
        }
    }

    fn get_string_from_buf(buffer: &[u8], size: usize) -> String {
        String::from_utf8_lossy(&buffer[0..size]).into_owned()
    }

    fn get_string_from_buf_trim(buffer: &[u8], size: usize) -> String {
        String::from_utf8_lossy(&buffer[1..size-3]).into_owned()
    }

    fn server(mut stream: TcpStream, state: &Arc<Mutex<u32>>) {
        let mut buffer = [0; 1024];
        let value = get_mutex_value(state);

        if value == STARTED {
            return;
        }

        let len = stream.read(&mut buffer).unwrap();
        let data = get_string_from_buf_trim(&buffer, len);

        println!("data {}", data);

        match data.as_ref() {
            "qSupported" => {
                let mut dest = String::new();
                GdbRemote::build_processed_string(&mut dest, "PacketSize=1fff");
                stream.write(b"+").unwrap(); // reply that we got the package
                stream.write_all(dest.as_bytes()).unwrap();
            }

            "g" => {
                let mut dest = String::new();
                GdbRemote::build_processed_string(&mut dest, "1122aa");
                stream.write(b"+").unwrap(); // reply that we got the package
                stream.write_all(dest.as_bytes()).unwrap();
            }
            _ => (),
        }

        loop {
            if get_mutex_value(state) == SHOULD_QUIT {
                break;
            }

            thread::sleep(Duration::from_millis(10));
        }
    }

    #[test]
    fn test_connect() {
        let port = 6860u16;
        let lock = Arc::new(Mutex::new(0));
        let thread_lock = lock.clone();

        thread::spawn(move || { setup_listener(&thread_lock, STARTED, port) });
        wait_for_thread_init(&lock);

        let mut gdb = GdbRemote::new();
        gdb.connect(("127.0.0.1", port)).unwrap();
    }

    #[test]
    fn test_qsupported() {
        let mut res = [0; 1024];
        let port = 6861u16;
        let lock = Arc::new(Mutex::new(0));
        let thread_lock = lock.clone();

        thread::spawn(move || { setup_listener(&thread_lock, READ_DATA, port) });
        wait_for_thread_init(&lock);

        let mut gdb = GdbRemote::new();
        gdb.connect(("127.0.0.1", port)).unwrap();
        let size = gdb.get_supported(&mut res).unwrap();

        println!("{:x}", res[0]);

        let supported = get_string_from_buf(&res, size);

        assert_eq!(supported, "PacketSize=1fff");

        update_mutex(&lock, SHOULD_QUIT);
    }

    #[test]
    fn test_registers() {
        let mut res = [0; 1024];
        let port = 6862u16;
        let lock = Arc::new(Mutex::new(0));
        let thread_lock = lock.clone();

        thread::spawn(move || { setup_listener(&thread_lock, READ_DATA, port) });
        wait_for_thread_init(&lock);

        let mut gdb = GdbRemote::new();
        gdb.connect(("127.0.0.1", port)).unwrap();
        let size = gdb.get_registers(&mut res).unwrap();

        assert_eq!(res[0], 0x11);
        assert_eq!(res[1], 0x22);
        assert_eq!(res[2], 0xaa);
        assert_eq!(size, 3);

        update_mutex(&lock, SHOULD_QUIT);
    }
}

<commit_msg>Added get_memory code<commit_after>use std::net::{TcpStream, ToSocketAddrs};
use std::io::{Read, Write};
use std::io;
use std::time::Duration;

pub enum NeedsAck {
    Yes,
    No,
}

#[derive(Copy, Clone, PartialEq)]
pub enum State {
    Disconnected,
    Connected,
    SendingData,
    WaitingForData,
    Close,
}

pub struct GdbRemote {
    stream: Option<TcpStream>,
    temp_string: String,
    needs_ack: NeedsAck,
    hex_to_byte: [u8; 256],
}

pub struct Memory {
    pub address: u64,
    pub data: Vec<u8>
}

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

const PACKET_SIZE: usize = 1024;
static HEX_CHARS: &'static [u8; 16] = b"0123456789abcdef";

#[inline]
fn calc_checksum(data: &[u8]) -> u8 {
    let mut checksum = 0u32;
    for i in data {
        checksum += *i as u32;
    }
    (checksum & 0xff) as u8
}

#[inline]
fn get_checksum(checksum: u8) -> (u8, u8) {
    (HEX_CHARS[((checksum >> 4) & 0xf) as usize],
     HEX_CHARS[(checksum & 0xf) as usize])
}

fn from_hex(ch: u8) -> u8 {
    if (ch >= b'a') && (ch <= b'f') {
        return ch - b'a' + 10;
    }

    if (ch >= b'0') && (ch <= b'9') {
        return ch - b'0';
    }

    if (ch >= b'A') && (ch <= b'F') {
        return ch - b'A' + 10;
    }

    0
}

fn build_hex_to_byte_table() -> [u8; 256] {
    let mut table = [0; 256];
    for (i, item) in table.iter_mut().enumerate().take(256) {
        *item = from_hex(i as u8)
    }
    table
}

fn from_pair_hex(data: (u8, u8)) -> u8 {
    let t0 = from_hex(data.0);
    let t1 = from_hex(data.1);
    (t0 << 4) | t1
}

impl GdbRemote {
    pub fn new() -> GdbRemote {
        GdbRemote {
            needs_ack: NeedsAck::Yes,
            temp_string: String::with_capacity(PACKET_SIZE + 4), // + 4 for header and checksum
            stream: None,
            hex_to_byte: build_hex_to_byte_table(),
        }
    }

    pub fn connect<A: ToSocketAddrs>(&mut self, addr: A) -> io::Result<()> {
        let stream = try!(TcpStream::connect(addr));
        // 2 sec of time-out to make sure we never gets infitite blocked
        try!(stream.set_read_timeout(Some(Duration::from_secs(2))));
        self.stream = Some(stream);
        Ok(())
    }

    pub fn build_processed_string(dest: &mut String, source: &str) {
        let checksum = calc_checksum(source.as_bytes());
        let csum = get_checksum(checksum);

        dest.clear();
        dest.push('$');
        dest.push_str(source);
        dest.push('#');
        dest.push(csum.0 as char);
        dest.push(csum.1 as char);
    }

    pub fn send_internal(&mut self) -> io::Result<()> {
        if let Some(ref mut stream) = self.stream {
            stream.write_all(self.temp_string.as_bytes())
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "No connection with a server."))
        }
    }

    pub fn send_command(&mut self, data: &str) -> io::Result<()> {
        Self::build_processed_string(&mut self.temp_string, data);
        self.send_internal()
    }

    fn handle_send_ack(stream: &mut TcpStream, resend_data: &str, dest: &mut [u8]) -> io::Result<usize> {
        loop {
            let mut v = [0; 1];
            try!(stream.read(&mut v));

            match v[0] {
                b'+' => return stream.read(dest),
                b'-' => try!(stream.write_all(resend_data.as_bytes())),
                _ => {
                    return Err(io::Error::new(io::ErrorKind::Other, "Illegal reply from server."))
                }
            }
        }
    }

    pub fn read_reply(&mut self, dest: &mut [u8]) -> io::Result<usize> {
        if let Some(ref mut stream) = self.stream {
            match self.needs_ack {
                NeedsAck::Yes => Self::handle_send_ack(stream, &self.temp_string.clone(), dest),
                NeedsAck::No => stream.read(dest),
            }
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "No connection with a server."))
        }
    }

    fn clone_slice(dst: &mut [u8], src: &[u8]) {
        for (d, s) in dst.iter_mut().zip(src.iter()) {
            *d = *s;
        }
    }

    fn validate_checksum(data: &[u8], len: usize) -> io::Result<usize> {
        // - 3 to skip $xx in the end
        let data_len = len;
        let checksum = calc_checksum(&data[1..len - 3]);
        let data_check = from_pair_hex((data[data_len - 2], data[data_len - 1]));

        if data_check == checksum {
            Ok((data_len))
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "Checksum missmatch for data"))
        }
    }

    #[no_mangle]
    pub fn convert_hex_data_to_binary(&self, dest: &mut [u8], src: &[u8]) {
        for (d, s) in dest.iter_mut().zip(src.chunks(2)) {
            let v0 = s[0] as usize;
            let v1 = s[1] as usize;
            *d = (self.hex_to_byte[v0] << 4) | self.hex_to_byte[v1];
        }
    }

    pub fn send_command_wait_reply_raw(&mut self, res: &mut [u8], command: &str) -> io::Result<usize> {
        let mut temp_buffer = [0; PACKET_SIZE];
        try!(self.send_command(command));
        let len = try!(self.read_reply(&mut temp_buffer));
        try!(Self::validate_checksum(&temp_buffer, len));
        Self::clone_slice(res, &temp_buffer[1..len - 3]);
        Ok((len - 4))
    }

    pub fn get_supported(&mut self, res: &mut [u8]) -> io::Result<usize> {
        self.send_command_wait_reply_raw(res, "qSupported")
    }

    pub fn step_sync(&mut self, res: &mut [u8]) -> io::Result<usize> {
        self.send_command_wait_reply_raw(res, "s")
    }

    pub fn get_registers(&mut self, res: &mut [u8]) -> io::Result<usize> {
        let mut temp_buffer = [0; PACKET_SIZE];
        let len = try!(self.send_command_wait_reply_raw(&mut temp_buffer, "g"));
        self.convert_hex_data_to_binary(res, &temp_buffer[0..len]);
        Ok((len / 2))
    }

    pub fn get_memory(&mut self, dest: &mut Vec<u8>, address: u32, size: u32) -> io::Result<usize> {
        let mut temp_buffer = [0; PACKET_SIZE];
        let mut temp_unpack = [0; PACKET_SIZE/2];

        if size == 0 {
            return Ok((0));
        }

        dest.clear();

        // Text hexdata and 4 bytes of header bytes gives this max amount of requested data / loop
        let size_per_loop = ((PACKET_SIZE - 4) / 2) as u32;
        let mut data_size = size;
        let mut addr = address;
        let mut trans_size = 0u32;

        loop {
            let current_size = if data_size < size_per_loop { data_size } else { size_per_loop };

            // TODO: This allocates memory, would be nice to format to existing string.
            let mem_req = format!("m{:x},{:x}", addr, current_size);

            let len = try!(self.send_command_wait_reply_raw(&mut temp_buffer, &mem_req));

            if temp_buffer[0] == b'E' {
                // Ok, something went wrong here. If we have already got some data we just
                // return what we got (it might be the case that some of the data was ok
                // to read but the other data wasn't (un-mapped memory for example)
                if trans_size == 0 {
                    return Err(io::Error::new(io::ErrorKind::Other, "Unable to read memory"))
                } else {
                    return Ok(trans_size as usize);
                }
            }

            self.convert_hex_data_to_binary(&mut temp_unpack, &temp_buffer[0..len]);
            dest.extend_from_slice(&temp_unpack[0..len/2]);

            // Bump size and prepare for next chunk

            data_size -= current_size;
            addr += current_size;
            trans_size += current_size;

            if data_size == 0 {
                break;
            }
        }

        Ok(trans_size as usize)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::net::{TcpStream, TcpListener};
    use std::sync::{Arc, Mutex};
    use std::io::{Read, Write};
    use std::time::Duration;

    //const NOT_STARTED: u32 = 0;
    const STARTED: u32 = 1;
    const READ_DATA: u32 = 2;
    const SHOULD_QUIT: u32 = 3;
    //const REPLY_SUPPORT: u32 = 2;

    #[test]
    fn test_checksum_calc() {
        let data: [u8; 8] = [32, 32, 32, 32, 64, 64, 64, 64];
        assert_eq!(::calc_checksum(&data), 128);
    }

    #[test]
    fn test_process_string() {
        let mut dest = String::new();
        GdbRemote::build_processed_string(&mut dest, "f");
        assert_eq!(dest, "$f#66");
    }

    fn check_mutex_complete(mutex: &Arc<Mutex<u32>>) -> bool {
        let data = mutex.lock().unwrap();
        if *data != 0 { true } else { false }
    }

    fn update_mutex(mutex: &Arc<Mutex<u32>>, value: u32) {
        let mut data = mutex.lock().unwrap();
        *data = value
    }

    fn get_mutex_value(mutex: &Arc<Mutex<u32>>) -> u32 {
        *mutex.lock().unwrap()
    }

    fn wait_for_thread_init(mutex: &Arc<Mutex<u32>>) {
        loop {
            if check_mutex_complete(mutex) {
                return;
            }

            thread::sleep(Duration::from_millis(1));
        }
    }

    fn setup_listener(server_lock: &Arc<Mutex<u32>>, state: u32, port: u16) {
        let listener = TcpListener::bind(("127.0.0.1", port)).unwrap();
        update_mutex(&server_lock, state as u32);

        loop {
            for stream in listener.incoming() {
                match stream {
                    Ok(stream) => {
                        server(stream, server_lock);
                        return;
                    }
                    _ => (),
                }
            }
        }
    }

    fn get_string_from_buf(buffer: &[u8], size: usize) -> String {
        String::from_utf8_lossy(&buffer[0..size]).into_owned()
    }

    fn get_string_from_buf_trim(buffer: &[u8], size: usize) -> String {
        String::from_utf8_lossy(&buffer[1..size-3]).into_owned()
    }

    fn server(mut stream: TcpStream, state: &Arc<Mutex<u32>>) {
        let mut buffer = [0; 1024];
        let value = get_mutex_value(state);

        if value == STARTED {
            return;
        }

        let len = stream.read(&mut buffer).unwrap();
        let data = get_string_from_buf_trim(&buffer, len);

        //println!("data {}", data);

        match data.as_ref() {
            "qSupported" => {
                let mut dest = String::new();
                GdbRemote::build_processed_string(&mut dest, "PacketSize=1fff");
                stream.write(b"+").unwrap(); // reply that we got the package
                stream.write_all(dest.as_bytes()).unwrap();
            }

            "g" => {
                let mut dest = String::new();
                GdbRemote::build_processed_string(&mut dest, "1122aa");
                stream.write(b"+").unwrap(); // reply that we got the package
                stream.write_all(dest.as_bytes()).unwrap();
            }
            _ => (),
        }

        loop {
            if get_mutex_value(state) == SHOULD_QUIT {
                break;
            }

            thread::sleep(Duration::from_millis(10));
        }
    }

    #[test]
    fn test_connect() {
        let port = 6860u16;
        let lock = Arc::new(Mutex::new(0));
        let thread_lock = lock.clone();

        thread::spawn(move || { setup_listener(&thread_lock, STARTED, port) });
        wait_for_thread_init(&lock);

        let mut gdb = GdbRemote::new();
        gdb.connect(("127.0.0.1", port)).unwrap();
    }

    #[test]
    fn test_qsupported() {
        let mut res = [0; 1024];
        let port = 6861u16;
        let lock = Arc::new(Mutex::new(0));
        let thread_lock = lock.clone();

        thread::spawn(move || { setup_listener(&thread_lock, READ_DATA, port) });
        wait_for_thread_init(&lock);

        let mut gdb = GdbRemote::new();
        gdb.connect(("127.0.0.1", port)).unwrap();
        let size = gdb.get_supported(&mut res).unwrap();

        println!("{:x}", res[0]);

        let supported = get_string_from_buf(&res, size);

        assert_eq!(supported, "PacketSize=1fff");

        update_mutex(&lock, SHOULD_QUIT);
    }

    #[test]
    fn test_registers() {
        let mut res = [0; 1024];
        let port = 6862u16;
        let lock = Arc::new(Mutex::new(0));
        let thread_lock = lock.clone();

        thread::spawn(move || { setup_listener(&thread_lock, READ_DATA, port) });
        wait_for_thread_init(&lock);

        let mut gdb = GdbRemote::new();
        gdb.connect(("127.0.0.1", port)).unwrap();
        let size = gdb.get_registers(&mut res).unwrap();

        assert_eq!(res[0], 0x11);
        assert_eq!(res[1], 0x22);
        assert_eq!(res[2], 0xaa);
        assert_eq!(size, 3);

        update_mutex(&lock, SHOULD_QUIT);
    }
}

<|endoftext|>


<commit_before>#![feature(core)]
extern crate biterator;
extern crate itertools;
#[cfg(test)] extern crate rand;

pub mod crockford_base32;
pub mod hashid_like;
<commit_msg>Updates for rust-nightly<commit_after>#![feature(peekable_is_empty)]
extern crate biterator;
extern crate itertools;
#[cfg(test)] extern crate rand;

pub mod crockford_base32;
pub mod hashid_like;
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<commit_msg>Allow unstable features during alpha<commit_after>#![feature(core, collections, io, path)]

extern crate tcod;

pub mod engine;
pub mod gui;
pub mod util;
<|endoftext|>


<commit_before>#![feature(unsafe_destructor, if_let)]
extern crate libc;

pub use udev::Udev;
pub use hwdb::{
    Hwdb,
    HwdbQuery
};
pub use device::{
    Device,
    Devnum,
    DeviceType,
};
pub use enumerator::Enumerator;
pub use monitor::Monitor;

mod libudev_c;
mod udev;
mod hwdb;
mod util;
mod device;
mod enumerator;
mod monitor;
mod iterator;
<commit_msg>Add simple test case.<commit_after>#![feature(unsafe_destructor, if_let)]
extern crate libc;

pub use udev::Udev;
pub use hwdb::{
    Hwdb,
    HwdbQuery
};
pub use device::{
    Device,
    Devnum,
    DeviceType,
};
pub use enumerator::Enumerator;
pub use monitor::Monitor;

mod libudev_c;
mod udev;
mod hwdb;
mod util;
mod device;
mod enumerator;
mod monitor;
mod iterator;

#[test]
fn test_ttys() {
    let udev = Udev::new();
    let mut vec = Vec::with_capacity(64);
    let mut found_tty = false;
    for dev in udev.enumerator().match_subsystem("tty").scan_devices().iter() {
        assert!(dev.subsystem().unwrap() == "tty");
        if dev.sysname().starts_with("tty") {
            match dev.sysnum() {
                Some(num) => vec.push(num),
                None => {
                    assert!(!found_tty);
                    found_tty = true;
                }
            }
        }
    }

    vec.sort();
    assert!(vec.into_iter().zip(range(0u64, 64u64)).all(|(i, j)| i == j));
}

<|endoftext|>


<commit_before>#![feature(custom_derive)]

extern crate rustc_serialize;
pub mod cypher;
<commit_msg>Remove unused feature<commit_after>extern crate rustc_serialize;
pub mod cypher;
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{digit, line_ending};
use nom::IResult::Done;
use nom::{space, anychar, crlf, multispace};

use std::str::FromStr;
use std::collections::HashMap;

#[derive(Debug)]
#[repr(C)]
pub struct Osu<'a> {
    version: u32,
    general: General<'a>,
}

#[derive(Debug, PartialEq, Default)]
struct General<'a> {
    audio_filename: &'a str,
    audio_lead_in:  u32,
    preview_time:   u32,
    countdown:      bool,
    sample_set:     &'a str,
    stack_leniency: f32,
    mode:           u32,
    letterboxin_breaks: bool,
    widescreen_storyboard: bool,
}

impl<'a> General<'a> {
    pub fn new<'b>(pairs: Vec<(&'b str, &'b str)>) -> General<'a> {
        let mut map = HashMap::new();
        for (ref key, ref val) in pairs.clone() {
            map.insert(key.to_owned(), val.to_owned());
        }
        General{
            audio_filename: map.get("audio_filename").unwrap(),
            ..Default::default()
        }
    }
}

#[derive(Debug, Default)]
struct Editor {
    asdf: u32,
}

named_args!(value<'a>(key: &'a str)<&'a [u8]>,
    do_parse!(
           opt!(multispace)
        >> tag_s!(key)
        >> opt!(space)
        >> char!(':')
        >> opt!(space)
        >> val: take_until_s!("\r\n")
        >> opt!(multispace)
        >> (val)
             )
    );

named!(key_value_pair<&str, (&str, &str)>,
    do_parse!(
                opt!(multispace)
        >> key: take_until_s!(":")
        >> val: take_until_s!("\r\n")
        >> opt!(multispace)
        >> (key, val)
    )
);

named!(section_general<&str, General>,
        do_parse!(
              opt!(multispace)
           >> tag_s!("[General]")
           >> opt!(multispace)
           >> pairs: many1!(key_value_pair)
           /*
        >> values: permutation!(
            apply!(value, "AudioFilename"),
            map_res!(apply!(value, "AudioLeadIn"), FromStr::from_str),
            map_res!(apply!(value, "PreviewTime"), FromStr::from_str),
            map_res!(apply!(value, "Countdown"), FromStr::from_str),
            apply!(value, "SampleSet"),
            map_res!(apply!(value, "StackLeniency"), FromStr::from_str),
            map_res!(apply!(value, "Mode"), FromStr::from_str),
            map_res!(apply!(value, "LetterboxInBreaks"), FromStr::from_str),
            map_res!(apply!(value, "WidescreenStoryboard"), FromStr::from_str),
            )
            */
        >> (General::new(pairs))
            /*
        >> (General {
            /*
            audio_filename: values.0,
            audio_lead_in: values.1,
            preview_time: values.2,
            countdown: values.3,
            sample_set: values.4,
            stack_leniency: values.5,
            mode: values.6,
            letterboxin_breaks: values.7,
            widescreen_storyboard: values.8,
            */
            ..Default::default()
            })
            */
          )
        );

named!(section_editor<&str, Editor>,
        do_parse!(
           tag_s!("[editor]")
          >> (Editor {..Default::default()})
          )
        );

named!(parse_osu<&str, Osu>,
    do_parse!(
                    tag_s!("osu file format v")
    >>  version:    map_res!(digit, FromStr::from_str)
    >>              line_ending
    >>  sections:   permutation!(call!(section_general), call!(line_ending))
    >>  (Osu {
        version: version,
        general: sections.0,
        })
    )
);

#[no_mangle]
pub extern "C" fn parse_osu_file<'a>() -> *const Osu<'a> {
    let input = include_str!("../test.osu");
    let res = parse_osu(input);
    match res {
        Done(_, x) => return &x,
        _ => return 0 as *const Osu,
    }
}

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

    #[test]
    fn it_works() {
        let input = include_str!("../test.osu");
        let res = parse_osu(input);
        if let Done(_, osu) = res {
            println!("{:?}", osu);
        }
        else {
            println!("{:?}", res);
            assert!(false);
        }
    }
}
<commit_msg>correct lifetime<commit_after>#[macro_use]
extern crate nom;

use nom::{digit, line_ending};
use nom::IResult::Done;
use nom::{space, multispace};

use std::str::FromStr;
use std::collections::HashMap;

#[derive(Debug)]
#[repr(C)]
pub struct Osu<'a> {
    version: u32,
    general: General<'a>,
}

#[derive(Debug, PartialEq, Default)]
struct General<'a> {
    audio_filename: &'a str,
    audio_lead_in:  u32,
    preview_time:   u32,
    countdown:      bool,
    sample_set:     &'a str,
    stack_leniency: f32,
    mode:           u32,
    letterboxin_breaks: bool,
    widescreen_storyboard: bool,
}

impl<'a> General<'a> {
    pub fn new(pairs: Vec<(&'a str, &'a str)>) -> General<'a> {
        let mut map = HashMap::new();
        for (ref key, ref val) in pairs {
            map.insert(key.to_owned(), val.to_owned());
        }
        let unwrap_get = |x| map.get(x).unwrap();
        let unwrap_from_str = |x| FromStr::from_str(unwrap_get(x)).unwrap();
        General{
            audio_filename: unwrap_get("AudioFilename"),
            audio_lead_in: unwrap_from_str("AudioLeadIn"),
            mode: unwrap_from_str("Mode"),
            ..Default::default()
        }
    }
}

#[derive(Debug, PartialEq, Default)]
struct Editor {
    asdf: u32,
}

named!(key_value_pair<&str, (&str, &str)>,
    do_parse!(
           key: take_until_and_consume_s!(":")
        >> opt!(multispace)
        >> val: take_until_and_consume_s!("\r\n")
        >> (key, val)
    )
);

named!(section_general<&str, General>,
        do_parse!(
                                tag_s!("[General]")
           >>                   opt!(multispace)
           >> pairs_with_end:   many_till!(key_value_pair, line_ending)
           >> (General::new(pairs_with_end.0))
          )
        );

named!(section_editor<&str, Editor>,
        do_parse!(
                                tag_s!("[Editor]")
           >>                   opt!(multispace)
           >> pairs_with_end:   many_till!(key_value_pair, line_ending)
           >> (Editor {..Default::default()})
          )
        );

named!(parse_osu<&str, Osu>,
    do_parse!(
                    tag_s!("osu file format v")
    >>  version:    map_res!(digit, FromStr::from_str)
    >>              line_ending
    >>              opt!(multispace)
    >>  sections:   permutation!(call!(section_general), call!(section_editor))
    >>  (Osu {
        version: version,
        general: sections.0,
        })
    )
);

#[no_mangle]
pub extern "C" fn parse_osu_file<'a>() -> *const Osu<'a> {
    let input = include_str!("../test.osu");
    let res = parse_osu(input);
    match res {
        Done(_, x) => return &x,
        _ => return 0 as *const Osu,
    }
}

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

    #[test]
    fn it_works() {
        let input = include_str!("../test.osu");
        let res = parse_osu(input);
        if let Done(_, osu) = res {
            println!("{:?}", osu);
        }
        else {
            println!("{:?}", res);
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

// Needed by pest
#![recursion_limit = "300"]

#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![cfg_attr(feature = "dev", allow(block_in_if_condition_stmt, linkedlist))]

extern crate serde;
extern crate serde_json;
extern crate glob;
#[macro_use] extern crate pest;
#[macro_use] extern crate quick_error;
extern crate slug;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate url;
extern crate humansize;

mod errors;
#[macro_use] mod macros;
mod parser;
mod context;
mod render;
mod template;
mod tera;
mod filters;
mod testers;
mod utils;

// Library exports.

// Template is meant to be used internally only but is exported for test/bench.
#[doc(hidden)] pub use template::Template;
pub use context::Context;
pub use tera::Tera;
pub use errors::{TeraResult, TeraError};
pub use utils::{escape_html};
<commit_msg>Export Value and to_value as part of Tera<commit_after>#![allow(dead_code)]

// Needed by pest
#![recursion_limit = "300"]

#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![cfg_attr(feature = "dev", allow(block_in_if_condition_stmt, linkedlist))]

extern crate serde;
extern crate serde_json;
extern crate glob;
#[macro_use] extern crate pest;
#[macro_use] extern crate quick_error;
extern crate slug;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate url;
extern crate humansize;

mod errors;
#[macro_use] mod macros;
mod parser;
mod context;
mod render;
mod template;
mod tera;
mod filters;
mod testers;
mod utils;

// Library exports.

// Template is meant to be used internally only but is exported for test/bench.
#[doc(hidden)] pub use template::Template;
pub use context::Context;
pub use tera::Tera;
pub use errors::{TeraResult, TeraError};
pub use utils::{escape_html};
// Re-export Value so apps/tools can encode data in Tera types
// for now it's serde_json
pub use serde_json::value::{Value, to_value};
<|endoftext|>


<commit_before>
//! Hubcaps wraps hyper with an interface for interacting with the Github API

extern crate hyper;
extern crate rustc_serialize;
extern crate url;

pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repository;
pub mod statuses;
pub mod pullrequests;

pub use rep::*;
use errors::Error;
use gists::{Gists, UserGists};
use hyper::Client;
use hyper::method::Method;
use hyper::header::{Authorization, UserAgent};
use hyper::status::StatusCode;
use repository::Repository;
use std::default::Default;
use std::fmt;
use std::io::Read;

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            State::Open   => "open",
            State::Closed => "closed",
            State::All    => "all"
        })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
pub enum SortDirection {
    Asc,
    Desc
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            SortDirection::Asc => "asc",
            SortDirection::Desc => "desc"
        })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: &'static str,
    agent: &'static str,
    client: &'a Client,
    token: Option<&'static str>
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new(
        agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github::host("https://api.github.com", agent, client, token)
    }

    /// Create a new Github instance hosted at a custom location
    pub fn host(
        host: &'static str, agent: &'static str,
        client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github {
            host: host,
            agent: agent,
            client: client,
            token: token
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists(&self, owner: &'static str) -> UserGists {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    fn request(
        &self, method: Method, uri: &str, body: Option<&'a [u8]>) -> Result<String> {
        let url = format!("{}{}", self.host, uri);
        let builder = self.client.request(method, &url).header(
            UserAgent(self.agent.to_owned())
        );
        let authenticated = match self.token {
            Some(token) =>
                builder.header(
                    Authorization(format!("token {}", token))
               ),
            _ =>
                builder
        };
        let mut res = match body {
            Some(ref bod) => try!(authenticated.body(*bod).send()),
            _ => try!(authenticated.send())
        };
        let mut body = String::new();
        try!(res.read_to_string(&mut body));
        match res.status {
            StatusCode::BadRequest
            | StatusCode::UnprocessableEntity
            | StatusCode::Unauthorized
            | StatusCode::NotFound
            | StatusCode::Forbidden => Err(
                Error::Fault { code: res.status, body: body }
            ),
            _ => Ok(body)
        }
    }

    fn get(&self, uri: &str) -> Result<String> {
        self.request(
            Method::Get,
            uri,
            None
        )
    }

    fn delete(&self, uri: &str) -> Result<()> {
        self.request(
            Method::Delete,
            uri,
            None
        ).map(|_| ())
    }

    fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Post,
            uri,
            Some(message)
        )
    }

    fn patch(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Patch,
            uri,
            Some(message)
        )
    }

    fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Put,
            uri,
            Some(message)
        )
    }
}
<commit_msg>one less try<commit_after>
//! Hubcaps wraps hyper with an interface for interacting with the Github API

extern crate hyper;
extern crate rustc_serialize;
extern crate url;

pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repository;
pub mod statuses;
pub mod pullrequests;

pub use rep::*;
use errors::Error;
use gists::{Gists, UserGists};
use hyper::Client;
use hyper::method::Method;
use hyper::header::{Authorization, UserAgent};
use hyper::status::StatusCode;
use repository::Repository;
use std::default::Default;
use std::fmt;
use std::io::Read;

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            State::Open   => "open",
            State::Closed => "closed",
            State::All    => "all"
        })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
pub enum SortDirection {
    Asc,
    Desc
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            SortDirection::Asc => "asc",
            SortDirection::Desc => "desc"
        })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: &'static str,
    agent: &'static str,
    client: &'a Client,
    token: Option<&'static str>
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new(
        agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github::host("https://api.github.com", agent, client, token)
    }

    /// Create a new Github instance hosted at a custom location
    pub fn host(
        host: &'static str, agent: &'static str,
        client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github {
            host: host,
            agent: agent,
            client: client,
            token: token
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists(&self, owner: &'static str) -> UserGists {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    fn request(
        &self, method: Method, uri: &str, body: Option<&'a [u8]>) -> Result<String> {
        let url = format!("{}{}", self.host, uri);
        let builder = self.client.request(method, &url).header(
            UserAgent(self.agent.to_owned())
        );
        let authenticated = match self.token {
            Some(token) =>
                builder.header(
                    Authorization(format!("token {}", token))
               ),
            _ =>
                builder
        };
        let mut res = try!(
            match body {
                Some(ref bod) => authenticated.body(*bod).send(),
                _ => authenticated.send()
            }
        );
        let mut body = String::new();
        try!(res.read_to_string(&mut body));
        match res.status {
            StatusCode::BadRequest
            | StatusCode::UnprocessableEntity
            | StatusCode::Unauthorized
            | StatusCode::NotFound
            | StatusCode::Forbidden => Err(
                Error::Fault { code: res.status, body: body }
            ),
            _ => Ok(body)
        }
    }

    fn get(&self, uri: &str) -> Result<String> {
        self.request(
            Method::Get,
            uri,
            None
        )
    }

    fn delete(&self, uri: &str) -> Result<()> {
        self.request(
            Method::Delete,
            uri,
            None
        ).map(|_| ())
    }

    fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Post,
            uri,
            Some(message)
        )
    }

    fn patch(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Patch,
            uri,
            Some(message)
        )
    }

    fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Put,
            uri,
            Some(message)
        )
    }
}
<|endoftext|>


<commit_before>extern crate log;
extern crate simplelog;

use goblin::pe::PE;
use goblin::Object;
use log::{debug, error, info, trace};
use rayon::prelude::*;
use std::env;
use std::fs;
use std::io::prelude::*;
use zydis;

// TODO: this really shouldn't be public. only for testing.
// TODO: what is the `cfg(doctest)` setting?
//#[cfg(test)]
pub mod rsrc;

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments");
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config { filename })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info, simplelog::Config::default())
        .expect("failed to setup logging");
}

#[derive(Debug)]
pub enum Error {
    FileAccess,
    FileFormat,
    NotImplemented,
    ValueError,
}

/// Round the given value up to the next multiple of the given base.
///
/// # Panics
///
///   - Base `b` must be at least `2`.
///
/// # Examples
///
/// ```
/// use lancelot::*;
/// assert_eq!(align(0, 2), 0);
/// assert_eq!(align(1, 2), 2);
/// assert_eq!(align(2, 2), 2);
/// assert_eq!(align(3, 2), 4);
/// assert_eq!(align(4, 2), 4);
/// ```
pub fn align(i: usize, b: usize) -> usize {
    if b < 2 {
        panic!("base `b` must be at least: 2");
    }
    let rem = i % b;
    if rem == 0 {
        i
    } else {
        i + (b - rem)
    }
}

pub fn hexdump_ascii(b: u8) -> char {
    if b.is_ascii_graphic() || b == b' ' {
        b as char
    } else {
        '.'
    }
}

pub fn hexdump(buf: &[u8], offset: usize) -> String {
    // 01234567:  00 01 02 03 04 05 06 07  ...............
    // <prefix>   <hex col>                <ascii col>

    let padding = "  ";

    let padding_size = 2;
    let hex_col_size = 3;
    let ascii_col_size = 1;
    let prefix_size = 8 + 1;
    let newline_size = 1;
    let line_size = prefix_size
        + padding_size
        + 16 * hex_col_size
        + padding_size
        + 16 * ascii_col_size
        + newline_size;
    let line_count = align(buf.len(), 0x10) / 0x10;

    let mut ret = String::with_capacity(line_count * line_size);

    let mut line = String::with_capacity(line_size);
    let mut remaining_count = buf.len();
    for line_index in 0..line_count {
        let line_elem_count = 0x10.min(remaining_count);
        let padding_elem_count = 0x10 - line_elem_count;

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        // ^^^^^^^^^
        line.push_str(format!("{:08x}:", offset + 0x10 * line_index).as_str());

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //          ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //            ^^^
        for elem in &buf[line_index..line_index + line_elem_count] {
            line.push_str(format!("{:02x} ", elem).as_str());
        }
        for _ in 0..padding_elem_count {
            line.push_str("   ");
        }

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                   ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                     ^
        for elem in &buf[line_index..line_index + line_elem_count] {
            line.push(hexdump_ascii(*elem))
        }
        for _ in 0..padding_elem_count {
            line.push(' ');
        }
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                                    ^
        line.push('\n');

        ret.push_str(line.as_str());
        line.truncate(0x0);
        remaining_count -= line_elem_count;
    }

    ret
}

fn foo(ws: &Workspace) -> Result<(), Error> {
    if let Object::PE(pe) = ws.get_obj().unwrap() {
        info!("module: {}", pe.name.unwrap_or("(unknown)"));

        info!("bitness: {}", if pe.is_64 { "64" } else { "32" });
        info!("image base: 0x{:x}", pe.image_base);
        info!("entry rva: 0x{:x}", pe.entry);

        // like:
        //
        //     sections:
        //       - .text
        //         raw size:     0x18aa00
        //         virtual size: 0x18a9a8
        info!("sections:");
        for section in ws.sections.iter() {
            info!("  - {}", section.name);
            info!("    virtual address: 0x{:x}", section.addr);
            info!("    virtual size: 0x{:x}", section.buf.len());

            info!(
                "\n{}",
                hexdump(&section.buf[..0x1C], pe.image_base + section.addr as usize)
            );

            let decoder =
                zydis::Decoder::new(zydis::MachineMode::Long64, zydis::AddressWidth::_64).unwrap();
            let insns: Vec<_> = section
                .buf
                .par_windows(0x10)
                .map(|ibuf| decoder.decode(ibuf))
                .collect();

            info!("total instructions: {}", insns.len());

            info!(
                "successful disassembles: {}",
                insns.par_iter().filter(|insn| insn.is_ok()).count()
            );

            info!(
                "valid instructions: {}",
                insns
                    .par_iter()
                    .filter(|insn| match insn {
                        Ok(Some(_)) => true,
                        _ => false,
                    })
                    .count()
            );
        }
    }

    Ok(())
}

pub fn read_file(filename: &str) -> Result<Vec<u8>, Error> {
    debug!("read_file: {:?}", filename);

    let mut buf = Vec::new();
    {
        debug!("reading file: {}", filename);
        let mut f = match fs::File::open(filename) {
            Ok(f) => f,
            Err(_) => {
                error!("failed to open file: {}", filename);
                return Err(Error::FileAccess);
            }
        };
        let bytes_read = match f.read_to_end(&mut buf) {
            Ok(c) => c,
            Err(_) => {
                error!("failed to read entire file: {}", filename);
                return Err(Error::FileAccess);
            }
        };
        debug!("read {} bytes", bytes_read);
        if bytes_read < 0x10 {
            error!("file too small: {}", filename);
            return Err(Error::FileFormat);
        }
    }

    Ok(buf)
}

pub struct Section {
    pub name: String,
    pub addr: u32,
    pub buf: Vec<u8>,
    pub insns: Vec<Option<zydis::ffi::DecodedInstruction>>,
}

pub struct Workspace {
    pub filename: String,
    pub buf: Vec<u8>,
    pub sections: Vec<Section>,
}

impl Workspace {
    /// Parse the given file into its object.
    ///
    /// # Errors
    ///   - `Error::FileFormat`: when not able to be parsed by Goblin.
    ///
    /// # Examples
    ///
    /// ```
    /// use goblin::Object;
    /// use matches::matches;
    /// use lancelot::rsrc::*;
    /// let ws = get_workspace(Rsrc::K32);
    /// assert!(matches!(ws.get_obj().unwrap(), Object::PE(_)));
    /// ```
    ///
    /// you might be tempted to maintain a method `get_pe`,
    /// however, i don't think this is a good idea:
    /// its fragile because the file type may not be PE.
    /// therefore, force clients to be explicit:
    ///
    /// ```
    /// use goblin::Object;
    /// use lancelot::rsrc::*;
    /// let ws = get_workspace(Rsrc::K32);
    /// if let Object::PE(_) = ws.get_obj().unwrap() {
    ///     // everyone is happy!
    /// }
    /// ```
    ///
    /// TODO: demonstrate `Error::FileFormat`.
    pub fn get_obj(&self) -> Result<Object, Error> {
        let obj = match Object::parse(&self.buf) {
            Ok(o) => o,
            Err(e) => {
                error!("failed to parse file: {} error: {:?}", self.filename, e);
                return Err(Error::FileFormat);
            }
        };

        match obj {
            Object::Unknown(_) => {
                error!(
                    "unknown file format, magic: | {:02X} {:02X} | '{}{}' ",
                    self.buf[0],
                    self.buf[1],
                    hexdump_ascii(self.buf[0]),
                    hexdump_ascii(self.buf[1])
                );

                Err(Error::FileFormat)
            }
            _ => Ok(obj),
        }
    }

    pub fn get_pe(&self) -> Result<PE, Error> {
        match self.get_obj()? {
            Object::PE(pe) => {
                return Ok(pe);
            }
            _ => {
                error!("not a PE file");
                return Err(Error::ValueError);
            }
        }
    }

    /// Construct a workspace from the module with the given contents.
    ///
    /// # Errors
    ///   - `Error::FileFormat`: when not able to be parsed by Goblin.
    ///   - `Error::NotImplemented`: when not a PE file.
    ///
    /// # Examples
    ///
    /// ```
    /// use lancelot::*;
    /// use lancelot::rsrc::*;
    /// let buf = get_buf(Rsrc::K32);
    /// let ws = Workspace::from_buf("kernel32.dll", buf).unwrap();
    /// ```
    ///
    /// TODO: demonstrate ELF file behavior.
    /// TODO: demonstrate MachO file behavior.
    /// TODO: demonstrate unknown file behavior.
    pub fn from_buf(filename: &str, buf: Vec<u8>) -> Result<Workspace, Error> {
        let mut ws = Workspace {
            filename: filename.to_string(),
            buf: buf.clone(),
            sections: vec![],
        };

        match ws.get_obj()? {
            Object::PE(pe) => {
                info!("found PE file");

                let machine;
                let mode;
                if pe.is_64 {
                    machine = zydis::MachineMode::Long64;
                    mode = zydis::AddressWidth::_64;
                } else {
                    // TODO: not sure what `LongCompat32` means, vs `Legacy32`.
                    machine = zydis::MachineMode::LongCompat32;
                    mode = zydis::AddressWidth::_32;
                }
                // TODO: save off decoder into workspace.
                let decoder = zydis::Decoder::new(machine, mode).unwrap();

                // TODO: load PE header, too

                ws.sections
                    .extend(pe.sections.iter().map(|section| -> Section {
                        // TODO: i'm sure this can be abused.
                        // TODO: add tests for weird section names.
                        let name = String::from_utf8_lossy(&section.name[..])
                            .into_owned()
                            .trim_end_matches("\u{0}")
                            .trim_end()
                            .to_string();

                        // TODO: figure out if we will work with usize, or u64, or what,
                        // then assert usize is ok.
                        // ref: `usize::max_value()`
                        let mut secbuf = vec![0; align(section.virtual_size as usize, 0x200)];

                        {
                            let secsize = section.size_of_raw_data as usize;
                            let rawbuf = &mut secbuf[..secsize];
                            let pstart = section.pointer_to_raw_data as usize;
                            rawbuf.copy_from_slice(&buf[pstart..pstart + secsize]);
                        }

                        let insns: Vec<_> = secbuf
                            .par_windows(0x10)
                            .map(|ibuf| match decoder.decode(ibuf) {
                                Ok(Some(insn)) => Some(insn),
                                _ => None,
                            })
                            .collect();

                        Section {
                            name: name,
                            addr: section.virtual_address,
                            buf: secbuf,
                            insns: insns,
                        }
                    }));
            }
            Object::Elf(_) => {
                return Err(Error::NotImplemented);
            }
            Object::Mach(_) => {
                return Err(Error::NotImplemented);
            }
            Object::Archive(_) => {
                return Err(Error::NotImplemented);
            }
            Object::Unknown(_) => {
                return Err(Error::NotImplemented);
            }
        }

        Ok(ws)
    }

    /// Construct a workspace from the module at given a file path.
    ///
    /// ```
    /// use lancelot::*;
    /// use lancelot::rsrc::*;
    /// let path = get_path(Rsrc::K32);
    /// // This test resource file is mangled. Needs to be fixed before parsing.
    /// // Otherwise, the following would work:
    /// // let ws = Workspace::from_file(&path).unwrap();
    /// ```
    pub fn from_file(filename: &str) -> Result<Workspace, Error> {
        let buf = read_file(filename)?;
        Workspace::from_buf(filename, buf)
    }
}

pub fn run(args: &Config) -> Result<(), Error> {
    debug!("filename: {:?}", args.filename);
    let ws = Workspace::from_file(&args.filename)?;

    if let Object::PE(_) = ws.get_obj()? {
        foo(&ws).expect("failed to foo");
    }

    Ok(())
}
<commit_msg>lib: add rva and va types<commit_after>extern crate log;
extern crate simplelog;

use goblin::pe::PE;
use goblin::Object;
use log::{debug, error, info, trace};
use rayon::prelude::*;
use std::env;
use std::fs;
use std::io::prelude::*;
use zydis;

// TODO: this really shouldn't be public. only for testing.
// TODO: what is the `cfg(doctest)` setting?
//#[cfg(test)]
pub mod rsrc;

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments");
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config { filename })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info, simplelog::Config::default())
        .expect("failed to setup logging");
}

#[derive(Debug)]
pub enum Error {
    FileAccess,
    FileFormat,
    NotImplemented,
    InvalidRva,
}

/// Round the given value up to the next multiple of the given base.
///
/// # Panics
///
///   - Base `b` must be at least `2`.
///
/// # Examples
///
/// ```
/// use lancelot::*;
/// assert_eq!(align(0, 2), 0);
/// assert_eq!(align(1, 2), 2);
/// assert_eq!(align(2, 2), 2);
/// assert_eq!(align(3, 2), 4);
/// assert_eq!(align(4, 2), 4);
/// ```
pub fn align(i: usize, b: usize) -> usize {
    if b < 2 {
        panic!("base `b` must be at least: 2");
    }
    let rem = i % b;
    if rem == 0 {
        i
    } else {
        i + (b - rem)
    }
}

pub fn hexdump_ascii(b: u8) -> char {
    if b.is_ascii_graphic() || b == b' ' {
        b as char
    } else {
        '.'
    }
}

pub fn hexdump(buf: &[u8], offset: usize) -> String {
    // 01234567:  00 01 02 03 04 05 06 07  ...............
    // <prefix>   <hex col>                <ascii col>

    let padding = "  ";

    let padding_size = 2;
    let hex_col_size = 3;
    let ascii_col_size = 1;
    let prefix_size = 8 + 1;
    let newline_size = 1;
    let line_size = prefix_size
        + padding_size
        + 16 * hex_col_size
        + padding_size
        + 16 * ascii_col_size
        + newline_size;
    let line_count = align(buf.len(), 0x10) / 0x10;

    let mut ret = String::with_capacity(line_count * line_size);

    let mut line = String::with_capacity(line_size);
    let mut remaining_count = buf.len();
    for line_index in 0..line_count {
        let line_elem_count = 0x10.min(remaining_count);
        let padding_elem_count = 0x10 - line_elem_count;

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        // ^^^^^^^^^
        line.push_str(format!("{:08x}:", offset + 0x10 * line_index).as_str());

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //          ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //            ^^^
        for elem in &buf[line_index..line_index + line_elem_count] {
            line.push_str(format!("{:02x} ", elem).as_str());
        }
        for _ in 0..padding_elem_count {
            line.push_str("   ");
        }

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                   ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                     ^
        for elem in &buf[line_index..line_index + line_elem_count] {
            line.push(hexdump_ascii(*elem))
        }
        for _ in 0..padding_elem_count {
            line.push(' ');
        }
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                                    ^
        line.push('\n');

        ret.push_str(line.as_str());
        line.truncate(0x0);
        remaining_count -= line_elem_count;
    }

    ret
}

fn foo(ws: &Workspace) -> Result<(), Error> {
    if let Object::PE(pe) = ws.get_obj().unwrap() {
        info!("module: {}", pe.name.unwrap_or("(unknown)"));

        info!("bitness: {}", if pe.is_64 { "64" } else { "32" });
        info!("image base: 0x{:x}", pe.image_base);
        info!("entry rva: 0x{:x}", pe.entry);

        // like:
        //
        //     sections:
        //       - .text
        //         raw size:     0x18aa00
        //         virtual size: 0x18a9a8
        info!("sections:");
        for section in ws.sections.iter() {
            info!("  - {}", section.name);
            info!("    virtual address: 0x{:x}", section.addr);
            info!("    virtual size: 0x{:x}", section.buf.len());

            info!(
                "\n{}",
                hexdump(&section.buf[..0x1C], pe.image_base + section.addr as usize)
            );

            let decoder =
                zydis::Decoder::new(zydis::MachineMode::Long64, zydis::AddressWidth::_64).unwrap();
            let insns: Vec<_> = section
                .buf
                .par_windows(0x10)
                .map(|ibuf| decoder.decode(ibuf))
                .collect();

            info!("total instructions: {}", insns.len());

            info!(
                "successful disassembles: {}",
                insns.par_iter().filter(|insn| insn.is_ok()).count()
            );

            info!(
                "valid instructions: {}",
                insns
                    .par_iter()
                    .filter(|insn| match insn {
                        Ok(Some(_)) => true,
                        _ => false,
                    })
                    .count()
            );
        }
    }

    Ok(())
}

pub fn read_file(filename: &str) -> Result<Vec<u8>, Error> {
    debug!("read_file: {:?}", filename);

    let mut buf = Vec::new();
    {
        debug!("reading file: {}", filename);
        let mut f = match fs::File::open(filename) {
            Ok(f) => f,
            Err(_) => {
                error!("failed to open file: {}", filename);
                return Err(Error::FileAccess);
            }
        };
        let bytes_read = match f.read_to_end(&mut buf) {
            Ok(c) => c,
            Err(_) => {
                error!("failed to read entire file: {}", filename);
                return Err(Error::FileAccess);
            }
        };
        debug!("read {} bytes", bytes_read);
        if bytes_read < 0x10 {
            error!("file too small: {}", filename);
            return Err(Error::FileFormat);
        }
    }

    Ok(buf)
}

type Rva = u64;
type Va = u64;

pub struct Section {
    pub name: String,
    pub addr: Rva,
    pub buf: Vec<u8>,
    pub insns: Vec<Option<zydis::ffi::DecodedInstruction>>,
}

pub struct Workspace {
    pub filename: String,
    pub buf: Vec<u8>,
    pub sections: Vec<Section>,
}

impl Workspace {
    /// Parse the given file into its object.
    ///
    /// # Errors
    ///   - `Error::FileFormat`: when not able to be parsed by Goblin.
    ///
    /// # Examples
    ///
    /// ```
    /// use goblin::Object;
    /// use matches::matches;
    /// use lancelot::rsrc::*;
    /// let ws = get_workspace(Rsrc::K32);
    /// assert!(matches!(ws.get_obj().unwrap(), Object::PE(_)));
    /// ```
    ///
    /// you might be tempted to maintain a method `get_pe`,
    /// however, i don't think this is a good idea:
    /// its fragile because the file type may not be PE.
    /// therefore, force clients to be explicit:
    ///
    /// ```
    /// use goblin::Object;
    /// use lancelot::rsrc::*;
    /// let ws = get_workspace(Rsrc::K32);
    /// if let Object::PE(_) = ws.get_obj().unwrap() {
    ///     // everyone is happy!
    /// }
    /// ```
    ///
    /// TODO: demonstrate `Error::FileFormat`.
    pub fn get_obj(&self) -> Result<Object, Error> {
        let obj = match Object::parse(&self.buf) {
            Ok(o) => o,
            Err(e) => {
                error!("failed to parse file: {} error: {:?}", self.filename, e);
                return Err(Error::FileFormat);
            }
        };

        match obj {
            Object::Unknown(_) => {
                error!(
                    "unknown file format, magic: | {:02X} {:02X} | '{}{}' ",
                    self.buf[0],
                    self.buf[1],
                    hexdump_ascii(self.buf[0]),
                    hexdump_ascii(self.buf[1])
                );

                Err(Error::FileFormat)
            }
            _ => Ok(obj),
        }
    }

    pub fn get_pe(&self) -> Result<PE, Error> {
        match self.get_obj()? {
            Object::PE(pe) => {
                return Ok(pe);
            }
            _ => {
                error!("not a PE file");
                return Err(Error::ValueError);
            }
        }
    }

    /// Construct a workspace from the module with the given contents.
    ///
    /// # Errors
    ///   - `Error::FileFormat`: when not able to be parsed by Goblin.
    ///   - `Error::NotImplemented`: when not a PE file.
    ///
    /// # Examples
    ///
    /// ```
    /// use lancelot::*;
    /// use lancelot::rsrc::*;
    /// let buf = get_buf(Rsrc::K32);
    /// let ws = Workspace::from_buf("kernel32.dll", buf).unwrap();
    /// ```
    ///
    /// TODO: demonstrate ELF file behavior.
    /// TODO: demonstrate MachO file behavior.
    /// TODO: demonstrate unknown file behavior.
    pub fn from_buf(filename: &str, buf: Vec<u8>) -> Result<Workspace, Error> {
        let mut ws = Workspace {
            filename: filename.to_string(),
            buf: buf.clone(),
            sections: vec![],
        };

        match ws.get_obj()? {
            Object::PE(pe) => {
                info!("found PE file");

                let machine;
                let mode;
                if pe.is_64 {
                    machine = zydis::MachineMode::Long64;
                    mode = zydis::AddressWidth::_64;
                } else {
                    // TODO: not sure what `LongCompat32` means, vs `Legacy32`.
                    machine = zydis::MachineMode::LongCompat32;
                    mode = zydis::AddressWidth::_32;
                }
                // TODO: save off decoder into workspace.
                let decoder = zydis::Decoder::new(machine, mode).unwrap();

                // TODO: load PE header, too

                ws.sections
                    .extend(pe.sections.iter().map(|section| -> Section {
                        // TODO: i'm sure this can be abused.
                        // TODO: add tests for weird section names.
                        let name = String::from_utf8_lossy(&section.name[..])
                            .into_owned()
                            .trim_end_matches("\u{0}")
                            .trim_end()
                            .to_string();

                        // TODO: figure out if we will work with usize, or u64, or what,
                        // then assert usize is ok.
                        // ref: `usize::max_value()`
                        let mut secbuf = vec![0; align(section.virtual_size as usize, 0x200)];

                        {
                            let secsize = section.size_of_raw_data as usize;
                            let rawbuf = &mut secbuf[..secsize];
                            let pstart = section.pointer_to_raw_data as usize;
                            rawbuf.copy_from_slice(&buf[pstart..pstart + secsize]);
                        }

                        let insns: Vec<_> = secbuf
                            .par_windows(0x10)
                            .map(|ibuf| match decoder.decode(ibuf) {
                                Ok(Some(insn)) => Some(insn),
                                _ => None,
                            })
                            .collect();

                        info!("loaded section: {}", name);
                        Section {
                            name: name,
                            addr: section.virtual_address as Rva,
                            buf: secbuf,
                            insns: insns,
                        }
                    }));
            }
            Object::Elf(_) => {
                return Err(Error::NotImplemented);
            }
            Object::Mach(_) => {
                return Err(Error::NotImplemented);
            }
            Object::Archive(_) => {
                return Err(Error::NotImplemented);
            }
            Object::Unknown(_) => {
                return Err(Error::NotImplemented);
            }
        }

        Ok(ws)
    }

    /// Construct a workspace from the module at given a file path.
    ///
    /// ```
    /// use lancelot::*;
    /// use lancelot::rsrc::*;
    /// let path = get_path(Rsrc::K32);
    /// // This test resource file is mangled. Needs to be fixed before parsing.
    /// // Otherwise, the following would work:
    /// // let ws = Workspace::from_file(&path).unwrap();
    /// ```
    pub fn from_file(filename: &str) -> Result<Workspace, Error> {
        let buf = read_file(filename)?;
        Workspace::from_buf(filename, buf)
    }
}

pub fn run(args: &Config) -> Result<(), Error> {
    debug!("filename: {:?}", args.filename);
    let ws = Workspace::from_file(&args.filename)?;

    if let Object::PE(_) = ws.get_obj()? {
        foo(&ws).expect("failed to foo");
    }

    Ok(())
}
<|endoftext|>