<commit_before>pub trait Property {
    fn inherits_automatically() -> bool;
}

/// Generates a property definition that simply parses strings to enum variants
/// or to a tuple struct of the given type.
///
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```
/// make_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, where
/// `type Data = ()` and `type Err = AttributeError`.
#[macro_export]
macro_rules! make_property {
    ($name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     identifiers:
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        pub enum $name {
            $($variant),+
        }

        impl Default for $name {
            fn default() -> $name {
                $name::$default
            }
        }

        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }

        impl ::parsers::Parse for $name {
            type Data = ();
            type Err = ::error::AttributeError;

            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
                match s.trim() {
                    $($str_prop => Ok($name::$variant),)+

                    _ => Err(::error::AttributeError::from(::parsers::ParseError::new("invalid value"))),
                }
            }
        }
    };

    ($name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype_from_str: $type: ty
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl Default for $name {
            fn default() -> $name {
                $name($default)
            }
        }

        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }

        impl ::parsers::Parse for $name {
            type Data = ();
            type Err = ::error::AttributeError;

            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
                s.trim()
                    .parse()
                    .map(|val| $name(val))
                    .map_err(|_| ::error::AttributeError::from(
                        ::parsers::ParseError::new("parse error")
                    ))
            }
        }
    };

    ($name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype: $type: ty
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl Default for $name {
            fn default() -> $name {
                $name($default)
            }
        }

        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }
    };

    ($name: ident,
     inherits_automatically: $inherits_automatically: expr,
     fields:
     $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name {
            $(pub $field_name: $field_type),+
        }

        impl Default for $name {
            fn default() -> $name {
                $name {
                    $($field_name: $field_default),+
                }
            }
        }

        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }
    };
}

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

    use parsers::Parse;

    #[test]
    fn check_generated_property() {
        make_property! {
            Foo,
            default: Def,
            inherits_automatically: true,

            identifiers:
            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property>::inherits_automatically(), true);
        assert!(<Foo as Parse>::parse("blargh", ()).is_err());
        assert_eq!(<Foo as Parse>::parse("bar", ()), Ok(Foo::Bar));

        make_property! {
            Bar,
            default: "bar".to_string(),
            inherits_automatically: true,
            newtype_from_str: String
        }

        assert_eq!(<Bar as Default>::default(), Bar("bar".to_string()));
        assert_eq!(<Bar as Property>::inherits_automatically(), true);
        assert_eq!(
            <Bar as Parse>::parse("test", ()),
            Ok(Bar("test".to_string()))
        );

        make_property! {
            Baz,
            default: 42f64,
            inherits_automatically: true,
            newtype_from_str: f64
        }

        assert_eq!(<Baz as Default>::default(), Baz(42f64));
        assert_eq!(<Baz as Property>::inherits_automatically(), true);
        assert_eq!(<Baz as Parse>::parse("42", ()), Ok(Baz(42f64)));
    }
}
<commit_msg>property_macros: factor out duplicated code<commit_after>pub trait Property {
    fn inherits_automatically() -> bool;
}

/// Generates a property definition that simply parses strings to enum variants
/// or to a tuple struct of the given type.
///
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```
/// make_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, where
/// `type Data = ()` and `type Err = AttributeError`.
#[macro_export]
macro_rules! make_property {
    ($name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     identifiers:
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        pub enum $name {
            $($variant),+
        }

        impl_default!($name, $name::$default);
        impl_property!($name, $inherits_automatically);

        impl ::parsers::Parse for $name {
            type Data = ();
            type Err = ::error::AttributeError;

            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
                match s.trim() {
                    $($str_prop => Ok($name::$variant),)+

                    _ => Err(::error::AttributeError::from(::parsers::ParseError::new("invalid value"))),
                }
            }
        }
    };

    ($name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype_from_str: $type: ty
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($name, $inherits_automatically);

        impl ::parsers::Parse for $name {
            type Data = ();
            type Err = ::error::AttributeError;

            fn parse(s: &str, _: Self::Data) -> Result<$name, ::error::AttributeError> {
                s.trim()
                    .parse()
                    .map(|val| $name(val))
                    .map_err(|_| ::error::AttributeError::from(
                        ::parsers::ParseError::new("parse error")
                    ))
            }
        }
    };

    ($name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype: $type: ty
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($name, $inherits_automatically);
    };

    ($name: ident,
     inherits_automatically: $inherits_automatically: expr,
     fields:
     $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name {
            $(pub $field_name: $field_type),+
        }

        impl_default!($name, $name { $($field_name: $field_default),+ });
        impl_property!($name, $inherits_automatically);
    };
}

macro_rules! impl_default {
    ($name: ident, $default: expr) => {
        impl Default for $name {
            fn default() -> $name {
                $default
            }
        }
    };
}

