<commit_before>use std::error::Error;

use mio::EventSet;

use {Machine, Scope, Response};

/// Composes two state machines
///
/// Used to "mount" two different application into single main loop, or to
/// use multiple protocols simultaneously. Can be nested to any level.
///
/// We will probably implement n > 2 composition later, for effeciency
/// reasons.
pub enum Compose2<A:Sized, B:Sized> {
    A(A),
    B(B),
}

pub enum Compose2Seed<A:Sized, B:Sized> {
    As(A),
    Bs(B),
}

impl<X, A, B> Machine for Compose2<A, B>
    where A: Machine<Context=X>, B:Machine<Context=X>
{
    type Context = X;
    type Seed = Compose2Seed<A::Seed, B::Seed>;

    fn create(seed: Self::Seed, scope: &mut Scope<X>)
        -> Result<Self, Box<Error>>
    {
        use Compose2::*;
        use self::Compose2Seed::*;
        match seed {
            As(s) => A::create(s, scope).map(A),
            Bs(s) => B::create(s, scope).map(B),
        }
    }
    fn ready(self, events: EventSet, scope: &mut Scope<X>)
        -> Response<Self, Self::Seed>
    {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.ready(events, scope).map(A, As) }
            B(m) => { m.ready(events, scope).map(B, Bs) }
        }
    }
    fn spawned(self, scope: &mut Scope<X>) -> Response<Self, Self::Seed>
    {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.spawned(scope).map(A, As) }
            B(m) => { m.spawned(scope).map(B, Bs) }
        }
    }
    fn timeout(self, scope: &mut Scope<X>) -> Response<Self, Self::Seed> {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.timeout(scope).map(A, As) }
            B(m) => { m.timeout(scope).map(B, Bs) }
        }
    }
    fn wakeup(self, scope: &mut Scope<X>) -> Response<Self, Self::Seed> {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.wakeup(scope).map(A, As) }
            B(m) => { m.wakeup(scope).map(B, Bs) }
        }
    }
}
<commit_msg>fix for E0248 in Compose<commit_after>use std::error::Error;

use mio::EventSet;

use {Machine, Scope, Response};

/// Composes two state machines
///
/// Used to "mount" two different application into single main loop, or to
/// use multiple protocols simultaneously. Can be nested to any level.
///
/// We will probably implement n > 2 composition later, for effeciency
/// reasons.
pub enum Compose2<A:Sized, B:Sized> {
    A(A),
    B(B),
}

pub enum Compose2Seed<A:Sized, B:Sized> {
    As(A),
    Bs(B),
}

impl<X, AA, BB> Machine for Compose2<AA, BB>
    where AA: Machine<Context=X>, BB:Machine<Context=X>
{
    type Context = X;
    type Seed = Compose2Seed<AA::Seed, BB::Seed>;

    fn create(seed: Self::Seed, scope: &mut Scope<X>)
        -> Result<Self, Box<Error>>
    {
        use Compose2::*;
        use self::Compose2Seed::*;
        match seed {
            As(s) => AA::create(s, scope).map(A),
            Bs(s) => BB::create(s, scope).map(B),
        }
    }
    fn ready(self, events: EventSet, scope: &mut Scope<X>)
        -> Response<Self, Self::Seed>
    {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.ready(events, scope).map(A, As) }
            B(m) => { m.ready(events, scope).map(B, Bs) }
        }
    }
    fn spawned(self, scope: &mut Scope<X>) -> Response<Self, Self::Seed>
    {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.spawned(scope).map(A, As) }
            B(m) => { m.spawned(scope).map(B, Bs) }
        }
    }
    fn timeout(self, scope: &mut Scope<X>) -> Response<Self, Self::Seed> {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.timeout(scope).map(A, As) }
            B(m) => { m.timeout(scope).map(B, Bs) }
        }
    }
    fn wakeup(self, scope: &mut Scope<X>) -> Response<Self, Self::Seed> {
        use Compose2::*;
        use self::Compose2Seed::*;
        match self {
            A(m) => { m.wakeup(scope).map(A, As) }
            B(m) => { m.wakeup(scope).map(B, Bs) }
        }
    }
}
<|endoftext|>


<commit_before>use Query;
use Token;

use std::collections::{HashMap, BTreeMap};

/// Result of a query
pub struct QueryReturn {
    text: String,
    condition: Option<bool>,
}

/// Trait describing an object that can be queried for variables
pub trait Queryable {
    fn query(&self, key: &str) -> Option<String>;
}

/// Trait describing an object that contains a dictionary of functions
pub trait Context {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>>;
}

/// Errors found while evaluating query
#[derive(Debug)]
pub enum EvalError {
    /// Function used is not in the current context
    /// String passed is the function name
    FunctionNotFound(String),
}

pub type EvalResult<T> = Result<T, EvalError>;

/// The General function signature for formatting function calls
/// > note: very likely to change
pub type EvalFunc = (Fn(&Vec<Token>) -> EvalResult<QueryReturn>);

impl Query {
    /// Evaluate the query with a queryable object to be based off and a
    /// context
    pub fn eval(&self, queryable: &Queryable, context: &Context) -> EvalResult<String> {
        match self.tokens.eval(queryable, context) {
            Ok(res) => Ok(res.text),
            Err(err) => Err(err),
        }
    }
}

impl Token {

    /// Evaluate a token
    pub fn eval(&self,
                  queryable: &Queryable,
                  context: &Context)
                  -> EvalResult<QueryReturn> {
        match *self {
            Token::Scope(ref tokens) => {
                let mut result = false;
                let mut text = String::new();
                for token in tokens {
                    match token.eval(queryable, context) {
                        Ok(res) => {
                            // TODO: should result of scope be an AND or OR of all results
                            result = result || res.condition.unwrap_or(false);
                            text.push_str(&res.text);
                        }
                        Err(e) => return Err(e),
                    }
                }
                Ok(QueryReturn {
                    text: text,
                    condition: Some(result),
                })
            }
            Token::Text(ref t) => {
                Ok(QueryReturn {
                    text: t.to_owned(),
                    condition: None,
                })
            }
            Token::Variable(ref v) => {
                match queryable.query(v) {
                    Some(r) => {
                        Ok(QueryReturn {
                            text: r,
                            condition: Some(true),
                        })
                    }
                    None => {
                        Ok(QueryReturn {
                            text: String::new(),
                            condition: Some(false),
                        })
                    }
                }
            }
            Token::Function(ref f, ref arg) => {
                match context.get_func(f) {
                    Some(func) => func(arg),
                    None => {
                        return Err(EvalError::FunctionNotFound(f.to_owned()));
                    }
                }
            }
        }
    }
}

// Example Implementation for Queryable and Context

impl Queryable for HashMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for HashMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

impl Queryable for BTreeMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for BTreeMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use Query;
    use std::collections::HashMap;

    #[test]
    fn test_run() {

        let mut map = HashMap::new();
        map.insert("name".to_owned(), "Dave".to_owned());

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%!".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello Dave!".to_owned(), result);
    }

    #[test]
    fn test_run_unknown_variable() {

        let map = HashMap::new();

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%!".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello !".to_owned(), result);
    }

    #[test]
    fn test_run_func() {

        let map = HashMap::new();

        let mut func = HashMap::<String, Box<EvalFunc>>::new();
        func.insert("hi".to_owned(),
                    Box::new(|_| {
                        Ok(QueryReturn {
                            text: "hi!".to_owned(),
                            condition: None,
                        })
                    }));

        let result = Query::parse("Hello $hi()".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello hi!".to_owned(), result);
    }

    #[test]
    fn test_run_func_does_not_exist() {

        let map = HashMap::new();

        let func = HashMap::<String, Box<EvalFunc>>::new();

        match Query::parse("Hello $hi()".to_owned())
                  .unwrap()
                  .eval(&map, &func) {
            Ok(_) => unreachable!(),
            Err(e) => {
                match e {
                    EvalError::FunctionNotFound(_) => (),
                }
            }
        }
    }
}
<commit_msg>refactor: fix simple clippy warning<commit_after>use Query;
use Token;