macro_rules! impl_property {
    ($name: ident, $inherits_automatically: expr) => {
        impl ::property_macros::Property for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }
        }
    };
}

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

    use parsers::Parse;

    #[test]
    fn check_generated_property() {
        make_property! {
            Foo,
            default: Def,
            inherits_automatically: true,

            identifiers:
            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property>::inherits_automatically(), true);
        assert!(<Foo as Parse>::parse("blargh", ()).is_err());
        assert_eq!(<Foo as Parse>::parse("bar", ()), Ok(Foo::Bar));

        make_property! {
            Bar,
            default: "bar".to_string(),
            inherits_automatically: true,
            newtype_from_str: String
        }

        assert_eq!(<Bar as Default>::default(), Bar("bar".to_string()));
        assert_eq!(<Bar as Property>::inherits_automatically(), true);
        assert_eq!(
            <Bar as Parse>::parse("test", ()),
            Ok(Bar("test".to_string()))
        );

        make_property! {
            Baz,
            default: 42f64,
            inherits_automatically: true,
            newtype_from_str: f64
        }

        assert_eq!(<Baz as Default>::default(), Baz(42f64));
        assert_eq!(<Baz as Property>::inherits_automatically(), true);
        assert_eq!(<Baz as Parse>::parse("42", ()), Ok(Baz(42f64)));
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;

use driver::cmd::Args;
use error::diag::Diagnostic;

use parser::ast::*;
use parser::ast::map::Map;
use parser::interner::*;

use sym::*;
use sym::Sym::*;

pub struct Context<'a, 'ast> where 'ast: 'a {
    pub args: &'a Args,
    pub interner: &'a Interner,
    pub map: &'a Map<'ast>,
    pub ast: &'a Ast,
    pub diag: RefCell<Diagnostic>,
    pub sym: RefCell<SymTable>,

    // points to the definition of variable from its usage
    pub defs: RefCell<HashMap<NodeId, VarInfoId>>,

    // maps function call to FctInfoId
    pub calls: RefCell<HashMap<NodeId, FctInfoId>>,

    // stores all function definitions
    pub fct_infos: RefCell<Vec<FctInfo<'ast>>>,

    // stores all var definitions
    pub var_infos: RefCell<Vec<VarInfo>>,
}

impl<'a, 'ast> Context<'a, 'ast> {
    pub fn new(args: &'a Args, interner: &'a Interner,
           map: &'a Map<'ast>, ast: &'a Ast) -> Context<'a, 'ast> {
        Context {
            args: args,
            interner: interner,
            map: map,
            ast: ast,
            diag: RefCell::new(Diagnostic::new()),
            sym: RefCell::new(SymTable::new()),
            defs: RefCell::new(HashMap::new()),
            calls: RefCell::new(HashMap::new()),
            fct_infos: RefCell::new(Vec::new()),
            var_infos: RefCell::new(Vec::new()),
        }
    }

    pub fn add_function(&self, fct_info: FctInfo<'ast>) -> Result<FctInfoId, Sym> {
        let name = fct_info.name;
        let fctid = FctInfoId(self.fct_infos.borrow().len());

        if let Some(ast) = fct_info.ast {
            assert!(self.calls.borrow_mut().insert(ast.id, fctid).is_none());
        }

        self.fct_infos.borrow_mut().push(fct_info);

        // TODO: replace insert with entry
        match self.sym.borrow_mut().insert(name, SymFunction(fctid)) {
            Some(sym) => Err(sym),
            None => Ok(fctid),
        }
    }

    pub fn add_var<F>(&self, var_info: VarInfo, replacable: F) ->
            Result<VarInfoId, Sym> where F: FnOnce(&Sym) -> bool {
        let name = var_info.name;
        let varid = VarInfoId(self.var_infos.borrow().len());

        let result = match self.sym.borrow().get(name) {
            Some(sym) => if replacable(&sym) { Ok(varid) } else { Err(sym) },
            None => Ok(varid)
        };

        if result.is_ok() {
            self.sym.borrow_mut().insert(name, SymVar(varid));
            assert!(self.defs.borrow_mut().insert(var_info.node_id, varid).is_none());
            self.var_infos.borrow_mut().push(var_info);
        }

        result
    }

    pub fn function<F, R>(&self, id: NodeId, f: F) -> R where F: FnOnce(&mut FctInfo<'ast>) -> R {
        let map = self.calls.borrow();
        let fctid = *map.get(&id).unwrap();

        let mut fct_infos = self.fct_infos.borrow_mut();
        f(&mut fct_infos[fctid.0])
    }

    pub fn var<F, R>(&self, id: NodeId, f: F) -> R where F: FnOnce(&mut VarInfo) -> R {
        let defs = self.defs.borrow();
        let varid = *defs.get(&id).unwrap();

        let mut var_infos = self.var_infos.borrow_mut();
        f(&mut var_infos[varid.0])
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct FctInfoId(pub usize);

#[derive(Debug)]
pub struct FctInfo<'ast> {
    pub name: Name,
    pub params_types: Vec<BuiltinType>,
    pub return_type: BuiltinType,
    pub ast: Option<&'ast Function>,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct VarInfoId(pub usize);

#[derive(Debug)]
pub struct VarInfo {
    pub name: Name,
    pub data_type: BuiltinType,
    pub node_id: NodeId,
}
<commit_msg>ctxt: don't use insert for add_function<commit_after>use std::cell::RefCell;
use std::collections::HashMap;

use driver::cmd::Args;
use error::diag::Diagnostic;

use parser::ast::*;
use parser::ast::map::Map;
use parser::interner::*;

use sym::*;
use sym::Sym::*;

pub struct Context<'a, 'ast> where 'ast: 'a {
    pub args: &'a Args,
    pub interner: &'a Interner,
    pub map: &'a Map<'ast>,
    pub ast: &'a Ast,
    pub diag: RefCell<Diagnostic>,
    pub sym: RefCell<SymTable>,

    // points to the definition of variable from its usage
    pub defs: RefCell<HashMap<NodeId, VarInfoId>>,

    // maps function call to FctInfoId
    pub calls: RefCell<HashMap<NodeId, FctInfoId>>,

    // stores all function definitions
    pub fct_infos: RefCell<Vec<FctInfo<'ast>>>,

    // stores all var definitions
    pub var_infos: RefCell<Vec<VarInfo>>,
}

impl<'a, 'ast> Context<'a, 'ast> {
    pub fn new(args: &'a Args, interner: &'a Interner,
           map: &'a Map<'ast>, ast: &'a Ast) -> Context<'a, 'ast> {
        Context {
            args: args,
            interner: interner,
            map: map,
            ast: ast,
            diag: RefCell::new(Diagnostic::new()),
            sym: RefCell::new(SymTable::new()),
            defs: RefCell::new(HashMap::new()),
            calls: RefCell::new(HashMap::new()),
            fct_infos: RefCell::new(Vec::new()),
            var_infos: RefCell::new(Vec::new()),
        }
    }

    pub fn add_function(&self, fct_info: FctInfo<'ast>) -> Result<FctInfoId, Sym> {
        let name = fct_info.name;
        let fctid = FctInfoId(self.fct_infos.borrow().len());

        if let Some(ast) = fct_info.ast {
            assert!(self.calls.borrow_mut().insert(ast.id, fctid).is_none());
        }

        self.fct_infos.borrow_mut().push(fct_info);

        let mut sym = self.sym.borrow_mut();

        match sym.get(name) {
            Some(sym) => Err(sym),
            None => {
                assert!(sym.insert(name, SymFunction(fctid)).is_none());

                Ok(fctid)
            }
        }
    }

    pub fn add_var<F>(&self, var_info: VarInfo, replacable: F) ->
            Result<VarInfoId, Sym> where F: FnOnce(&Sym) -> bool {
        let name = var_info.name;
        let varid = VarInfoId(self.var_infos.borrow().len());

        let result = match self.sym.borrow().get(name) {
            Some(sym) => if replacable(&sym) { Ok(varid) } else { Err(sym) },
            None => Ok(varid)
        };

        if result.is_ok() {
            self.sym.borrow_mut().insert(name, SymVar(varid));
            assert!(self.defs.borrow_mut().insert(var_info.node_id, varid).is_none());
            self.var_infos.borrow_mut().push(var_info);
        }

        result
    }

    pub fn function<F, R>(&self, id: NodeId, f: F) -> R where F: FnOnce(&mut FctInfo<'ast>) -> R {
        let map = self.calls.borrow();
        let fctid = *map.get(&id).unwrap();

        let mut fct_infos = self.fct_infos.borrow_mut();
        f(&mut fct_infos[fctid.0])
    }

    pub fn var<F, R>(&self, id: NodeId, f: F) -> R where F: FnOnce(&mut VarInfo) -> R {
        let defs = self.defs.borrow();
        let varid = *defs.get(&id).unwrap();

        let mut var_infos = self.var_infos.borrow_mut();
        f(&mut var_infos[varid.0])
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct FctInfoId(pub usize);

#[derive(Debug)]
pub struct FctInfo<'ast> {
    pub name: Name,
    pub params_types: Vec<BuiltinType>,
    pub return_type: BuiltinType,
    pub ast: Option<&'ast Function>,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct VarInfoId(pub usize);

#[derive(Debug)]
pub struct VarInfo {
    pub name: Name,
    pub data_type: BuiltinType,
    pub node_id: NodeId,
}
<|endoftext|>


<commit_before>use std::{
    fmt,
    ops::{Deref, DerefMut},
    sync,
};

use crate::gc::{Gc, Trace};

pub use std::sync::{PoisonError, TryLockError};

pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;

pub struct Mutex<T>
where
    T: ?Sized,
{
    // TODO Implement using atomics?
    // `rooted` is always locked first to avoid dead locks
    rooted: sync::Mutex<bool>,
    mutex: sync::Mutex<T>,
}

impl<T> Default for Mutex<T>
where
    T: Default,
{
    fn default() -> Self {
        Mutex::new(Default::default())
    }
}

impl<T> fmt::Debug for Mutex<T>
where
    T: ?Sized + fmt::Debug + Trace,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
            Err(TryLockError::Poisoned(err)) => f
                .debug_struct("Mutex")
                .field("data", &&**err.get_ref())
                .finish(),
            Err(TryLockError::WouldBlock) => {
                struct LockedPlaceholder;
                impl fmt::Debug for LockedPlaceholder {
                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                        f.write_str("<locked>")
                    }
                }

                f.debug_struct("Mutex")
                    .field("data", &LockedPlaceholder)
                    .finish()
            }
        }
    }
}

impl<T> Mutex<T> {
    pub fn new(value: T) -> Self {
        Mutex {
            rooted: sync::Mutex::new(true),
            mutex: sync::Mutex::new(value),
        }
    }
}

impl<T> Mutex<T>
where
    T: ?Sized + Trace,
{
    pub fn lock(&self) -> LockResult<MutexGuard<T>> {
        let rooted = self.rooted.lock().unwrap();
        match self.mutex.lock() {
            Ok(lock) => Ok(self.new_guard(*rooted, lock)),
            Err(err) => {
                let lock = err.into_inner();
                Err(PoisonError::new(self.new_guard(*rooted, lock)))
            }
        }
    }

    pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
        let rooted = self.rooted.lock().unwrap();
        match self.mutex.try_lock() {
            Ok(lock) => Ok(self.new_guard(*rooted, lock)),
            Err(sync::TryLockError::Poisoned(err)) => {
                let lock = err.into_inner();
                Err(TryLockError::Poisoned(PoisonError::new(
                    self.new_guard(*rooted, lock),
                )))
            }
            Err(sync::TryLockError::WouldBlock) => Err(sync::TryLockError::WouldBlock),
        }
    }

    pub fn is_poisoned(&self) -> bool {
        self.mutex.is_poisoned()
    }

    pub fn into_inner(self) -> LockResult<T>
    where
        T: Sized,
    {
        self.mutex.into_inner()
    }

    pub fn get_mut(&mut self) -> LockResult<&mut T> {
        self.mutex.get_mut()
    }

    fn new_guard<'a>(
        &'a self,
        rooted: bool,
        mut value: sync::MutexGuard<'a, T>,
    ) -> MutexGuard<'a, T> {
        if !rooted {
            unsafe {
                value.root();
            }
        }
        MutexGuard {
            value,
            rooted: &self.rooted,
        }
    }
}

unsafe impl<T> Trace for Mutex<T>
where
    T: Trace,
{
    unsafe fn root(&mut self) {
        let mut rooted = self.rooted.lock().unwrap();
        assert!(!*rooted, "Mutex can't be rooted twice!");
        *rooted = true;
        match self.mutex.try_lock() {
            Ok(mut lock) => lock.root(),
            Err(TryLockError::WouldBlock) => (), // The value will be rooted when the lock is released
            Err(TryLockError::Poisoned(err)) => err.into_inner().root(),
        }
    }
    unsafe fn unroot(&mut self) {
        let mut rooted = self.rooted.lock().unwrap();
        assert!(*rooted, "Mutex can't be unrooted twice!");
        *rooted = false;
        match self.mutex.try_lock() {
            Ok(mut lock) => lock.unroot(),
            Err(TryLockError::WouldBlock) => (), // The value will be unrooted when the lock is released
            Err(TryLockError::Poisoned(err)) => err.into_inner().unroot(),
        }
    }
    fn trace(&self, gc: &mut Gc) {
        match self.mutex.try_lock() {
            Ok(lock) => lock.trace(gc),
            Err(TryLockError::WouldBlock) => (), // The value is already rooted so we don't need to do anything here
            Err(TryLockError::Poisoned(err)) => err.into_inner().trace(gc),
        }
    }
}
pub struct MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    rooted: &'a sync::Mutex<bool>,
    value: sync::MutexGuard<'a, T>,
}