use std::collections::{HashMap, BTreeMap};

/// Result of a query
pub struct QueryReturn {
    text: String,
    condition: Option<bool>,
}

/// Trait describing an object that can be queried for variables
pub trait Queryable {
    fn query(&self, key: &str) -> Option<String>;
}

/// Trait describing an object that contains a dictionary of functions
pub trait Context {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>>;
}

/// Errors found while evaluating query
#[derive(Debug)]
pub enum EvalError {
    /// Function used is not in the current context
    /// String passed is the function name
    FunctionNotFound(String),
}

pub type EvalResult<T> = Result<T, EvalError>;

/// The General function signature for formatting function calls
/// > note: very likely to change
pub type EvalFunc = (Fn(&Vec<Token>) -> EvalResult<QueryReturn>);

impl Query {
    /// Evaluate the query with a queryable object to be based off and a
    /// context
    pub fn eval(&self, queryable: &Queryable, context: &Context) -> EvalResult<String> {
        match self.tokens.eval(queryable, context) {
            Ok(res) => Ok(res.text),
            Err(err) => Err(err),
        }
    }
}

impl Token {
    /// Evaluate a token
    pub fn eval(&self, queryable: &Queryable, context: &Context) -> EvalResult<QueryReturn> {
        match *self {
            Token::Scope(ref tokens) => {
                let mut result = false;
                let mut text = String::new();
                for token in tokens {
                    match token.eval(queryable, context) {
                        Ok(res) => {
                            // TODO: should result of scope be an AND or OR of all results
                            result = result || res.condition.unwrap_or(false);
                            text.push_str(&res.text);
                        }
                        Err(e) => return Err(e),
                    }
                }
                Ok(QueryReturn {
                    text: text,
                    condition: Some(result),
                })
            }
            Token::Text(ref t) => {
                Ok(QueryReturn {
                    text: t.to_owned(),
                    condition: None,
                })
            }
            Token::Variable(ref v) => {
                match queryable.query(v) {
                    Some(r) => {
                        Ok(QueryReturn {
                            text: r,
                            condition: Some(true),
                        })
                    }
                    None => {
                        Ok(QueryReturn {
                            text: String::new(),
                            condition: Some(false),
                        })
                    }
                }
            }
            Token::Function(ref f, ref arg) => {
                match context.get_func(f) {
                    Some(func) => func(arg),
                    None => Err(EvalError::FunctionNotFound(f.to_owned())),
                }
            }
        }
    }
}

// Example Implementation for Queryable and Context

impl Queryable for HashMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for HashMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

impl Queryable for BTreeMap<String, String> {
    fn query(&self, query: &str) -> Option<String> {
        match self.get(query) {
            Some(ans) => Some(ans.to_owned()),
            None => None,
        }
    }
}

impl Context for BTreeMap<String, Box<EvalFunc>> {
    fn get_func(&self, name: &str) -> Option<&Box<EvalFunc>> {
        self.get(name)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use Query;
    use std::collections::HashMap;

    #[test]
    fn test_run() {

        let mut map = HashMap::new();
        map.insert("name".to_owned(), "Dave".to_owned());

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%!".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello Dave!".to_owned(), result);
    }

    #[test]
    fn test_run_unknown_variable() {

        let map = HashMap::new();

        let func = HashMap::<String, Box<EvalFunc>>::new();

        let result = Query::parse("Hello %name%!".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello !".to_owned(), result);
    }

    #[test]
    fn test_run_func() {

        let map = HashMap::new();

        let mut func = HashMap::<String, Box<EvalFunc>>::new();
        func.insert("hi".to_owned(),
                    Box::new(|_| {
                        Ok(QueryReturn {
                            text: "hi!".to_owned(),
                            condition: None,
                        })
                    }));

        let result = Query::parse("Hello $hi()".to_owned())
                         .unwrap()
                         .eval(&map, &func)
                         .unwrap();

        assert_eq!("Hello hi!".to_owned(), result);
    }

    #[test]
    fn test_run_func_does_not_exist() {

        let map = HashMap::new();

        let func = HashMap::<String, Box<EvalFunc>>::new();

        match Query::parse("Hello $hi()".to_owned())
                  .unwrap()
                  .eval(&map, &func) {
            Ok(_) => unreachable!(),
            Err(e) => {
                match e {
                    EvalError::FunctionNotFound(_) => (),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Transformation context

use draw_state::DrawState;
use default_draw_state;
use math::{
    abs_transform,
    identity,
    get_scale,
    Matrix2d,
    Scalar,
    Vec2d,
};

/// Transform property
#[derive(Copy, Clone)]
pub struct Transform(pub Matrix2d);

/// View transform property
#[derive(Copy, Clone)]
pub struct ViewTransform(pub Matrix2d);

/// Drawing 2d context.
#[derive(Copy, Clone)]
pub struct Context {
    /// View transformation.
    pub view: Matrix2d,
    /// Current transformation.
    pub transform: Matrix2d,
    /// Current draw state settings.
    pub draw_state: DrawState,
}

impl Context {
    /// Creates a new drawing context.
    #[inline(always)]
    pub fn new() -> Context {
        Context {
            view: identity(),
            transform: identity(),
            draw_state: *default_draw_state(),
        }
    }

    /// Creates a new drawing context in absolute coordinates.
    ///
    /// This function assumes the default coordinate system
    /// being centered with x axis pointing to the right
    /// and y axis pointing up.
    ///
    /// Returns a drawing context
    /// with origin in the upper left corner
    /// and x axis pointing to the right
    /// and y axis pointing down.
    #[inline(always)]
    pub fn abs(w: Scalar, h: Scalar) -> Context {
        let mat = abs_transform(w, h);
        Context {
            view: mat,
            transform: mat,
            draw_state: *default_draw_state(),
        }
    }

    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    pub fn view(mut self) -> Self {
        self.transform = self.view;
        self
    }

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    #[inline(always)]
    pub fn reset(mut self) -> Self {
        self.transform = identity();
        self
    }

    /// Stores the current transform as new view.
    #[inline(always)]
    pub fn store_view(mut self) -> Self {
        self.view = self.transform;
        self
    }

    /// Computes the current view size.
    #[inline(always)]
    pub fn get_view_size(&self) -> Vec2d {
        let scale = get_scale(self.view);
        [2.0 / scale[0], 2.0 / scale[1]]
    }
}

#[cfg(test)]
mod test {
    use super::Context;
    use std::num::Float;

    #[test]
    fn test_context() {
        use RelativeTransform;

        let c = Context::new();
        {
            let d = c.trans(20.0, 40.0);
            let d = d.trans(10.0, 10.0);
            let transform = d.transform;
            assert_eq!(transform[0][2], 30.0);
            assert_eq!(transform[1][2], 50.0);
        }

        let transform = c.transform;
        assert_eq!(transform[0][2], 0.0);
        assert_eq!(transform[1][2], 0.0);

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

    #[test]
    fn test_scale() {
        use RelativeTransform;

        let c = Context::new();
        let c = c.scale(2.0, 3.0);
        let transform = c.transform;
        assert!((transform[0][0] - 2.0).abs() < 0.00001);
        assert!((transform[1][1] - 3.0).abs() < 0.00001);
    }
}
<commit_msg>Deleted `Transform` property type<commit_after>//! Transformation context

use draw_state::DrawState;
use default_draw_state;
use math::{
    abs_transform,
    identity,
    get_scale,
    Matrix2d,
    Scalar,
    Vec2d,
};

/// View transform property
#[derive(Copy, Clone)]
pub struct ViewTransform(pub Matrix2d);

/// Drawing 2d context.
#[derive(Copy, Clone)]
pub struct Context {
    /// View transformation.
    pub view: Matrix2d,
    /// Current transformation.
    pub transform: Matrix2d,
    /// Current draw state settings.
    pub draw_state: DrawState,
}

impl Context {
    /// Creates a new drawing context.
    #[inline(always)]
    pub fn new() -> Context {
        Context {
            view: identity(),
            transform: identity(),
            draw_state: *default_draw_state(),
        }
    }

    /// Creates a new drawing context in absolute coordinates.
    ///
    /// This function assumes the default coordinate system
    /// being centered with x axis pointing to the right
    /// and y axis pointing up.
    ///
    /// Returns a drawing context
    /// with origin in the upper left corner
    /// and x axis pointing to the right
    /// and y axis pointing down.
    #[inline(always)]
    pub fn abs(w: Scalar, h: Scalar) -> Context {
        let mat = abs_transform(w, h);
        Context {
            view: mat,
            transform: mat,
            draw_state: *default_draw_state(),
        }
    }

    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    pub fn view(mut self) -> Self {
        self.transform = self.view;
        self
    }

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    #[inline(always)]
    pub fn reset(mut self) -> Self {
        self.transform = identity();
        self
    }

    /// Stores the current transform as new view.
    #[inline(always)]
    pub fn store_view(mut self) -> Self {
        self.view = self.transform;
        self
    }

    /// Computes the current view size.
    #[inline(always)]
    pub fn get_view_size(&self) -> Vec2d {
        let scale = get_scale(self.view);
        [2.0 / scale[0], 2.0 / scale[1]]
    }
}

#[cfg(test)]
mod test {
    use super::Context;
    use std::num::Float;

    #[test]
    fn test_context() {
        use RelativeTransform;

        let c = Context::new();
        {
            let d = c.trans(20.0, 40.0);
            let d = d.trans(10.0, 10.0);
            let transform = d.transform;
            assert_eq!(transform[0][2], 30.0);
            assert_eq!(transform[1][2], 50.0);
        }

        let transform = c.transform;
        assert_eq!(transform[0][2], 0.0);
        assert_eq!(transform[1][2], 0.0);

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

    #[test]
    fn test_scale() {
        use RelativeTransform;

        let c = Context::new();
        let c = c.scale(2.0, 3.0);
        let transform = c.transform;
        assert!((transform[0][0] - 2.0).abs() < 0.00001);
        assert!((transform[1][1] - 3.0).abs() < 0.00001);
    }
}
<|endoftext|>


<commit_before>use crate::gen::{Error, Input, Result};
use crate::syntax::namespace::Namespace;
use quote::quote;
use syn::{Attribute, File, Item};

pub(super) fn find_bridge_mod(syntax: File) -> Result<Input> {
    for item in syntax.items {
        if let Item::Mod(item) = item {
            for attr in &item.attrs {
                let path = &attr.path;
                if quote!(#path).to_string() == "cxx :: bridge" {
                    let module = match item.content {
                        Some(module) => module.1,
                        None => {
                            return Err(Error::Syn(syn::Error::new_spanned(
                                item,
                                Error::OutOfLineMod,
                            )));
                        }
                    };
                    let namespace = parse_args(attr)?;
                    return Ok(Input { namespace, module });
                }
            }
        }
    }
    Err(Error::NoBridgeMod)
}

fn parse_args(attr: &Attribute) -> syn::Result<Namespace> {
    if attr.tokens.is_empty() {
        Ok(Namespace::none())
    } else {
        attr.parse_args()
    }
}
<commit_msg>Find cxx::bridge mod nested inside another mod<commit_after>use crate::gen::{Error, Input, Result};
use crate::syntax::namespace::Namespace;
use quote::quote;
use syn::{Attribute, File, Item};

pub(super) fn find_bridge_mod(syntax: File) -> Result<Input> {
    match scan(syntax.items)? {
        Some(input) => Ok(input),
        None => Err(Error::NoBridgeMod),
    }
}

fn scan(items: Vec<Item>) -> Result<Option<Input>> {
    for item in items {
        if let Item::Mod(item) = item {
            for attr in &item.attrs {
                let path = &attr.path;
                if quote!(#path).to_string() == "cxx :: bridge" {
                    let module = match item.content {
                        Some(module) => module.1,
                        None => {
                            return Err(Error::Syn(syn::Error::new_spanned(
                                item,
                                Error::OutOfLineMod,
                            )));
                        }
                    };
                    let namespace = parse_args(attr)?;
                    return Ok(Some(Input { namespace, module }));
                }
            }
            if let Some(module) = item.content {
                if let Some(input) = scan(module.1)? {
                    return Ok(Some(input));
                }
            }
        }
    }
    Ok(None)
}

fn parse_args(attr: &Attribute) -> syn::Result<Namespace> {
    if attr.tokens.is_empty() {
        Ok(Namespace::none())
    } else {
        attr.parse_args()
    }
}
<|endoftext|>


<commit_before>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new(name: &str) {
    let home_unwrap = homedir().unwrap();
    let home        = home_unwrap.display();

    let muxed_dir = if muxed_dir_exists(&"muxed".to_string()) {
      Path::new(format!("{}/.muxed/", home))
    } else {
      create_muxed_dir(&"muxed".to_string())
    };

    let path = format!("{}/{}", muxed_dir.display(), name);

    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    path.exists()
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let home_unwrap = homedir().unwrap();
  let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<commit_msg>Spacing.<commit_after>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new(name: &str) {
    let home_unwrap = homedir().unwrap();
    let home        = home_unwrap.display();

    let muxed_dir = if muxed_dir_exists(&"muxed".to_string()) {
      Path::new(format!("{}/.muxed/", home))
    } else {
      create_muxed_dir(&"muxed".to_string())
    };

    let path = format!("{}/{}", muxed_dir.display(), name);

    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    path.exists()
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let home_unwrap = homedir().unwrap();
  let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn populates_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = value.as_slice().contains("muxed project");
    assert!(result);
}

#[test]
fn replaces_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = !value.as_slice().contains("{file_name}");
    assert!(result);
}

#[test]
fn creates_project_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn errors_when_creating_project_file() {
    assert!(false);
}

#[test]
fn create_copies_the_template_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    let data = File::open(path).read_to_end().unwrap();
    assert_eq!(data.as_slice(), TEMPLATE.as_bytes());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<commit_msg>Add method to modify template values.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

fn modified_template(template: &str, project_name: &str) -> String {
    template.replace("{file_name}", project_name)
}

#[test]
fn populates_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = value.as_slice().contains("muxed project");
    assert!(result);
}

#[test]
fn replaces_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = !value.as_slice().contains("{file_name}");
    assert!(result);
}

#[test]
fn creates_project_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn errors_when_creating_project_file() {
    assert!(false);
}

#[test]
fn create_copies_the_template_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    let data = File::open(path).read_to_end().unwrap();
    assert_eq!(data.as_slice(), TEMPLATE.as_bytes());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<|endoftext|>


<commit_before>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

extern crate extra;
use extra::test::BenchHarness;

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;

/// Returns Some(`rem`) if the line is a horizontal rule, with `rem` being the
/// buf after the hrule. Otherwise returns None.
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut buf = buf;

    if buf.len() < 3 { return None }

    // Skip up to three leading spaces.
    //
    // We don't need to care about tabs here as in this position they are
    // equivalent to 4 spaces, which means we would not parse this as a
    // hrule.
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }

    // We need at least 3 items
    if buf.len() < 3 { return None }

    let item = buf[0];

    if !(item == ('*' as u8) || item == ('-' as u8) || item == ('_' as u8)) {
        return None;
    }

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces

    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());
}

#[bench]
fn bench_is_hrule(b: &mut BenchHarness) {
    let s = bytes!("   * * * * * * * * * * * * * * * *\n");
    b.iter(|| is_hrule(s));
}
<commit_msg>Add test case to check remaining buffer<commit_after>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

extern crate extra;
use extra::test::BenchHarness;

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;

/// Returns Some(`rem`) if the line is a horizontal rule, with `rem` being the
/// buf after the hrule. Otherwise returns None.
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut buf = buf;

    if buf.len() < 3 { return None }

    // Skip up to three leading spaces.
    //
    // We don't need to care about tabs here as in this position they are
    // equivalent to 4 spaces, which means we would not parse this as a
    // hrule.
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }

    // We need at least 3 items
    if buf.len() < 3 { return None }

    let item = buf[0];

    if !(item == ('*' as u8) || item == ('-' as u8) || item == ('_' as u8)) {
        return None;
    }

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces

    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());