impl<'a, T> Drop for MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    fn drop(&mut self) {
        let rooted = self.rooted.lock().unwrap();
        if !*rooted {
            unsafe {
                self.value.unroot();
            }
        }
    }
}

impl<'a, T> Deref for MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

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

    use std::cell::Cell;

    struct Rooted<'a>(&'a Cell<bool>);

    unsafe impl<'a> Trace for Rooted<'a> {
        unsafe fn root(&mut self) {
            assert!(!self.0.get());
            self.0.set(true);
        }
        unsafe fn unroot(&mut self) {
            assert!(self.0.get());
            self.0.set(false);
        }
        fn trace(&self, _gc: &mut Gc) {}
    }

    #[test]
    fn rooted() {
        let rooted = Cell::new(true);
        let mutex = Mutex::new(Rooted(&rooted));

        assert!(rooted.get());
        {
            let _lock = mutex.lock().unwrap();
            assert!(rooted.get());
        }
        assert!(rooted.get());
    }

    #[test]
    fn unrooted() {
        let rooted = Cell::new(true);
        let mut mutex = Mutex::new(Rooted(&rooted));
        // Emulate this `Mutex` being unrooted (stored in another root)
        unsafe {
            mutex.unroot();
        }

        assert!(!rooted.get());
        {
            let _lock = mutex.lock().unwrap();
            assert!(rooted.get());
        }
        assert!(!rooted.get());
    }

    #[test]
    fn unroot_during_lock() {
        let rooted = Cell::new(true);
        let mut mutex = Mutex::new(Rooted(&rooted));

        assert!(rooted.get());
        {
            let _lock = mutex.lock().unwrap();
            assert!(rooted.get());

            // Emulate this `Mutex` being unrooted (stored in another root)
            unsafe {
                mutex.unroot();
            }
            assert!(!*mutex.rooted.lock().unwrap());
            assert!(
                rooted.get(),
                "We should not be able to unroot the inner value since it is locked"
            );
        }
        assert!(!rooted.get(), "Must be unrooted after the lock releases");
    }
}
<commit_msg>Remove test that is now statically prevented<commit_after>use std::{
    fmt,
    ops::{Deref, DerefMut},
    sync,
};

use crate::gc::{Gc, Trace};

pub use std::sync::{PoisonError, TryLockError};

pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;

pub struct Mutex<T>
where
    T: ?Sized,
{
    // TODO Implement using atomics?
    // `rooted` is always locked first to avoid dead locks
    rooted: sync::Mutex<bool>,
    mutex: sync::Mutex<T>,
}

impl<T> Default for Mutex<T>
where
    T: Default,
{
    fn default() -> Self {
        Mutex::new(Default::default())
    }
}

impl<T> fmt::Debug for Mutex<T>
where
    T: ?Sized + fmt::Debug + Trace,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
            Err(TryLockError::Poisoned(err)) => f
                .debug_struct("Mutex")
                .field("data", &&**err.get_ref())
                .finish(),
            Err(TryLockError::WouldBlock) => {
                struct LockedPlaceholder;
                impl fmt::Debug for LockedPlaceholder {
                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                        f.write_str("<locked>")
                    }
                }

                f.debug_struct("Mutex")
                    .field("data", &LockedPlaceholder)
                    .finish()
            }
        }
    }
}

impl<T> Mutex<T> {
    pub fn new(value: T) -> Self {
        Mutex {
            rooted: sync::Mutex::new(true),
            mutex: sync::Mutex::new(value),
        }
    }
}

impl<T> Mutex<T>
where
    T: ?Sized + Trace,
{
    pub fn lock(&self) -> LockResult<MutexGuard<T>> {
        let rooted = self.rooted.lock().unwrap();
        match self.mutex.lock() {
            Ok(lock) => Ok(self.new_guard(*rooted, lock)),
            Err(err) => {
                let lock = err.into_inner();
                Err(PoisonError::new(self.new_guard(*rooted, lock)))
            }
        }
    }

    pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
        let rooted = self.rooted.lock().unwrap();
        match self.mutex.try_lock() {
            Ok(lock) => Ok(self.new_guard(*rooted, lock)),
            Err(sync::TryLockError::Poisoned(err)) => {
                let lock = err.into_inner();
                Err(TryLockError::Poisoned(PoisonError::new(
                    self.new_guard(*rooted, lock),
                )))
            }
            Err(sync::TryLockError::WouldBlock) => Err(sync::TryLockError::WouldBlock),
        }
    }

    pub fn is_poisoned(&self) -> bool {
        self.mutex.is_poisoned()
    }

    pub fn into_inner(self) -> LockResult<T>
    where
        T: Sized,
    {
        self.mutex.into_inner()
    }

    pub fn get_mut(&mut self) -> LockResult<&mut T> {
        self.mutex.get_mut()
    }

    fn new_guard<'a>(
        &'a self,
        rooted: bool,
        mut value: sync::MutexGuard<'a, T>,
    ) -> MutexGuard<'a, T> {
        if !rooted {
            unsafe {
                value.root();
            }
        }
        MutexGuard {
            value,
            rooted: &self.rooted,
        }
    }
}

unsafe impl<T> Trace for Mutex<T>
where
    T: Trace,
{
    unsafe fn root(&mut self) {
        let mut rooted = self.rooted.lock().unwrap();
        assert!(!*rooted, "Mutex can't be rooted twice!");
        *rooted = true;
        match self.mutex.try_lock() {
            Ok(mut lock) => lock.root(),
            Err(TryLockError::WouldBlock) => (), // The value will be rooted when the lock is released
            Err(TryLockError::Poisoned(err)) => err.into_inner().root(),
        }
    }
    unsafe fn unroot(&mut self) {
        let mut rooted = self.rooted.lock().unwrap();
        assert!(*rooted, "Mutex can't be unrooted twice!");
        *rooted = false;
        match self.mutex.try_lock() {
            Ok(mut lock) => lock.unroot(),
            Err(TryLockError::WouldBlock) => (), // The value will be unrooted when the lock is released
            Err(TryLockError::Poisoned(err)) => err.into_inner().unroot(),
        }
    }
    fn trace(&self, gc: &mut Gc) {
        match self.mutex.try_lock() {
            Ok(lock) => lock.trace(gc),
            Err(TryLockError::WouldBlock) => (), // The value is already rooted so we don't need to do anything here
            Err(TryLockError::Poisoned(err)) => err.into_inner().trace(gc),
        }
    }
}
pub struct MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    rooted: &'a sync::Mutex<bool>,
    value: sync::MutexGuard<'a, T>,
}

impl<'a, T> Drop for MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    fn drop(&mut self) {
        let rooted = self.rooted.lock().unwrap();
        if !*rooted {
            unsafe {
                self.value.unroot();
            }
        }
    }
}

impl<'a, T> Deref for MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T>
where
    T: ?Sized + Trace,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

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

    use std::cell::Cell;

    struct Rooted<'a>(&'a Cell<bool>);

    unsafe impl<'a> Trace for Rooted<'a> {
        unsafe fn root(&mut self) {
            assert!(!self.0.get());
            self.0.set(true);
        }
        unsafe fn unroot(&mut self) {
            assert!(self.0.get());
            self.0.set(false);
        }
        fn trace(&self, _gc: &mut Gc) {}
    }

    #[test]
    fn rooted() {
        let rooted = Cell::new(true);
        let mutex = Mutex::new(Rooted(&rooted));

        assert!(rooted.get());
        {
            let _lock = mutex.lock().unwrap();
            assert!(rooted.get());
        }
        assert!(rooted.get());
    }

    #[test]
    fn unrooted() {
        let rooted = Cell::new(true);
        let mut mutex = Mutex::new(Rooted(&rooted));
        // Emulate this `Mutex` being unrooted (stored in another root)
        unsafe {
            mutex.unroot();
        }

        assert!(!rooted.get());
        {
            let _lock = mutex.lock().unwrap();
            assert!(rooted.get());
        }
        assert!(!rooted.get());
    }
}
<|endoftext|>


<commit_before>//! Draw rectangle

use internal;
use triangulation;
use Graphics;
use Color;
use DrawState;
use math::Matrix2d;

pub use math::margin_rectangle as margin;

/// Use x, y, half-width, half-height
pub fn centered(rect: internal::Rectangle) -> internal::Rectangle {
    [rect[0] - rect[2], rect[1] - rect[3], 2.0 * rect[2], 2.0 * rect[3]]
}

/// Use centered square
pub fn centered_square(
    x: internal::Scalar,
    y: internal::Scalar,
    radius: internal::Scalar
) -> internal::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Use square with x, y in upper left corner
pub fn square(
    x: internal::Scalar,
    y: internal::Scalar,
    size: internal::Scalar
) -> internal::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners
    Round(internal::Radius),
    /// Bevel corners
    Bevel(internal::Radius),
}

/// The border of the rectangle
#[derive(Copy, Clone)]
pub struct Border {
    /// The color of the border
    pub color: internal::Color,
    /// The radius of the border
    pub radius: internal::Radius,
}

/// Maybe border property
#[derive(Copy, Clone)]
pub struct MaybeBorder(pub Option<Border>);

/// A filled rectangle
#[derive(Copy, Clone)]
pub struct Rectangle {
    /// The rectangle color
    pub color: internal::Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: internal::Color) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new round rectangle.
    pub fn new_round(
        color: internal::Color,
        round_radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Round(round_radius),
            border: None
        }
    }

    /// Creates a new rectangle border.
    pub fn border(
        color: internal::Color,
        radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Square,
            border: Some(Border {
                    color: color,
                    radius: radius
                })
        }
    }

    /// Creates a new round rectangle border.
    pub fn round_border(
        color: internal::Color,
        round_radius: internal::Radius,
        border_radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Round(round_radius),
            border: Some(Border {
                    color: color,
                    radius: border_radius
                })
        }
    }

    /// Draws the rectangle
    pub fn draw<G>(
        &self,
        rectangle: internal::Rectangle,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        if self.color[3] != 0.0 {
            match self.shape {
                Shape::Square => {
                    g.tri_list(
                        draw_state,
                        &self.color,
                        |f|
                            f(&triangulation::rect_tri_list_xy(
                                transform,
                                rectangle
                            )),
                    );
                }
                Shape::Round(round_radius) => {
                    g.tri_list(
                        draw_state,
                        &self.color,
                        |f|
                    triangulation::with_round_rectangle_tri_list(
                        32,
                        transform,
                        rectangle,
                        round_radius,
                        |vertices| f(vertices)
                    ));
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(
                        draw_state,
                        &self.color,
                        |f|
                    triangulation::with_round_rectangle_tri_list(
                        2,
                        transform,
                        rectangle,
                        bevel_radius,
                        |vertices| f(vertices)
                    ));
                }
            }
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 { return; }
            match self.shape {
                Shape::Square => {
                    g.tri_list(
                        draw_state,
                        &color,
                        |f| f(
                            &triangulation::rect_border_tri_list_xy(
                                transform, rectangle, border_radius),
                        )
                    );
                }
                Shape::Round(round_radius) => {
                    g.tri_list(
                        draw_state,
                        &color,
                        |f|
                    triangulation::with_round_rectangle_border_tri_list(
                        128,
                        transform,
                        rectangle,
                        round_radius,
                        border_radius,
                        |vertices| f(vertices)
                    ));
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(
                        draw_state,
                        &color,
                        |f|
                    triangulation::with_round_rectangle_border_tri_list(
                        2,
                        transform,
                        rectangle,
                        bevel_radius,
                        border_radius,
                        |vertices| f(vertices)
                    ));
                }
            }
        }
    }
}

/*
quack! {
    r: Rectangle[]
    get:
        fn () -> Color [] { Color(r.color) }
        fn () -> Shape [] { r.shape }
        fn () -> MaybeBorder [] { MaybeBorder(r.border) }
    set:
        fn (val: Color) [] { r.color = val.0 }
        fn (val: Shape) [] { r.shape = val }
        fn (val: Border) [] { r.border = Some(val) }
        fn (val: MaybeBorder) [] { r.border = val.0 }
    action:
}
*/

#[cfg(test)]
mod test {
    use super::Rectangle;
    use super::Shape;
    use super::Border;
    use Color;

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0; 4])
            .set(Color([0.0; 4]))
            .set(Shape::Round(10.0))
            .set(Border { color: [0.0; 4], radius: 4.0 });
    }
}
<commit_msg>Renamed `Rectangle::border` to `Rectangle::new_border`<commit_after>//! Draw rectangle

use internal;
use triangulation;
use Graphics;
use Color;
use DrawState;
use math::Matrix2d;

pub use math::margin_rectangle as margin;

/// Use x, y, half-width, half-height
pub fn centered(rect: internal::Rectangle) -> internal::Rectangle {
    [rect[0] - rect[2], rect[1] - rect[3], 2.0 * rect[2], 2.0 * rect[3]]
}

/// Use centered square
pub fn centered_square(
    x: internal::Scalar,
    y: internal::Scalar,
    radius: internal::Scalar
) -> internal::Rectangle {
    [x - radius, y - radius, 2.0 * radius, 2.0 * radius]
}

/// Use square with x, y in upper left corner
pub fn square(
    x: internal::Scalar,
    y: internal::Scalar,
    size: internal::Scalar
) -> internal::Rectangle {
    [x, y, size, size]
}

/// The shape of the rectangle
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square corners
    Square,
    /// Round corners
    Round(internal::Radius),
    /// Bevel corners
    Bevel(internal::Radius),
}

/// The border of the rectangle
#[derive(Copy, Clone)]
pub struct Border {
    /// The color of the border
    pub color: internal::Color,
    /// The radius of the border
    pub radius: internal::Radius,
}

/// Maybe border property
#[derive(Copy, Clone)]
pub struct MaybeBorder(pub Option<Border>);

/// A filled rectangle
#[derive(Copy, Clone)]
pub struct Rectangle {
    /// The rectangle color
    pub color: internal::Color,
    /// The roundness of the rectangle
    pub shape: Shape,
    /// The border
    pub border: Option<Border>,
}

impl Rectangle {
    /// Creates a new rectangle.
    pub fn new(color: internal::Color) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Square,
            border: None,
        }
    }

    /// Creates a new round rectangle.
    pub fn new_round(
        color: internal::Color,
        round_radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: color,
            shape: Shape::Round(round_radius),
            border: None
        }
    }

    /// Creates a new rectangle border.
    pub fn new_border(
        color: internal::Color,
        radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Square,
            border: Some(Border {
                    color: color,
                    radius: radius
                })
        }
    }

    /// Creates a new round rectangle border.
    pub fn round_border(
        color: internal::Color,
        round_radius: internal::Radius,
        border_radius: internal::Radius
    ) -> Rectangle {
        Rectangle {
            color: [0.0; 4],
            shape: Shape::Round(round_radius),
            border: Some(Border {
                    color: color,
                    radius: border_radius
                })
        }
    }

    /// Draws the rectangle
    pub fn draw<G>(
        &self,
        rectangle: internal::Rectangle,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        if self.color[3] != 0.0 {
            match self.shape {
                Shape::Square => {
                    g.tri_list(
                        draw_state,
                        &self.color,
                        |f|
                            f(&triangulation::rect_tri_list_xy(
                                transform,
                                rectangle
                            )),
                    );
                }
                Shape::Round(round_radius) => {
                    g.tri_list(
                        draw_state,
                        &self.color,
                        |f|
                    triangulation::with_round_rectangle_tri_list(
                        32,
                        transform,
                        rectangle,
                        round_radius,
                        |vertices| f(vertices)
                    ));
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(
                        draw_state,
                        &self.color,
                        |f|
                    triangulation::with_round_rectangle_tri_list(
                        2,
                        transform,
                        rectangle,
                        bevel_radius,
                        |vertices| f(vertices)
                    ));
                }
            }
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 { return; }
            match self.shape {
                Shape::Square => {
                    g.tri_list(
                        draw_state,
                        &color,
                        |f| f(
                            &triangulation::rect_border_tri_list_xy(
                                transform, rectangle, border_radius),
                        )
                    );
                }
                Shape::Round(round_radius) => {
                    g.tri_list(
                        draw_state,
                        &color,
                        |f|
                    triangulation::with_round_rectangle_border_tri_list(
                        128,
                        transform,
                        rectangle,
                        round_radius,
                        border_radius,
                        |vertices| f(vertices)
                    ));
                }
                Shape::Bevel(bevel_radius) => {
                    g.tri_list(
                        draw_state,
                        &color,
                        |f|
                    triangulation::with_round_rectangle_border_tri_list(
                        2,
                        transform,
                        rectangle,
                        bevel_radius,
                        border_radius,
                        |vertices| f(vertices)
                    ));
                }
            }
        }
    }
}

/*
quack! {
    r: Rectangle[]
    get:
        fn () -> Color [] { Color(r.color) }
        fn () -> Shape [] { r.shape }
        fn () -> MaybeBorder [] { MaybeBorder(r.border) }
    set:
        fn (val: Color) [] { r.color = val.0 }
        fn (val: Shape) [] { r.shape = val }
        fn (val: Border) [] { r.border = Some(val) }
        fn (val: MaybeBorder) [] { r.border = val.0 }
    action:
}
*/

#[cfg(test)]
mod test {
    use super::Rectangle;
    use super::Shape;
    use super::Border;
    use Color;