    // Test if the remaining buf actually works.
    let s = bytes!("   * * *\nremaining");
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

#[bench]
fn bench_is_hrule(b: &mut BenchHarness) {
    let s = bytes!("   * * * * * * * * * * * * * * * *\n");
    b.iter(|| is_hrule(s));
}
<|endoftext|>


<commit_before>use std::{collections::VecDeque, io::SeekFrom};

use log::{debug, error, trace};
use nom::{self, Err, IResult, Needed, Offset};

use av_data::{
    audiosample::ChannelMap, packet::Packet, params::*, rational::Rational64, timeinfo::TimeInfo,
};
use av_format::{
    buffer::Buffered,
    common::GlobalInfo,
    demuxer::{Demuxer, Descr, Descriptor, Event},
    error::*,
    stream::Stream,
};

use crate::{
    ebml::{self, custom_error, ebml_header, EBMLHeader},
    elements::{
        segment, segment_element, simple_block, Audio, Cluster, Info, SeekHead, SegmentElement,
        TrackEntry, Tracks, Video,
    },
};

#[derive(Debug, Clone, Default)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
    pub params: Option<DemuxerParams>,
}

#[derive(Debug, Clone, Default)]
pub struct DemuxerParams {
    pub track_numbers: Option<Vec<u64>>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
            params: None,
        }
    }

    pub fn with_params(params: DemuxerParams) -> MkvDemuxer {
        MkvDemuxer {
            params: Some(params),
            ..Default::default()
        }
    }

    pub fn parse_until_tracks<'a>(
        &mut self,
        original_input: &'a [u8],
    ) -> IResult<&'a [u8], (), ebml::Error<'a>> {
        let (i1, header) = ebml_header(original_input)?;

        self.header = Some(header);

        let (mut input, _) = segment(i1)?;

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            let (i3, element) = segment_element(input)?;

            match element {
                SegmentElement::SeekHead(s) => {
                    trace!("got seek head: {:#?}", s);
                    self.seek_head = if self.seek_head.is_none() {
                        Some(s)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Info(i) => {
                    trace!("got info: {:#?}", i);
                    self.info = if self.info.is_none() {
                        Some(i)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Tracks(t) => {
                    trace!("got tracks: {:#?}", t);
                    self.tracks = if self.tracks.is_none() {
                        // Only keep tracks we're interested in
                        if let Some(params) = &self.params {
                            if let Some(track_numbers) = &params.track_numbers {
                                let mut t = t;
                                t.tracks = t
                                    .tracks
                                    .into_iter()
                                    .filter(|tr| track_numbers.contains(&tr.track_number))
                                    .collect();
                                Some(t)
                            } else {
                                None
                            }
                        } else {
                            None
                        }
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                el => {
                    debug!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<dyn Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self
                    .info
                    .as_ref()
                    .and_then(|info| info.duration)
                    .map(|d| d as u64);
                if let Some(ref mut t) = self.tracks {
                    for tr in t.tracks.iter_mut() {
                        info.add_stream(track_to_stream(self.info.as_ref().unwrap(), tr));
                        tr.stream_index = info.streams.last().unwrap().index;
                    }
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            }
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + usize::from(size),
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            }
            e => {
                error!("{:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            debug!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets(self.tracks.as_ref().unwrap());
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {}
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                }
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(usize::from(size)))
                }
                e => {
                    error!("{:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1" => Some("av1".to_owned()),
        "V_VP8" => Some("vp8".to_owned()),
        "V_VP9" => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(video: &Video) -> Option<MediaKind> {
    let v = VideoInfo {
        width: video.pixel_width as usize,
        height: video.pixel_height as usize,
        // TODO parse Colour and/or CodecPrivate to extract the format
        format: None,
    };
    Some(MediaKind::Video(v))
}

fn track_entry_audio_kind(audio: &Audio) -> Option<MediaKind> {
    let rate = if let Some(r) = audio.output_sampling_frequency {
        r
    } else {
        audio.sampling_frequency
    };
    // TODO: complete it
    let map = if audio.channel_positions.is_none() {
        Some(ChannelMap::default_map(audio.channels as usize))
    } else {
        unimplemented!("Convert matroska map to rust-av map")
    };
    let a = AudioInfo {
        rate: rate as usize,
        map,
        format: None,
    };
    Some(MediaKind::Audio(a))
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => {
            if let Some(ref video) = t.video {
                track_entry_video_kind(video)
            } else {
                None
            }
        }
        0x2 => {
            if let Some(ref audio) = t.audio {
                track_entry_audio_kind(audio)
            } else {
                None
            }
        }
        _ => None,
    }
}

pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = t
        .track_timecode_scale
        .map(|ts| {
            if ts != 0. {
                (ts * info.timecode_scale as f64) as i64
            } else {
                info.timecode_scale as i64
            }
        })
        .unwrap_or(info.timecode_scale as i64);

    Stream {
        id: t.track_uid as isize,
        index: t.stream_index,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
        user_private: None,
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self, tracks: &Tracks) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                debug!("parsing simple block: {:?}", block);
                if let Some(index) = tracks.lookup(block.track_number) {
                    let packet = Packet {
                        data: i.into(),
                        t: TimeInfo {
                            pts: Some(i64::from(block.timecode)),
                            dts: None,
                            duration: None,
                            timebase: None,
                            user_private: None,
                        },
                        pos: None,
                        stream_index: index as isize,
                        is_key: block.keyframe,
                        is_corrupted: false,
                    };

                    v.push(Event::NewPacket(packet));
                }
            } else {
                error!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<dyn Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe(&self) -> &Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        ebml_header(&data[..100]).map(|_| 100).unwrap_or(0)
    }
}

pub const MKV_DESC: &dyn Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    },
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use std::io::Cursor;

    use log::info;
    use nom::Offset;

    use av_format::{buffer::*, demuxer::Context};

    use super::*;

    const webm: &[u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        info!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                info!("offset: {} bytes", webm.offset(i));
            }
            e => {
                info!("could not parse: {:?}", e);
            }
        }

        info!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => info!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => info!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(
            Box::new(MkvDemuxer::new()),
            Box::new(AccReader::new(Cursor::new(webm))),
        );
        info!("read headers: {:?}", context.read_headers().unwrap());
        info!("streams: {:?}", context.info.streams);
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
    }
}
<commit_msg>Simplify code a bit<commit_after>use std::{collections::VecDeque, io::SeekFrom};

use log::{debug, error, trace};
use nom::{self, Err, IResult, Needed, Offset};

use av_data::{
    audiosample::ChannelMap, packet::Packet, params::*, rational::Rational64, timeinfo::TimeInfo,
};
use av_format::{
    buffer::Buffered,
    common::GlobalInfo,
    demuxer::{Demuxer, Descr, Descriptor, Event},
    error::*,
    stream::Stream,
};

use crate::{
    ebml::{self, custom_error, ebml_header, EBMLHeader},
    elements::{
        segment, segment_element, simple_block, Audio, Cluster, Info, SeekHead, SegmentElement,
        TrackEntry, Tracks, Video,
    },
};

#[derive(Debug, Clone, Default)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
    pub params: Option<DemuxerParams>,
}

#[derive(Debug, Clone, Default)]
pub struct DemuxerParams {
    pub track_numbers: Option<Vec<u64>>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
            params: None,
        }
    }

    pub fn with_params(params: DemuxerParams) -> MkvDemuxer {
        MkvDemuxer {
            params: Some(params),
            ..Default::default()
        }
    }

    pub fn parse_until_tracks<'a>(
        &mut self,
        original_input: &'a [u8],
    ) -> IResult<&'a [u8], (), ebml::Error<'a>> {
        let (i1, header) = ebml_header(original_input)?;

        self.header = Some(header);

        let (mut input, _) = segment(i1)?;

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            let (i3, element) = segment_element(input)?;

            match element {
                SegmentElement::SeekHead(s) => {
                    trace!("got seek head: {:#?}", s);
                    self.seek_head = if self.seek_head.is_none() {
                        Some(s)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Info(i) => {
                    trace!("got info: {:#?}", i);
                    self.info = if self.info.is_none() {
                        Some(i)
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                SegmentElement::Tracks(t) => {
                    trace!("got tracks: {:#?}", t);
                    self.tracks = if self.tracks.is_none() {
                        // Only keep tracks we're interested in
                        self.params.as_ref().and_then(|params| {
                            params.track_numbers.as_ref().map(|track_numbers| {
                                let mut t = t;
                                t.tracks = t
                                    .tracks
                                    .into_iter()
                                    .filter(|tr| track_numbers.contains(&tr.track_number))
                                    .collect();
                                t
                            })
                        })
                    } else {
                        return Err(Err::Error(custom_error(input, 1)));
                    };
                }
                el => {
                    debug!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<dyn Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self
                    .info
                    .as_ref()
                    .and_then(|info| info.duration)
                    .map(|d| d as u64);
                if let Some(ref mut t) = self.tracks {
                    for tr in t.tracks.iter_mut() {
                        info.add_stream(track_to_stream(self.info.as_ref().unwrap(), tr));
                        tr.stream_index = info.streams.last().unwrap().index;
                    }
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            }
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + usize::from(size),
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            }
            e => {
                error!("{:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    if let SegmentElement::Cluster(c) = element {
                        debug!("got cluster element at timecode: {}", c.timecode);
                        let mut packets = c.generate_packets(self.tracks.as_ref().unwrap());
                        self.queue.extend(packets.drain(..));
                        if let Some(event) = self.queue.pop_front() {
                            return Ok((seek, event));
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                }
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(usize::from(size)))
                }
                e => {
                    error!("{:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1" => Some("av1".to_owned()),
        "V_VP8" => Some("vp8".to_owned()),
        "V_VP9" => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(video: &Video) -> Option<MediaKind> {
    let v = VideoInfo {
        width: video.pixel_width as usize,
        height: video.pixel_height as usize,
        // TODO parse Colour and/or CodecPrivate to extract the format
        format: None,
    };
    Some(MediaKind::Video(v))
}

fn track_entry_audio_kind(audio: &Audio) -> Option<MediaKind> {
    let rate = audio
        .output_sampling_frequency
        .unwrap_or(audio.sampling_frequency);
    // TODO: complete it
    let map = if audio.channel_positions.is_none() {
        Some(ChannelMap::default_map(audio.channels as usize))
    } else {
        unimplemented!("Convert matroska map to rust-av map")
    };
    let a = AudioInfo {
        rate: rate as usize,
        map,
        format: None,
    };
    Some(MediaKind::Audio(a))
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => t.video.as_ref().and_then(track_entry_video_kind),
        0x2 => t.audio.as_ref().and_then(track_entry_audio_kind),
        _ => None,
    }
}

pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = t
        .track_timecode_scale
        .map_or(info.timecode_scale as i64, |ts| {
            if ts != 0. {
                (ts * info.timecode_scale as f64) as i64
            } else {
                info.timecode_scale as i64
            }
        });

    Stream {
        id: t.track_uid as isize,
        index: t.stream_index,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
        user_private: None,
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self, tracks: &Tracks) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                debug!("parsing simple block: {:?}", block);
                if let Some(index) = tracks.lookup(block.track_number) {
                    let packet = Packet {
                        data: i.into(),
                        t: TimeInfo {
                            pts: Some(i64::from(block.timecode)),
                            dts: None,
                            duration: None,
                            timebase: None,
                            user_private: None,
                        },
                        pos: None,
                        stream_index: index as isize,
                        is_key: block.keyframe,
                        is_corrupted: false,
                    };

                    v.push(Event::NewPacket(packet));
                }
            } else {
                error!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<dyn Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe(&self) -> &Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        ebml_header(&data[..100]).map_or(0, |_| 100)
    }
}

pub const MKV_DESC: &dyn Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    },
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use std::io::Cursor;

    use log::info;
    use nom::Offset;

    use av_format::{buffer::*, demuxer::Context};

    use super::*;

    const webm: &[u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        info!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                info!("offset: {} bytes", webm.offset(i));
            }
            e => {
                info!("could not parse: {:?}", e);
            }
        }

        info!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => info!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => info!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(
            Box::new(MkvDemuxer::new()),
            Box::new(AccReader::new(Cursor::new(webm))),
        );
        info!("read headers: {:?}", context.read_headers().unwrap());
        info!("streams: {:?}", context.info.streams);
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
        info!("event: {:?}", context.read_event().unwrap());
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate nom;
extern crate quote;
extern crate syn;

#[cfg(feature = "serde-json")]
extern crate serde;
#[cfg(feature = "serde-json")]
extern crate serde_json;

pub use escaping::MarkupDisplay;
pub use errors::{Error, Result};
pub mod filters;
pub mod path;

mod escaping;
mod generator;
mod parser;

use std::borrow::Cow;
use std::path::PathBuf;

/// Takes a `syn::DeriveInput` and generates source code for it
///
/// Reads the metadata from the `template()` attribute to get the template
/// metadata, then fetches the source from the filesystem. The source is
/// parsed, and the parse tree is fed to the code generator. Will print
/// the parse tree and/or generated source according to the `print` key's
/// value as passed to the `template()` attribute.
pub fn build_template(ast: &syn::DeriveInput) -> String {
    let meta = get_template_meta(ast);
    let (path, src) = match meta.source {
        Source::Source(s) => (PathBuf::new(), Cow::Borrowed(s)),
        Source::Path(s) => {
            let path = path::find_template_from_path(&s, None);
            let src = path::get_template_source(&path);
            (path, Cow::Owned(src))
        },
    };
    let nodes = parser::parse(src.as_ref());
    if meta.print == Print::Ast || meta.print == Print::All {
        println!("{:?}", nodes);
    }
    let code = generator::generate(ast, &path, &nodes);
    if meta.print == Print::Code || meta.print == Print::All {
        println!("{}", code);
    }
    code
}

// Returns a `TemplateMeta` based on the `template()` attribute data found
// in the parsed struct or enum. Will panic if it does not find the required
// template path, or if the `print` key has an unexpected value.
fn get_template_meta<'a>(ast: &'a syn::DeriveInput) -> TemplateMeta<'a> {
    let attr = ast.attrs.iter().find(|a| a.name() == "template");
    if attr.is_none() {
        let msg = format!("'template' attribute not found on struct '{}'",
                          ast.ident.as_ref());
        panic!(msg);
    }

    let attr = attr.unwrap();
    let mut source = None;
    let mut print = Print::None;
    if let syn::MetaItem::List(_, ref inner) = attr.value {
        for nm_item in inner {
            if let syn::NestedMetaItem::MetaItem(ref item) = *nm_item {
                if let syn::MetaItem::NameValue(ref key, ref val) = *item {
                    match key.as_ref() {
                        "path" => if let syn::Lit::Str(ref s, _) = *val {
                            source = Some(Source::Path(s.as_ref()));
                        } else {
                            panic!("template path must be string literal");
                        },
                        "source" => if let syn::Lit::Str(ref s, _) = *val {
                            source = Some(Source::Source(s.as_ref()));
                        } else {
                            panic!("template source must be string literal");
                        },
                        "print" => if let syn::Lit::Str(ref s, _) = *val {
                            print = s.into();
                        } else {
                            panic!("print value must be string literal");
                        },
                        _ => { panic!("unsupported annotation key found") }
                    }
                }
            }
        }
    }

    match source {
        Some(s) => TemplateMeta { source: s, print },
        None => panic!("template path or source not found in struct attributes"),
    }
}

mod errors {
    error_chain! {
        foreign_links {
            Fmt(::std::fmt::Error);
            Json(::serde_json::Error) #[cfg(feature = "serde-json")];
        }
    }
}

// Holds metadata for the template, based on the `template()` attribute.
struct TemplateMeta<'a> {
    source: Source<'a>,
    print: Print,
}