    #[test]
    fn test_rectangle() {
        let _rectangle = Rectangle::new([1.0; 4])
            .set(Color([0.0; 4]))
            .set(Shape::Round(10.0))
            .set(Border { color: [0.0; 4], radius: 4.0 });
    }
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` orders will not fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator. The default is `Normal`.
pub const EVALUATION_ORDER: Order = Normal;

/// The available variants of β-reduction evaluation order.
#[derive(Debug, PartialEq)]
pub enum Order {
    /// leftmost outermost
    Normal,
    /// leftmost innermost
    ApplicativeLeft,
    /// rightmost innermost
    ApplicativeRight
}

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        match EVALUATION_ORDER {
            Normal => self._beta_once_normal(0),
            ApplicativeLeft => self._beta_once_applicative_l(0),
            ApplicativeRight => self._beta_once_applicative_r(0)
        };
    }

    fn reduce(&mut self, depth: u32) {
        let copy = self.clone();
        if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
        *self = copy.eval().unwrap();
        if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.reduce(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_normal(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative_l(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative_l(depth + 1),
            App(_, _) => {
                if !self.lhs_ref().unwrap().is_beta_reducible() &&
                   !self.rhs_ref().unwrap().is_beta_reducible() &&
                    self.lhs_ref().unwrap().unabs_ref().is_ok()
                {
                    self.reduce(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_applicative_l(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_applicative_l(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative_r(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative_r(depth + 1),
            App(_, _) => {
                if !self.rhs_ref().unwrap().is_beta_reducible() &&
                   !self.lhs_ref().unwrap().is_beta_reducible() &&
                    self.lhs_ref().unwrap().unabs_ref().is_ok()
                {
                    self.reduce(depth);
                    true
                } else {
                    self.rhs_ref_mut().unwrap()._beta_once_applicative_r(depth) ||
                    self.lhs_ref_mut().unwrap()._beta_once_applicative_r(depth)
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible());
    /// assert!(!not_reducible.is_beta_reducible());
    /// ```
    pub fn is_beta_reducible(&self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref().unwrap().is_beta_reducible(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible() ||
                    self.rhs_ref().unwrap().is_beta_reducible()
                }
            }
        }
    }

    /// Performs full β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

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

    #[test]
    fn evaluation_order() {
        match EVALUATION_ORDER {
            Normal => {
                let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(beta_full(should_reduce), Var(1))
            },
            ApplicativeLeft => {
                let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
                assert_eq!(&format!("{}", beta_once(expr)), "λ1((λλ1)((λλ21)1))");

                let shouldnt_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(&format!("{}", beta_once(shouldnt_reduce)), "(λ2)((λ111)(λ111)(λ111))")
            },
            ApplicativeRight => {
                let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
                assert_eq!(&format!("{}", beta_once(expr)), "λ1((λλλ1)1(λ21))");

                let shouldnt_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(&format!("{}", beta_once(shouldnt_reduce)), "(λ2)((λ111)(λ111)(λ111))")
            }
        }
    }
}
<commit_msg>improve evaluation order tests<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` orders will not fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator. The default is `Normal`.
pub const EVALUATION_ORDER: Order = Normal;

/// The available variants of β-reduction evaluation order.
#[derive(Debug, PartialEq)]
pub enum Order {
    /// leftmost outermost
    Normal,
    /// leftmost innermost
    ApplicativeLeft,
    /// rightmost innermost
    ApplicativeRight
}

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        match EVALUATION_ORDER {
            Normal => self._beta_once_normal(0),
            ApplicativeLeft => self._beta_once_applicative_l(0),
            ApplicativeRight => self._beta_once_applicative_r(0)
        };
    }

    fn reduce(&mut self, depth: u32) {
        let copy = self.clone();
        if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
        *self = copy.eval().unwrap();
        if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.reduce(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_normal(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative_l(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative_l(depth + 1),
            App(_, _) => {
                if !self.lhs_ref().unwrap().is_beta_reducible() &&
                   !self.rhs_ref().unwrap().is_beta_reducible() &&
                    self.lhs_ref().unwrap().unabs_ref().is_ok()
                {
                    self.reduce(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_applicative_l(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_applicative_l(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative_r(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative_r(depth + 1),
            App(_, _) => {
                if !self.rhs_ref().unwrap().is_beta_reducible() &&
                   !self.lhs_ref().unwrap().is_beta_reducible() &&
                    self.lhs_ref().unwrap().unabs_ref().is_ok()
                {
                    self.reduce(depth);
                    true
                } else {
                    self.rhs_ref_mut().unwrap()._beta_once_applicative_r(depth) ||
                    self.lhs_ref_mut().unwrap()._beta_once_applicative_r(depth)
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible());
    /// assert!(!not_reducible.is_beta_reducible());
    /// ```
    pub fn is_beta_reducible(&self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref().unwrap().is_beta_reducible(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible() ||
                    self.rhs_ref().unwrap().is_beta_reducible()
                }
            }
        }
    }

    /// Performs full β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

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

    #[test]
    fn evaluation_order() {
        match EVALUATION_ORDER {
            Normal => {
                let reduces_instantly = parse(&"(λλ1)((λλλ((32)1))(λλ2))").unwrap();
                assert_eq!(beta_full(reduces_instantly.clone()), beta_once(reduces_instantly));

                let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(beta_full(should_reduce), Var(1))
            },
            ApplicativeLeft => {
                let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
                assert_eq!(&format!("{}", beta_once(expr)), "λ1((λλ1)((λλ21)1))");

                let expands = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(&format!("{}", beta_once(expands)), "(λ2)((λ111)(λ111)(λ111))")
            },
            ApplicativeRight => {
                let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
                assert_eq!(&format!("{}", beta_once(expr)), "λ1((λλλ1)1(λ21))");

                let expands = parse(&"(λ2)((λ111)(λ111))").unwrap();
                assert_eq!(&format!("{}", beta_once(expands)), "(λ2)((λ111)(λ111)(λ111))")
            }
        }
    }
}
<|endoftext|>


<commit_before>// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Network message
//!
//! This module defines the `Message` traits which are used
//! for (de)serializing Bitcoin objects for transmission on the network. It
//! also defines (de)serialization routines for many primitives.
//!

use std::iter;
use std::io::Cursor;
use std::sync::mpsc::Sender;

use blockdata::block;
use blockdata::transaction;
use network::address::Address;
use network::message_network;
use network::message_blockdata;
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::encodable::CheckedData;
use network::serialize::{serialize, RawDecoder, SimpleEncoder, SimpleDecoder};
use util::{self, propagate_err};

/// Serializer for command string
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct CommandString(pub String);

impl<S: SimpleEncoder> ConsensusEncodable<S> for CommandString {
    #[inline]
    fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
        let &CommandString(ref inner_str) = self;
        let mut rawbytes = [0u8; 12];
        let strbytes = inner_str.as_bytes();
        if strbytes.len() > 12 {
            panic!("Command string longer than 12 bytes");
        }
        for x in 0..strbytes.len() {
            rawbytes[x] = strbytes[x];
        }
        rawbytes.consensus_encode(s)
    }
}

impl<D: SimpleDecoder> ConsensusDecodable<D> for CommandString {
    #[inline]
    fn consensus_decode(d: &mut D) -> Result<CommandString, D::Error> {
        let rawbytes: [u8; 12] = try!(ConsensusDecodable::consensus_decode(d));
        let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
        Ok(CommandString(rv))
    }
}

/// A Network message
pub struct RawNetworkMessage {
    /// Magic bytes to identify the network these messages are meant for
    pub magic: u32,
    /// The actual message data
    pub payload: NetworkMessage
}

/// A response from the peer-connected socket
pub enum SocketResponse {
    /// A message was received
    MessageReceived(NetworkMessage),
    /// An error occured and the socket needs to close
    ConnectionFailed(util::Error, Sender<()>)
}

#[derive(Clone, PartialEq, Eq, Debug)]
/// A Network message payload. Proper documentation is available on at
/// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification)
pub enum NetworkMessage {
    /// `version`
    Version(message_network::VersionMessage),
    /// `verack`
    Verack,
    /// `addr`
    Addr(Vec<(u32, Address)>),
    /// `inv`
    Inv(Vec<message_blockdata::Inventory>),
    /// `getdata`
    GetData(Vec<message_blockdata::Inventory>),
    /// `notfound`
    NotFound(Vec<message_blockdata::Inventory>),
    /// `getblocks`
    GetBlocks(message_blockdata::GetBlocksMessage),
    /// `getheaders`
    GetHeaders(message_blockdata::GetHeadersMessage),
    /// `mempool`
    MemPool,
    /// tx
    Tx(transaction::Transaction),
    /// `block`
    Block(block::Block),
    /// `headers`
    Headers(Vec<block::LoneBlockHeader>),
    // TODO: getaddr,
    // TODO: checkorder,
    // TODO: submitorder,
    // TODO: reply,
    /// `ping`
    Ping(u64),
    /// `pong`
    Pong(u64)
    // TODO: reject,
    // TODO: bloom filtering
    // TODO: alert
}