enum Source<'a> {
    Path(&'a str),
    Source(&'a str),
}

#[derive(PartialEq)]
enum Print {
    All,
    Ast,
    Code,
    None,
}

impl<'a> From<&'a String> for Print {
    fn from(s: &'a String) -> Print {
        use Print::*;
        match s.as_ref() {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => panic!("invalid value for print option: {}", v),
        }
    }
}
<commit_msg>Create better abstraction around TemplateMeta type<commit_after>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate nom;
extern crate quote;
extern crate syn;

#[cfg(feature = "serde-json")]
extern crate serde;
#[cfg(feature = "serde-json")]
extern crate serde_json;

pub use escaping::MarkupDisplay;
pub use errors::{Error, Result};
pub mod filters;
pub mod path;

mod escaping;
mod generator;
mod parser;

use std::borrow::Cow;
use std::path::PathBuf;

/// Takes a `syn::DeriveInput` and generates source code for it
///
/// Reads the metadata from the `template()` attribute to get the template
/// metadata, then fetches the source from the filesystem. The source is
/// parsed, and the parse tree is fed to the code generator. Will print
/// the parse tree and/or generated source according to the `print` key's
/// value as passed to the `template()` attribute.
pub fn build_template(ast: &syn::DeriveInput) -> String {
    let meta = TemplateMeta::new(ast);
    let (path, src) = match meta.source {
        Source::Source(s) => (PathBuf::new(), Cow::Borrowed(s)),
        Source::Path(s) => {
            let path = path::find_template_from_path(&s, None);
            let src = path::get_template_source(&path);
            (path, Cow::Owned(src))
        },
    };
    let nodes = parser::parse(src.as_ref());
    if meta.print == Print::Ast || meta.print == Print::All {
        println!("{:?}", nodes);
    }
    let code = generator::generate(ast, &path, &nodes);
    if meta.print == Print::Code || meta.print == Print::All {
        println!("{}", code);
    }
    code
}

mod errors {
    error_chain! {
        foreign_links {
            Fmt(::std::fmt::Error);
            Json(::serde_json::Error) #[cfg(feature = "serde-json")];
        }
    }
}

// Holds metadata for the template, based on the `template()` attribute.
struct TemplateMeta<'a> {
    source: Source<'a>,
    print: Print,
}

impl<'a> TemplateMeta<'a> {
    fn new(ast: &'a syn::DeriveInput) -> TemplateMeta<'a> {
        let attr = ast.attrs.iter().find(|a| a.name() == "template");
        if attr.is_none() {
            let msg = format!("'template' attribute not found on struct '{}'",
                              ast.ident.as_ref());
            panic!(msg);
        }

        let attr = attr.unwrap();
        let mut source = None;
        let mut print = Print::None;
        if let syn::MetaItem::List(_, ref inner) = attr.value {
            for nm_item in inner {
                if let syn::NestedMetaItem::MetaItem(ref item) = *nm_item {
                    if let syn::MetaItem::NameValue(ref key, ref val) = *item {
                        match key.as_ref() {
                            "path" => if let syn::Lit::Str(ref s, _) = *val {
                                source = Some(Source::Path(s.as_ref()));
                            } else {
                                panic!("template path must be string literal");
                            },
                            "source" => if let syn::Lit::Str(ref s, _) = *val {
                                source = Some(Source::Source(s.as_ref()));
                            } else {
                                panic!("template source must be string literal");
                            },
                            "print" => if let syn::Lit::Str(ref s, _) = *val {
                                print = s.into();
                            } else {
                                panic!("print value must be string literal");
                            },
                            _ => { panic!("unsupported annotation key found") }
                        }
                    }
                }
            }
        }

        match source {
            Some(s) => TemplateMeta { source: s, print },
            None => panic!("template path or source not found in struct attributes"),
        }
    }
}

enum Source<'a> {
    Path(&'a str),
    Source(&'a str),
}

#[derive(PartialEq)]
enum Print {
    All,
    Ast,
    Code,
    None,
}

impl<'a> From<&'a String> for Print {
    fn from(s: &'a String) -> Print {
        use Print::*;
        match s.as_ref() {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => panic!("invalid value for print option: {}", v),
        }
    }
}
<|endoftext|>


<commit_before>//! Functions and data-structures to load descriptor tables.
use core::fmt;
use core::mem::size_of;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> DescriptorTablePointer<T> {
    pub fn new(tbl: &T) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: tbl as *const T,
            limit: len as u16,
        }
    }

    pub fn new_from_slice(slice: &[T]) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = slice.len() * size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

impl<T> fmt::Debug for DescriptorTablePointer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe { write!(f, "DescriptorTablePointer ({} {:?})", self.limit, self.base) }
    }
}

/// Load GDT table with 32bit descriptors
pub unsafe fn lgdt<T>(gdt: &DescriptorTablePointer<T>) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table with 32bit descriptors.
pub unsafe fn lldt<T>(ldt: &DescriptorTablePointer<T>) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table with 32bit descriptors.
pub unsafe fn lidt<T>(idt: &DescriptorTablePointer<T>) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}
<commit_msg>Add support for sidt instruction.<commit_after>//! Functions and data-structures to load descriptor tables.
use core::fmt;
use core::mem::size_of;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> Default for DescriptorTablePointer<T> {
    fn default() -> DescriptorTablePointer<T> {
        DescriptorTablePointer {
            limit: 0,
            base: core::ptr::null(),
        }
    }
}