impl RawNetworkMessage {
    fn command(&self) -> String {
        match self.payload {
            NetworkMessage::Version(_) => "version",
            NetworkMessage::Verack     => "verack",
            NetworkMessage::Addr(_)    => "addr",
            NetworkMessage::Inv(_)     => "inv",
            NetworkMessage::GetData(_) => "getdata",
            NetworkMessage::NotFound(_) => "notfound",
            NetworkMessage::GetBlocks(_) => "getblocks",
            NetworkMessage::GetHeaders(_) => "getheaders",
            NetworkMessage::MemPool    => "mempool",
            NetworkMessage::Tx(_)      => "tx",
            NetworkMessage::Block(_)   => "block",
            NetworkMessage::Headers(_) => "headers",
            NetworkMessage::Ping(_)    => "ping",
            NetworkMessage::Pong(_)    => "pong",
        }.to_owned()
    }
}

impl<S: SimpleEncoder> ConsensusEncodable<S> for RawNetworkMessage {
    fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
        try!(self.magic.consensus_encode(s));
        try!(CommandString(self.command()).consensus_encode(s));
        try!(CheckedData(match self.payload {
            NetworkMessage::Version(ref dat) => serialize(dat),
            NetworkMessage::Verack           => Ok(vec![]),
            NetworkMessage::Addr(ref dat)    => serialize(dat),
            NetworkMessage::Inv(ref dat)     => serialize(dat),
            NetworkMessage::GetData(ref dat) => serialize(dat),
            NetworkMessage::NotFound(ref dat) => serialize(dat),
            NetworkMessage::GetBlocks(ref dat) => serialize(dat),
            NetworkMessage::GetHeaders(ref dat) => serialize(dat),
            NetworkMessage::MemPool          => Ok(vec![]),
            NetworkMessage::Tx(ref dat)      => serialize(dat),
            NetworkMessage::Block(ref dat)   => serialize(dat),
            NetworkMessage::Headers(ref dat) => serialize(dat),
            NetworkMessage::Ping(ref dat)    => serialize(dat),
            NetworkMessage::Pong(ref dat)    => serialize(dat),
        }.unwrap()).consensus_encode(s));
        Ok(())
    }
}