impl<T> DescriptorTablePointer<T> {
    pub fn new(tbl: &T) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: tbl as *const T,
            limit: len as u16,
        }
    }

    pub fn new_from_slice(slice: &[T]) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = slice.len() * size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

impl<T> fmt::Debug for DescriptorTablePointer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe { write!(f, "DescriptorTablePointer ({} {:?})", self.limit, self.base) }
    }
}

/// Load GDT table with 32bit descriptors
pub unsafe fn lgdt<T>(gdt: &DescriptorTablePointer<T>) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table with 32bit descriptors.
pub unsafe fn lldt<T>(ldt: &DescriptorTablePointer<T>) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table with 32bit descriptors.
pub unsafe fn lidt<T>(idt: &DescriptorTablePointer<T>) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}

/// Retrive IDT table with 32bit descriptors.
pub unsafe fn sidt<T>(mut idt: &mut DescriptorTablePointer<T>) {
    asm!("sidt ($0)" : "=r" (idt) :: "memory");
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::f64;

use image::{ DynamicImage, GenericImage, ImageFormat };
use image;

use bitreader::BitReader;

use num_traits::float::Float;

pub struct CoverImage {
    cover_image: DynamicImage
}

impl CoverImage {
    pub fn new(file_path: &str) -> CoverImage {
        CoverImage {
            cover_image: image::open(&Path::new(&file_path)).unwrap()
        }
    }

    pub fn encode_with(&self, message: &str) {
        let bit_vector = get_bit_vec(message);

        encode(&self.cover_image, &bit_vector);

        let ref mut fout = File::create(&Path::new("/home/hugh/Pictures/yurt.png")).unwrap();

        let _ = self.cover_image.save(fout, ImageFormat::PNG).unwrap();
    }
}

// Get a Vector of Bits to Encode the Image with
fn get_bit_vec(message: &str) -> Vec<u8> {
    let mut bit_vector = Vec::new();
    let mut reader = BitReader::new(&message.as_bytes());

    // Multiplied by 8 because it's a Vec of bits not bytes
    for _ in 0..message.len() * 8 {
        bit_vector.push(reader.read_u8(1).unwrap());
    }

    bit_vector
}

// Encode the image with the Vector of Bits
fn encode(c_image: &DynamicImage, bit_vec: &Vec<u8>) {
    let mut tiled_image_vec = tile_image(&c_image);

    let (width, height) = c_image.dimensions();

    let encoded_image = encode_image(&mut tiled_image_vec, bit_vec, width, height);
}

fn tile_image(c_image: &DynamicImage) -> Vec<image::Rgba<u8>> {
    let (width, height) = c_image.dimensions();

    let mut image_blocks = Vec::new();

    for row_index in 0..(height / 8) as u32 {
        for col_index in 0..(width / 8) as u32 {
            for row in 0..8 {
                for column in 0..8 {
                    image_blocks.push(c_image.get_pixel(column + (col_index * 8), row + (row_index * 8)));
                }
            }
        }
    }

    image_blocks
}

fn encode_image(tiled_image: &mut Vec<image::Rgba<u8>>, message: &Vec<u8>, width: u32, height: u32) {
    let mut cu = 0.0;
    let mut cv = 0.0;
    let mut total = 0.0;
    let mut inverse_total = 0.0;
    let mut index: usize = 0;
    let mut count = 0;
    let mut rgb_coeffs = Vec::new();

    let num_of_iterations = if message.len() / 3 == 0 {
                                    (message.len() / 3) as u32
                                } else {
                                    ((message.len() / 3) + 1) as u32
                                };

    for _ in 0..(num_of_iterations * 64) {
        for channel in 0..3 {
            for v in 0..8 {
                for u in 0..8 {

                    // Forward transform
                    for y in 0..8 {
                        for x in 0..8 {
                            index = u + (v * 8) + (num_of_iterations * 64) as usize;

                            let colour_value = tiled_image[index].data[channel];

                            if u == 0 {
                                cu = 1.0 / 2.0.sqrt()
                            } else {
                                cu = 1.0
                            }

                            if v == 0 {
                                cv = 1.0 / 2.0.sqrt()
                            } else {
                                cv = 0.0
                            }

                            total = total + (4.0 * f64::consts::PI * ((2.0 * y as f64) + 1.0) / 16.0).cos() *
                                            (4.0 * f64::consts::PI * ((2.0 * x as f64) + 1.0) / 16.0).cos() *
                                            colour_value as f64;
                        }
                    }

                    // 0.25, Cu and Cv are scaling factors
                    total = total * 0.25 * cu * cv;

                    // Encode the message
                    if total.trunc() % 2.0 == 0.0 {
                        if message[count] == 1 {
                            total = total + 1.0
                        }
                    } else {
                        if message[count] == 0 {
                            total = total + 1.0
                        }
                    }

                    /*// Inverse transform
                    for v in 0..8 {
                        for u in 0..8 {
                            if u == 0 {
                                cu = 0.0
                            } else {
                                cu = 1.0 / 2.0.sqrt()
                            }

                            if v == 0 {
                                cv = 0.0
                            } else {
                                cv = 1.0 / 2.0.sqrt()
                            }

                            inverse_total = inverse_total + (v * f64::consts::PI * ((2.0 * 4.0) + 1.0) / 16.0).cos() *
                                                            (u * f64::consts::PI * ((2.0 * 4.0) + 1.0) / 16.0).cos() *
                                                            colour_value as f64;
                        }
                    }*/
                }
            }
        }
    }
}

/**************************************************************************************************
 *                                                                                *
 *                                         Tests                                                  *
 *                                                                                *
 **************************************************************************************************/

#[cfg(test)]
#[test]
fn test_get_bit_vec_len() {
    let bits = get_bit_vec("h");

    assert_eq!(8, bits.len());
}

#[cfg(test)]
#[test]
fn test_get_bit_vec() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let bits = get_bit_vec("h");

    assert_eq!(bits, test_bits);
}

#[cfg(test)]
#[test]
fn test_encode_red_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[0] % 2, bit_vec[0]);
}

#[cfg(test)]
#[test]
fn test_encode_green_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[1] % 2, bit_vec[1]);
}

#[cfg(test)]
#[test]
fn test_encode_blue_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[2] % 2 as u8, bit_vec[2]);
}

#[cfg(test)]
#[test]
fn test_full_byte_is_encoded() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let mut encoded_bit_vec = Vec::new();
    let mut count = 0;

    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    'outer: for x_co_ord in 0..3 {
        let pixel = img.get_pixel(x_co_ord, 0);

        for channel in 0..3 {
            if count >= 8 {
                break 'outer;
            }

            encoded_bit_vec.push(pixel.data[channel] % 2);

            count += 1;
        }
    }

    assert_eq!(encoded_bit_vec, bit_vec);
}

#[cfg(test)]
#[test]
fn test_tile_image_length() {
    let img = image::open(&Path::new("/home/hugh/Pictures/colour.jpg")).unwrap();

    let vec = tile_image(&img);

    assert_eq!(vec.len(), 91200);
}

#[cfg(test)]
#[test]
fn test_tile_image_first_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(0, 0);

    let vec = tile_image(&img);

    assert_eq!(vec[0], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel1() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel2() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(40, 16);

    let vec = tile_image(&img);

    assert_eq!(vec[6720], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel3() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_last_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(399, 399);

    let vec = tile_image(&img);

    assert_eq!(vec[159999], pixel);
}
<commit_msg>Start of inverse transform<commit_after>use std::path::Path;
use std::fs::File;
use std::f64;

use image::{ DynamicImage, GenericImage, ImageFormat };
use image;

use bitreader::BitReader;

use num_traits::float::Float;

pub struct CoverImage {
    cover_image: DynamicImage
}

impl CoverImage {
    pub fn new(file_path: &str) -> CoverImage {
        CoverImage {
            cover_image: image::open(&Path::new(&file_path)).unwrap()
        }
    }

    pub fn encode_with(&self, message: &str) {
        let bit_vector = get_bit_vec(message);

        encode(&self.cover_image, &bit_vector);

        let ref mut fout = File::create(&Path::new("/home/hugh/Pictures/yurt.png")).unwrap();

        let _ = self.cover_image.save(fout, ImageFormat::PNG).unwrap();
    }
}

// Get a Vector of Bits to Encode the Image with
fn get_bit_vec(message: &str) -> Vec<u8> {
    let mut bit_vector = Vec::new();
    let mut reader = BitReader::new(&message.as_bytes());

    // Multiplied by 8 because it's a Vec of bits not bytes
    for _ in 0..message.len() * 8 {
        bit_vector.push(reader.read_u8(1).unwrap());
    }

    bit_vector
}

// Encode the image with the Vector of Bits
fn encode(c_image: &DynamicImage, bit_vec: &Vec<u8>) {
    let mut tiled_image_vec = tile_image(&c_image);

    //let (width, height) = c_image.dimensions();

    let encoded_image = encode_image(&mut tiled_image_vec, bit_vec);
}

fn tile_image(c_image: &DynamicImage) -> Vec<image::Rgba<u8>> {
    let (width, height) = c_image.dimensions();

    let mut image_blocks = Vec::new();

    for row_index in 0..(height / 8) as u32 {
        for col_index in 0..(width / 8) as u32 {
            for row in 0..8 {
                for column in 0..8 {
                    image_blocks.push(c_image.get_pixel(column + (col_index * 8), row + (row_index * 8)));
                }
            }
        }
    }

    image_blocks
}

fn encode_image(tiled_image: &mut Vec<image::Rgba<u8>>, message: &Vec<u8>) {
    let mut cu = 0.0;
    let mut cv = 0.0;
    let mut total = 0.0;
    let mut inverse_total = 0.0;
    let mut index: usize = 0;
    let mut count = 0;
    let mut rgb_coeffs: Vec<f64> = Vec::new();
    let mut colour_value: u8 = 0;

    let num_of_iterations = if message.len() / 3 == 0 {
                                    (message.len() / 3) as u32
                                } else {
                                    ((message.len() / 3) + 1) as u32
                                };

    for iteration in 0..num_of_iterations {
        for channel in 0..3 {
            for v in 0..8 {
                for u in 0..8 {
                    // Forward transform
                    for y in 0..8 {
                        for x in 0..8 {
                            index = u + (v * 8) + (iteration * 64) as usize;

                            colour_value = tiled_image[index].data[channel];

                            if u == 0 {
                                cu = 1.0 / 2.0.sqrt()
                            } else {
                                cu = 1.0
                            }

                            if v == 0 {
                                cv = 1.0 / 2.0.sqrt()
                            } else {
                                cv = 0.0
                            }

                            total = total + (v as f64 * f64::consts::PI * (2.0 * (y as f64) + 1.0) / 16.0).cos()
                                          * (u as f64 * f64::consts::PI * (2.0 * (x as f64) + 1.0) / 16.0).cos()
                                          * colour_value as f64;
                        }
                    }

                    // 0.25, Cu and Cv are scaling factors
                    total = total * 0.25 * cu * cv;

                    rgb_coeffs.push(total);
                }
            }

            // Encode the message
            let coeff_to_mod = (27 + (iteration * 64)) as usize;

            if rgb_coeffs[coeff_to_mod].trunc() % 2.0 == 0.0 {
                if message[count] == 1 {
                    rgb_coeffs[coeff_to_mod] = rgb_coeffs[coeff_to_mod] + 1.0
                }
            } else {
                if message[count] == 0 {
                    rgb_coeffs[coeff_to_mod] = rgb_coeffs[coeff_to_mod] + 1.0
                }
            }

            // Inverse transform
            for v in 0..8 {
                for u in 0..8 {
                    if u == 0 {
                        cu = 0.0
                    } else {
                        cu = 1.0 / 2.0.sqrt()
                    }

                    if v == 0 {
                        cv = 0.0
                    } else {
                        cv = 1.0 / 2.0.sqrt()
                    }

                    inverse_total = inverse_total + (v as f64 * f64::consts::PI * (2.0 * (y as f64) + 1.0) / 16.0).cos()
                                                  * (u as f64 * f64::consts::PI * (2.0 * (x as f64) + 1.0) / 16.0).cos()
                                                  * colour_value as f64;
                }
            }
        }
    }
}

/**************************************************************************************************
 *                                                                                *
 *                                         Tests                                                  *
 *                                                                                *
 **************************************************************************************************/

#[cfg(test)]
#[test]
fn test_get_bit_vec_len() {
    let bits = get_bit_vec("h");

    assert_eq!(8, bits.len());
}

#[cfg(test)]
#[test]
fn test_get_bit_vec() {
    let test_bits = vec![0, 1, 1, 0, 1, 0, 0, 0];
    let bits = get_bit_vec("h");

    assert_eq!(bits, test_bits);
}

#[cfg(test)]
#[test]
fn test_encode_red_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[0] % 2, bit_vec[0]);
}

#[cfg(test)]
#[test]
fn test_encode_green_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[1] % 2, bit_vec[1]);
}

#[cfg(test)]
#[test]
fn test_encode_blue_channel_lsb_set() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    let pixel = img.get_pixel(0, 0);

    assert_eq!(pixel.data[2] % 2 as u8, bit_vec[2]);
}

#[cfg(test)]
#[test]
fn test_full_byte_is_encoded() {
    let mut img = image::open(&Path::new("/home/hugh/Pictures/scenery.jpg")).unwrap();
    let mut encoded_bit_vec = Vec::new();
    let mut count = 0;

    let bit_vec = vec![0, 1, 1, 0, 1, 0, 0, 0];

    encode(&mut img, &bit_vec);

    'outer: for x_co_ord in 0..3 {
        let pixel = img.get_pixel(x_co_ord, 0);

        for channel in 0..3 {
            if count >= 8 {
                break 'outer;
            }

            encoded_bit_vec.push(pixel.data[channel] % 2);

            count += 1;
        }
    }

    assert_eq!(encoded_bit_vec, bit_vec);
}

#[cfg(test)]
#[test]
fn test_tile_image_length() {
    let img = image::open(&Path::new("/home/hugh/Pictures/colour.jpg")).unwrap();

    let vec = tile_image(&img);

    assert_eq!(vec.len(), 91200);
}

#[cfg(test)]
#[test]
fn test_tile_image_first_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(0, 0);

    let vec = tile_image(&img);

    assert_eq!(vec[0], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel1() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel2() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(40, 16);

    let vec = tile_image(&img);

    assert_eq!(vec[6720], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_random_pixel3() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(15, 7);

    let vec = tile_image(&img);

    assert_eq!(vec[127], pixel);
}

#[cfg(test)]
#[test]
fn test_tile_image_last_pixel() {
    let img = image::open(&Path::new("/home/hugh/Pictures/project.jpg")).unwrap();

    let pixel = img.get_pixel(399, 399);

    let vec = tile_image(&img);

    assert_eq!(vec[159999], pixel);
}
<|endoftext|>