// TODO: restriction on D::Error is so that `propagate_err` will work;
//       is there a more generic way to handle this?
impl<D: SimpleDecoder<Error=util::Error>> ConsensusDecodable<D> for RawNetworkMessage {
    fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, D::Error> {
        let magic = try!(ConsensusDecodable::consensus_decode(d));
        let CommandString(cmd): CommandString= try!(ConsensusDecodable::consensus_decode(d));
        let CheckedData(raw_payload): CheckedData = try!(ConsensusDecodable::consensus_decode(d));

        let mut mem_d = RawDecoder::new(Cursor::new(raw_payload));
        let payload = match &cmd[..] {
            "version" => NetworkMessage::Version(try!(propagate_err("version".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "verack"  => NetworkMessage::Verack,
            "addr"    => NetworkMessage::Addr(try!(propagate_err("addr".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "inv"     => NetworkMessage::Inv(try!(propagate_err("inv".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getdata" => NetworkMessage::GetData(try!(propagate_err("getdata".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "notfound" => NetworkMessage::NotFound(try!(propagate_err("notfound".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getblocks" => NetworkMessage::GetBlocks(try!(propagate_err("getblocks".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getheaders" => NetworkMessage::GetHeaders(try!(propagate_err("getheaders".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "mempool" => NetworkMessage::MemPool,
            "block"   => NetworkMessage::Block(try!(propagate_err("block".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "headers" => NetworkMessage::Headers(try!(propagate_err("headers".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "ping"    => NetworkMessage::Ping(try!(propagate_err("ping".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "pong"    => NetworkMessage::Pong(try!(propagate_err("pong".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "tx"      => NetworkMessage::Tx(try!(propagate_err("tx".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd)))
        };
        Ok(RawNetworkMessage {
            magic: magic,
            payload: payload
        })
    }
}

#[cfg(test)]
mod test {
    use super::{RawNetworkMessage, NetworkMessage, CommandString};

    use network::serialize::{deserialize, serialize};

    #[test]
    fn serialize_commandstring_test() {
        let cs = CommandString("Andrew".to_owned());
        assert_eq!(serialize(&cs).ok(), Some(vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]));
    }

    #[test]
    fn deserialize_commandstring_test() {
        let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
        assert!(cs.is_ok());
        assert_eq!(cs.unwrap(), CommandString("Andrew".to_owned()));

        let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
        assert!(short_cs.is_err());
    }

    #[test]
    fn serialize_verack_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
                                       0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
    }

    #[test]
    fn serialize_ping_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
                                       0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
    }

    #[test]
    fn serialize_mempool_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
                                       0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
    }

}
<commit_msg>Add GetAddr message<commit_after>// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Network message
//!
//! This module defines the `Message` traits which are used
//! for (de)serializing Bitcoin objects for transmission on the network. It
//! also defines (de)serialization routines for many primitives.
//!

use std::iter;
use std::io::Cursor;
use std::sync::mpsc::Sender;

use blockdata::block;
use blockdata::transaction;
use network::address::Address;
use network::message_network;
use network::message_blockdata;
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::encodable::CheckedData;
use network::serialize::{serialize, RawDecoder, SimpleEncoder, SimpleDecoder};
use util::{self, propagate_err};

/// Serializer for command string
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct CommandString(pub String);

impl<S: SimpleEncoder> ConsensusEncodable<S> for CommandString {
    #[inline]
    fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
        let &CommandString(ref inner_str) = self;
        let mut rawbytes = [0u8; 12];
        let strbytes = inner_str.as_bytes();
        if strbytes.len() > 12 {
            panic!("Command string longer than 12 bytes");
        }
        for x in 0..strbytes.len() {
            rawbytes[x] = strbytes[x];
        }
        rawbytes.consensus_encode(s)
    }
}

impl<D: SimpleDecoder> ConsensusDecodable<D> for CommandString {
    #[inline]
    fn consensus_decode(d: &mut D) -> Result<CommandString, D::Error> {
        let rawbytes: [u8; 12] = try!(ConsensusDecodable::consensus_decode(d));
        let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
        Ok(CommandString(rv))
    }
}

/// A Network message
pub struct RawNetworkMessage {
    /// Magic bytes to identify the network these messages are meant for
    pub magic: u32,
    /// The actual message data
    pub payload: NetworkMessage
}

/// A response from the peer-connected socket
pub enum SocketResponse {
    /// A message was received
    MessageReceived(NetworkMessage),
    /// An error occured and the socket needs to close
    ConnectionFailed(util::Error, Sender<()>)
}

#[derive(Clone, PartialEq, Eq, Debug)]
/// A Network message payload. Proper documentation is available on at
/// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification)
pub enum NetworkMessage {
    /// `version`
    Version(message_network::VersionMessage),
    /// `verack`
    Verack,
    /// `addr`
    Addr(Vec<(u32, Address)>),
    /// `inv`
    Inv(Vec<message_blockdata::Inventory>),
    /// `getdata`
    GetData(Vec<message_blockdata::Inventory>),
    /// `notfound`
    NotFound(Vec<message_blockdata::Inventory>),
    /// `getblocks`
    GetBlocks(message_blockdata::GetBlocksMessage),
    /// `getheaders`
    GetHeaders(message_blockdata::GetHeadersMessage),
    /// `mempool`
    MemPool,
    /// tx
    Tx(transaction::Transaction),
    /// `block`
    Block(block::Block),
    /// `headers`
    Headers(Vec<block::LoneBlockHeader>),
    /// `getaddr`
    GetAddr,
    // TODO: checkorder,
    // TODO: submitorder,
    // TODO: reply,
    /// `ping`
    Ping(u64),
    /// `pong`
    Pong(u64)
    // TODO: reject,
    // TODO: bloom filtering
    // TODO: alert
}

impl RawNetworkMessage {
    fn command(&self) -> String {
        match self.payload {
            NetworkMessage::Version(_) => "version",
            NetworkMessage::Verack     => "verack",
            NetworkMessage::Addr(_)    => "addr",
            NetworkMessage::Inv(_)     => "inv",
            NetworkMessage::GetData(_) => "getdata",
            NetworkMessage::NotFound(_) => "notfound",
            NetworkMessage::GetBlocks(_) => "getblocks",
            NetworkMessage::GetHeaders(_) => "getheaders",
            NetworkMessage::MemPool    => "mempool",
            NetworkMessage::Tx(_)      => "tx",
            NetworkMessage::Block(_)   => "block",
            NetworkMessage::Headers(_) => "headers",
            NetworkMessage::GetAddr    => "getaddr",
            NetworkMessage::Ping(_)    => "ping",
            NetworkMessage::Pong(_)    => "pong",
        }.to_owned()
    }
}

impl<S: SimpleEncoder> ConsensusEncodable<S> for RawNetworkMessage {
    fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
        try!(self.magic.consensus_encode(s));
        try!(CommandString(self.command()).consensus_encode(s));
        try!(CheckedData(match self.payload {
            NetworkMessage::Version(ref dat) => serialize(dat),
            NetworkMessage::Verack           => Ok(vec![]),
            NetworkMessage::Addr(ref dat)    => serialize(dat),
            NetworkMessage::Inv(ref dat)     => serialize(dat),
            NetworkMessage::GetData(ref dat) => serialize(dat),
            NetworkMessage::NotFound(ref dat) => serialize(dat),
            NetworkMessage::GetBlocks(ref dat) => serialize(dat),
            NetworkMessage::GetHeaders(ref dat) => serialize(dat),
            NetworkMessage::MemPool          => Ok(vec![]),
            NetworkMessage::Tx(ref dat)      => serialize(dat),
            NetworkMessage::Block(ref dat)   => serialize(dat),
            NetworkMessage::Headers(ref dat) => serialize(dat),
            NetworkMessage::GetAddr          => Ok(vec![]),
            NetworkMessage::Ping(ref dat)    => serialize(dat),
            NetworkMessage::Pong(ref dat)    => serialize(dat),
        }.unwrap()).consensus_encode(s));
        Ok(())
    }
}

// TODO: restriction on D::Error is so that `propagate_err` will work;
//       is there a more generic way to handle this?
impl<D: SimpleDecoder<Error=util::Error>> ConsensusDecodable<D> for RawNetworkMessage {
    fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, D::Error> {
        let magic = try!(ConsensusDecodable::consensus_decode(d));
        let CommandString(cmd): CommandString= try!(ConsensusDecodable::consensus_decode(d));
        let CheckedData(raw_payload): CheckedData = try!(ConsensusDecodable::consensus_decode(d));

        let mut mem_d = RawDecoder::new(Cursor::new(raw_payload));
        let payload = match &cmd[..] {
            "version" => NetworkMessage::Version(try!(propagate_err("version".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "verack"  => NetworkMessage::Verack,
            "addr"    => NetworkMessage::Addr(try!(propagate_err("addr".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "inv"     => NetworkMessage::Inv(try!(propagate_err("inv".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getdata" => NetworkMessage::GetData(try!(propagate_err("getdata".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "notfound" => NetworkMessage::NotFound(try!(propagate_err("notfound".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getblocks" => NetworkMessage::GetBlocks(try!(propagate_err("getblocks".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getheaders" => NetworkMessage::GetHeaders(try!(propagate_err("getheaders".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "mempool" => NetworkMessage::MemPool,
            "block"   => NetworkMessage::Block(try!(propagate_err("block".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "headers" => NetworkMessage::Headers(try!(propagate_err("headers".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "getaddr" => NetworkMessage::GetAddr,
            "ping"    => NetworkMessage::Ping(try!(propagate_err("ping".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "pong"    => NetworkMessage::Pong(try!(propagate_err("pong".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            "tx"      => NetworkMessage::Tx(try!(propagate_err("tx".to_owned(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
            cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd)))
        };
        Ok(RawNetworkMessage {
            magic: magic,
            payload: payload
        })
    }
}

#[cfg(test)]
mod test {
    use super::{RawNetworkMessage, NetworkMessage, CommandString};

    use network::serialize::{deserialize, serialize};

    #[test]
    fn serialize_commandstring_test() {
        let cs = CommandString("Andrew".to_owned());
        assert_eq!(serialize(&cs).ok(), Some(vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]));
    }

    #[test]
    fn deserialize_commandstring_test() {
        let cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
        assert!(cs.is_ok());
        assert_eq!(cs.unwrap(), CommandString("Andrew".to_owned()));

        let short_cs: Result<CommandString, _> = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
        assert!(short_cs.is_err());
    }

    #[test]
    fn serialize_verack_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
                                       0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
    }

    #[test]
    fn serialize_ping_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
                                       0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
    }

    #[test]
    fn serialize_mempool_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
                                       0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
    }

    #[test]
    fn serialize_getaddr_test() {
        assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }).ok(),
                             Some(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
                                       0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
    }

}
<|endoftext|>


<commit_before>use self::ll::{AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S8, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8};
use self::ll::{SDL_LockAudio, SDL_MixAudio, SDL_OpenAudio};
use self::ll::{SDL_UnlockAudio};

use std::mem::{forget, transmute};
use libc::{c_int, c_void, uint16_t};
use std::ptr::null_mut;

pub mod ll {
    #![allow(non_camel_case_types)]

    use libc::{c_int, c_void, uint16_t};

    pub const AUDIO_U8: uint16_t = 0x0008;
    pub const AUDIO_S8: uint16_t = 0x8008;
    pub const AUDIO_U16LSB: uint16_t = 0x0010;
    pub const AUDIO_S16LSB: uint16_t = 0x8010;
    pub const AUDIO_U16MSB: uint16_t = 0x1010;
    pub const AUDIO_S16MSB: uint16_t = 0x9010;
    pub const AUDIO_U16: uint16_t = AUDIO_U16LSB;
    pub const AUDIO_S16: uint16_t = AUDIO_S16LSB;

    #[repr(C)]
    pub struct SDL_AudioSpec {
        pub freq: c_int,
        pub format: u16,
        pub channels: u8,
        pub silence: u8,
        pub samples: u16,
        pub padding: u16,
        pub size: u32,
        pub callback: *mut u8,
        pub userdata: *mut c_void,
    }

    impl Copy for SDL_AudioSpec {}

    extern "C" {
        pub fn SDL_OpenAudio(desired: *mut SDL_AudioSpec, obtained: *mut SDL_AudioSpec) -> c_int;
        pub fn SDL_PauseAudio(pause_on: c_int);
        pub fn SDL_MixAudio(dst: *mut u8, src: *const u8, len: u32, volume: c_int);
        pub fn SDL_LockAudio();
        pub fn SDL_UnlockAudio();
        pub fn SDL_CloseAudio();
    }
}

pub enum AudioFormat {
    U8 = AUDIO_U8 as isize,
    S8 = AUDIO_S8 as isize,
    U16Lsb = AUDIO_U16LSB as isize,
    S16Lsb = AUDIO_S16LSB as isize,
    U16Msb = AUDIO_U16MSB as isize,
    S16Msb = AUDIO_S16MSB as isize
}

impl Copy for AudioFormat {}

pub static U16_AUDIO_FORMAT: AudioFormat = AudioFormat::U16Lsb;
pub static S16_AUDIO_FORMAT: AudioFormat = AudioFormat::S16Lsb;

impl AudioFormat {
    pub fn to_ll_format(self) -> uint16_t {
        match self {
            AudioFormat::U8 => AUDIO_U8,
            AudioFormat::S8 => AUDIO_S8,
            AudioFormat::U16Lsb => AUDIO_U16LSB,
            AudioFormat::S16Lsb => AUDIO_S16LSB,
            AudioFormat::U16Msb => AUDIO_U16MSB,
            AudioFormat::S16Msb => AUDIO_S16MSB,
        }
    }

    pub fn from_ll_format(x: uint16_t) -> AudioFormat {
        match x {
            AUDIO_U8 => AudioFormat::U8,
            AUDIO_S8 => AudioFormat::S8,
            AUDIO_U16LSB => AudioFormat::U16Lsb,
            AUDIO_S16LSB => AudioFormat::S16Lsb,
            AUDIO_U16MSB => AudioFormat::U16Msb,
            AUDIO_S16MSB => AudioFormat::S16Msb,
            _ => panic!("unexpected format")
        }
    }
}

#[derive(PartialEq, Eq)]
pub enum Channels {
    Mono,
    Stereo,
}

impl Copy for Channels {}

impl Channels {
    pub fn new(count: c_int) -> Channels { if count == 1 { Channels::Mono } else { Channels::Stereo } }
    pub fn count(self) -> c_int          { match self { Channels::Mono => 1, Channels::Stereo => 2 } }
}

pub type AudioCallback = fn(&mut [u8]);

pub struct DesiredAudioSpec {
    pub freq: c_int,
    pub format: AudioFormat,
    pub channels: Channels,
    pub samples: u16,
    pub callback: AudioCallback,
}

impl Copy for DesiredAudioSpec {}

impl DesiredAudioSpec {
    fn to_ll_spec(self) -> ll::SDL_AudioSpec {
        unsafe {
            let DesiredAudioSpec { freq, format, channels, samples, callback } = self;
            ll::SDL_AudioSpec {
                freq: freq,
                format: format.to_ll_format(),
                channels: channels.count() as u8,
                silence: 0,
                samples: samples,
                padding: 0,
                size: 0,
                callback: native_callback as *mut u8,
                userdata: transmute(box callback),
            }
        }
    }
}

pub struct ObtainedAudioSpec {
    pub freq: c_int,
    pub format: AudioFormat,
    pub channels: Channels,
    pub silence: u8,
    pub samples: u16,
    pub size: u32,
}

impl Copy for ObtainedAudioSpec {}

impl ObtainedAudioSpec {
    fn from_ll_spec(spec: &ll::SDL_AudioSpec) -> ObtainedAudioSpec {
        ObtainedAudioSpec {
            freq: spec.freq,
            format: AudioFormat::from_ll_format(spec.format),
            channels: Channels::new(spec.channels as c_int),
            silence: spec.silence,
            samples: spec.samples,
            size: spec.size,
        }
    }
}

extern fn native_callback(userdata: *const c_void, stream: *mut u8, len: c_int) {
    unsafe {
        let callback: Box<AudioCallback> = transmute(userdata);
        let buffer = transmute((stream, len as usize));
        (*callback)(buffer);
        forget(callback);   // Don't free the callback!
    }
}

pub fn open(desired: DesiredAudioSpec) -> Result<ObtainedAudioSpec,()> {
    unsafe {
        let mut ll_desired = desired.to_ll_spec();
        let mut ll_obtained = ll::SDL_AudioSpec {
            freq: 0,
            format: 0,
            channels: 0,
            silence: 0,
            samples: 0,
            padding: 0,
            size: 0,
            callback: null_mut(),
            userdata: null_mut(),
        };

        if SDL_OpenAudio(&mut ll_desired, &mut ll_obtained) < 0 {
            Err(())
        } else {
            Ok(ObtainedAudioSpec::from_ll_spec(&ll_obtained))
        }
    }
}

pub fn pause(paused: bool) {
    unsafe {
        ll::SDL_PauseAudio(paused as c_int);
    }
}

pub fn close() {
    unsafe {
        ll::SDL_CloseAudio();
    }
}

pub fn mix(dest: &mut [u8], src: &[u8], volume: c_int) {
    unsafe {
        assert!(dest.len() == src.len());
        SDL_MixAudio(&mut dest[0], &src[0], dest.len() as u32, volume);
    }
}

pub fn with_lock<F: Fn() -> bool>(f: F) -> bool {
    unsafe {
        SDL_LockAudio();
        let result = f();
        SDL_UnlockAudio();
        result
    }
}

<commit_msg>language changes: `box` -> `Box::new`<commit_after>use self::ll::{AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S8, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8};
use self::ll::{SDL_LockAudio, SDL_MixAudio, SDL_OpenAudio};
use self::ll::{SDL_UnlockAudio};

use std::mem::{forget, transmute};
use libc::{c_int, c_void, uint16_t};
use std::ptr::null_mut;

pub mod ll {
    #![allow(non_camel_case_types)]

    use libc::{c_int, c_void, uint16_t};

    pub const AUDIO_U8: uint16_t = 0x0008;
    pub const AUDIO_S8: uint16_t = 0x8008;
    pub const AUDIO_U16LSB: uint16_t = 0x0010;
    pub const AUDIO_S16LSB: uint16_t = 0x8010;
    pub const AUDIO_U16MSB: uint16_t = 0x1010;
    pub const AUDIO_S16MSB: uint16_t = 0x9010;
    pub const AUDIO_U16: uint16_t = AUDIO_U16LSB;
    pub const AUDIO_S16: uint16_t = AUDIO_S16LSB;

    #[repr(C)]
    pub struct SDL_AudioSpec {
        pub freq: c_int,
        pub format: u16,
        pub channels: u8,
        pub silence: u8,
        pub samples: u16,
        pub padding: u16,
        pub size: u32,
        pub callback: *mut u8,
        pub userdata: *mut c_void,
    }

    impl Copy for SDL_AudioSpec {}

    extern "C" {
        pub fn SDL_OpenAudio(desired: *mut SDL_AudioSpec, obtained: *mut SDL_AudioSpec) -> c_int;
        pub fn SDL_PauseAudio(pause_on: c_int);
        pub fn SDL_MixAudio(dst: *mut u8, src: *const u8, len: u32, volume: c_int);
        pub fn SDL_LockAudio();
        pub fn SDL_UnlockAudio();
        pub fn SDL_CloseAudio();
    }
}

pub enum AudioFormat {
    U8 = AUDIO_U8 as isize,
    S8 = AUDIO_S8 as isize,
    U16Lsb = AUDIO_U16LSB as isize,
    S16Lsb = AUDIO_S16LSB as isize,
    U16Msb = AUDIO_U16MSB as isize,
    S16Msb = AUDIO_S16MSB as isize
}

impl Copy for AudioFormat {}

pub static U16_AUDIO_FORMAT: AudioFormat = AudioFormat::U16Lsb;
pub static S16_AUDIO_FORMAT: AudioFormat = AudioFormat::S16Lsb;

impl AudioFormat {
    pub fn to_ll_format(self) -> uint16_t {
        match self {
            AudioFormat::U8 => AUDIO_U8,
            AudioFormat::S8 => AUDIO_S8,
            AudioFormat::U16Lsb => AUDIO_U16LSB,
            AudioFormat::S16Lsb => AUDIO_S16LSB,
            AudioFormat::U16Msb => AUDIO_U16MSB,
            AudioFormat::S16Msb => AUDIO_S16MSB,
        }
    }

    pub fn from_ll_format(x: uint16_t) -> AudioFormat {
        match x {
            AUDIO_U8 => AudioFormat::U8,
            AUDIO_S8 => AudioFormat::S8,
            AUDIO_U16LSB => AudioFormat::U16Lsb,
            AUDIO_S16LSB => AudioFormat::S16Lsb,
            AUDIO_U16MSB => AudioFormat::U16Msb,
            AUDIO_S16MSB => AudioFormat::S16Msb,
            _ => panic!("unexpected format")
        }
    }
}

#[derive(PartialEq, Eq)]
pub enum Channels {
    Mono,
    Stereo,
}

impl Copy for Channels {}

impl Channels {
    pub fn new(count: c_int) -> Channels { if count == 1 { Channels::Mono } else { Channels::Stereo } }
    pub fn count(self) -> c_int          { match self { Channels::Mono => 1, Channels::Stereo => 2 } }
}

pub type AudioCallback = fn(&mut [u8]);

pub struct DesiredAudioSpec {
    pub freq: c_int,
    pub format: AudioFormat,
    pub channels: Channels,
    pub samples: u16,
    pub callback: AudioCallback,
}

impl Copy for DesiredAudioSpec {}

impl DesiredAudioSpec {
    fn to_ll_spec(self) -> ll::SDL_AudioSpec {
        unsafe {
            let DesiredAudioSpec { freq, format, channels, samples, callback } = self;
            ll::SDL_AudioSpec {
                freq: freq,
                format: format.to_ll_format(),
                channels: channels.count() as u8,
                silence: 0,
                samples: samples,
                padding: 0,
                size: 0,
                callback: native_callback as *mut u8,
                userdata: transmute(Box::new(callback)),
            }
        }
    }
}

pub struct ObtainedAudioSpec {
    pub freq: c_int,
    pub format: AudioFormat,
    pub channels: Channels,
    pub silence: u8,
    pub samples: u16,
    pub size: u32,
}

impl Copy for ObtainedAudioSpec {}

impl ObtainedAudioSpec {
    fn from_ll_spec(spec: &ll::SDL_AudioSpec) -> ObtainedAudioSpec {
        ObtainedAudioSpec {
            freq: spec.freq,
            format: AudioFormat::from_ll_format(spec.format),
            channels: Channels::new(spec.channels as c_int),
            silence: spec.silence,
            samples: spec.samples,
            size: spec.size,
        }
    }
}

extern fn native_callback(userdata: *const c_void, stream: *mut u8, len: c_int) {
    unsafe {
        let callback: Box<AudioCallback> = transmute(userdata);
        let buffer = transmute((stream, len as usize));
        (*callback)(buffer);
        forget(callback);   // Don't free the callback!
    }
}

pub fn open(desired: DesiredAudioSpec) -> Result<ObtainedAudioSpec,()> {
    unsafe {
        let mut ll_desired = desired.to_ll_spec();
        let mut ll_obtained = ll::SDL_AudioSpec {
            freq: 0,
            format: 0,
            channels: 0,
            silence: 0,
            samples: 0,
            padding: 0,
            size: 0,
            callback: null_mut(),
            userdata: null_mut(),
        };

        if SDL_OpenAudio(&mut ll_desired, &mut ll_obtained) < 0 {
            Err(())
        } else {
            Ok(ObtainedAudioSpec::from_ll_spec(&ll_obtained))
        }
    }
}

pub fn pause(paused: bool) {
    unsafe {
        ll::SDL_PauseAudio(paused as c_int);
    }
}

pub fn close() {
    unsafe {
        ll::SDL_CloseAudio();
    }
}

pub fn mix(dest: &mut [u8], src: &[u8], volume: c_int) {
    unsafe {
        assert!(dest.len() == src.len());
        SDL_MixAudio(&mut dest[0], &src[0], dest.len() as u32, volume);
    }
}

pub fn with_lock<F: Fn() -> bool>(f: F) -> bool {
    unsafe {
        SDL_LockAudio();
        let result = f();
        SDL_UnlockAudio();
        result
    }
}

<|endoftext|>