<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;
use llvm_sys::prelude::LLVMValueRef;

use iron_llvm::core;
use iron_llvm::core::types::{ Type
                            , TypeCtor
                            , RealTypeCtor
                            , RealTypeRef
                            , IntTypeCtor
                            , IntTypeRef
                            };
use iron_llvm::{LLVMRef, LLVMRefCtor};

use errors::ExpectICE;
use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types;
use semantic::types::{ Primitive
                    , Reference
                    };

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<LLVMValueRef, Vec<Positional<String>>>;

/// Result type for compiling a type to an LLVM `TypeRef`.
pub type TypeResult<T: Type + Sized> = Result<T, Positional<String>>;

pub type NamedValues<'a> = ForkTable<'a, &'a str, LLVMValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `ValueRef` if this was compiled correctly.
    ///   - An `Err` with a vector of error messages containing any
    ///     errors that occured during compilation.
    ///
    /// # Panics:
    ///   - If something has gone horribly wrong. This does NOT panic if the
    ///     code could not be compiled because it was incorrect, but it will
    ///     panic in the event of an internal compiler error.
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
// pub trait TranslateType {
//     /// Translate `self` to an LLVM `TypeRef`
//     ///
//     /// # Returns:
//     ///   - `Ok` containing a `TypeRef` if this was compiled correctly.
//     ///   - An `Err` with a positional error message in the event of
//     ///     a type error.
//     ///
//     /// # Panics:
//     ///   - In the event of an internal compiler error (i.e. if a well-formed
//     ///     type could not be gotten from LLVM correctly).
//     fn translate_type(&self, context: LLVMContext) -> TypeResult;
// }

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { llctx: core::Context
                           , llmod: core::Module
                           , llbuilder: core::Builder
                           , named_vals: NamedValues<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        LLVMContext { llctx: core::Context::get_global()
                    , llmod: core::Module::new(module_name)
                    , llbuilder: core::Builder::new()
                    , named_vals: NamedValues::new()
                    }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `Module` in LLVM
    pub fn dump(&self) { self.llmod.dump() }

    pub fn int_type(&self, size: usize) -> IntTypeRef {
        IntTypeRef::get_int_in_context(&self.llctx, size as c_uint)
    }

    pub fn float_type(&self) -> RealTypeRef {
        RealTypeRef::get_float_in_context(&self.llctx)
    }
    pub fn double_type(&self) -> RealTypeRef {
        RealTypeRef::get_double_in_context(&self.llctx)
    }
    pub fn byte_type(&self) -> IntTypeRef {
        IntTypeRef::get_int8_in_context(&self.llctx)
    }

    /// Get any existing declarations for a given function name.
    ///
    /// # Returns:
    ///   - `Some` if there is an existing previous declaration
    ///     for this function.
    ///   - `None` if the function has not been declared previously.
    ///
    /// # Panics:
    ///   - If the C string representation for the function name could
    ///     not be created.
    pub fn get_fn(&self, name: &Ident) -> Option<core::FunctionRef> {
        self.llmod.get_function_by_name(name.value.as_ref())
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.get_fn(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {

    fn to_ir(&self, context: LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        // Check to see if the pattern binds an equivalent number of arguments
        // as the function signature (minus one, which is the return type).
        for e in &self.equations {
            match e.pattern_length()
                   .cmp(&self.arity()) {
                // the equation's pattern is shorter than the function's arity
                // eventually, we'll autocurry this, but for now, we error.
                // TODO: maybe there should be a warning as well?
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
                // the equation's pattern is longer than the function's arity
                // this is super wrong and always an error.
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
            , _ =>  {}
            }
        }
        // TODO: this could be made way more idiomatic...
        try_vec!(errs);
        unimplemented!()
    }

}

// impl TranslateType for types::Type {
//     fn translate_type(&self, context: LLVMContext) -> TypeResult {
//         match *self {
//             types::Type::Ref(ref r) => r.translate_type(context)
//           , types::Type::Prim(ref p) => p.translate_type(context)
//           , _ => unimplemented!() // TODO: figure this out
//         }
//     }
// }

// impl TranslateType for Reference {
//     fn translate_type(&self, context: LLVMContext) -> TypeResult {
//         unimplemented!() // TODO: figure this out
//     }
// }

// impl TranslateType for Primitive {
//     fn translate_type(&self, context: LLVMContext) -> TypeResult {
//     //     Ok(match *self {
//     //         Primitive::IntSize => context.int_type(word_size())
//     //       , Primitive::UintSize => context.int_type(word_size())
//     //       , Primitive::Int(bits) => context.int_type(bits as usize)
//     //       , Primitive::Uint(bits) => context.int_type(bits as usize)
//     //       , Primitive::Float => context.float_type()
//     //       , Primitive::Double => context.double_type()
//     //       , Primitive::Byte => context.byte_type()
//     //       , _ => unimplemented!() // TODO: figure this out
//     //   })
//         unimplemented!()
//     }
// }
<commit_msg>Found where the segfault lives<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;
use llvm_sys::prelude::LLVMValueRef;

use iron_llvm::core;
use iron_llvm::core::types::{ Type
                            , TypeCtor
                            , RealTypeCtor
                            , RealTypeRef
                            , IntTypeCtor
                            , IntTypeRef
                            };
use iron_llvm::{LLVMRef, LLVMRefCtor};

use errors::ExpectICE;
use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types;
use semantic::types::{ Primitive
                    , Reference
                    };

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<LLVMValueRef, Vec<Positional<String>>>;

/// Result type for compiling a type to an LLVM `TypeRef`.
pub type TypeResult<T: Type + Sized> = Result<T, Positional<String>>;

pub type NamedValues<'a> = ForkTable<'a, &'a str, LLVMValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    ///
    /// # Returns:
    ///   - `Ok` containing a `ValueRef` if this was compiled correctly.
    ///   - An `Err` with a vector of error messages containing any
    ///     errors that occured during compilation.
    ///
    /// # Panics:
    ///   - If something has gone horribly wrong. This does NOT panic if the
    ///     code could not be compiled because it was incorrect, but it will
    ///     panic in the event of an internal compiler error.
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
// pub trait TranslateType {
//     /// Translate `self` to an LLVM `TypeRef`
//     ///
//     /// # Returns:
//     ///   - `Ok` containing a `TypeRef` if this was compiled correctly.
//     ///   - An `Err` with a positional error message in the event of
//     ///     a type error.
//     ///
//     /// # Panics:
//     ///   - In the event of an internal compiler error (i.e. if a well-formed
//     ///     type could not be gotten from LLVM correctly).
//     fn translate_type(&self, context: LLVMContext) -> TypeResult;
// }

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { llctx: core::Context
                           , llmod: core::Module
                           , llbuilder: core::Builder
                           , named_vals: NamedValues<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

// ------------ SEGFAULT EXISTS SOMEWHERE BELOW THIS LINE --------------------

//
// impl<'a> LLVMContext<'a> {
//
//     /// Constructs a new LLVM context.
//     ///
//     /// # Returns:
//     ///   - An `LLVMContext`
//     ///
//     /// # Panics:
//     ///   - If the LLVM C ABI returned a null value for the `Context`,
//     ///     `Builder`, or `Module`
//     pub fn new(module_name: &str) -> Self {
//         LLVMContext { llctx: core::Context::get_global()
//                     , llmod: core::Module::new(module_name)
//                     , llbuilder: core::Builder::new()
//                     , named_vals: NamedValues::new()
//                     }
//     }
//
//     /// Dump the module's contents to stderr for debugging
//     ///
//     /// Apparently this is the only reasonable way to get a textual
//     /// representation of a `Module` in LLVM
//     pub fn dump(&self) { self.llmod.dump() }
//
//     pub fn int_type(&self, size: usize) -> IntTypeRef {
//         IntTypeRef::get_int_in_context(&self.llctx, size as c_uint)
//     }
//
//     pub fn float_type(&self) -> RealTypeRef {
//         RealTypeRef::get_float_in_context(&self.llctx)
//     }
//     pub fn double_type(&self) -> RealTypeRef {
//         RealTypeRef::get_double_in_context(&self.llctx)
//     }
//     pub fn byte_type(&self) -> IntTypeRef {
//         IntTypeRef::get_int8_in_context(&self.llctx)
//     }
//
//     /// Get any existing declarations for a given function name.
//     ///
//     /// # Returns:
//     ///   - `Some` if there is an existing previous declaration
//     ///     for this function.
//     ///   - `None` if the function has not been declared previously.
//     ///
//     /// # Panics:
//     ///   - If the C string representation for the function name could
//     ///     not be created.
//     pub fn get_fn(&self, name: &Ident) -> Option<core::FunctionRef> {
//         self.llmod.get_function_by_name(name.value.as_ref())
//     }
// }

// impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
//     fn to_ir(&self, context: LLVMContext) -> IRResult {
//         match **self {
//             Form::Define(ref form) => unimplemented!()
//           , Form::Let(ref form) => unimplemented!()
//           , Form::If { .. } => unimplemented!()
//           , Form::Call { .. } => unimplemented!()
//           , Form::Lambda(ref fun) => unimplemented!()
//           , Form::Logical(ref exp) => unimplemented!()
//           , Form::Lit(ref c) => unimplemented!()
//           , Form::NameRef(ref form) => unimplemented!()
//         }
//     }
// }
//
// impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
//     fn to_ir(&self, context: LLVMContext) -> IRResult {
//         match **self {
//             DefForm::TopLevel { ref name, ref value, .. } =>
//                 unimplemented!()
//          ,  DefForm::Function { ref name, ref fun } => {
//                 match context.get_fn(name) {
//                     Some(previous) => unimplemented!()
//                   , None => unimplemented!()
//                 }
//             }
//         }
//     }
// }
//
//
// impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {
//
//     fn to_ir(&self, context: LLVMContext) -> IRResult {
//         let mut errs: Vec<Positional<String>> = vec![];
//         // Check to see if the pattern binds an equivalent number of arguments
//         // as the function signature (minus one, which is the return type).
//         for e in &self.equations {
//             match e.pattern_length()
//                    .cmp(&self.arity()) {
//                 // the equation's pattern is shorter than the function's arity
//                 // eventually, we'll autocurry this, but for now, we error.
//                 // TODO: maybe there should be a warning as well?
//                 Ordering::Less => errs.push(Positional {
//                     pos: e.position.clone()
//                   , value: format!( "[error] equation had fewer bindings \
//                                      than function arity\n \
//                                      [error] auto-currying is not currently \
//                                      implemented.\n \
//                                      signature: {}\nfunction: {}\n"
//                                   , self.sig
//                                   , (*e).to_sexpr(0)
//                                   )
//                   })
//                 // the equation's pattern is longer than the function's arity
//                 // this is super wrong and always an error.
//               , Ordering::Greater => errs.push(Positional {
//                   pos: e.position.clone()
//                 , value: format!( "[error] equation bound too many arguments\n \
//                                    signature: {}\nfunction: {}\n"
//                                 , self.sig
//                                 , (*e).to_sexpr(0)
//                                 )
//               })
//             , _ =>  {}
//             }
//         }
//         // TODO: this could be made way more idiomatic...
//         try_vec!(errs);
//         unimplemented!()
//     }
//
// }
//
//
//
// // impl TranslateType for types::Type {
// //     fn translate_type(&self, context: LLVMContext) -> TypeResult {
// //         match *self {
// //             types::Type::Ref(ref r) => r.translate_type(context)
// //           , types::Type::Prim(ref p) => p.translate_type(context)
// //           , _ => unimplemented!() // TODO: figure this out
// //         }
// //     }
// // }
//
// // impl TranslateType for Reference {
// //     fn translate_type(&self, context: LLVMContext) -> TypeResult {
// //         unimplemented!() // TODO: figure this out
// //     }
// // }
//
// // impl TranslateType for Primitive {
// //     fn translate_type(&self, context: LLVMContext) -> TypeResult {
// //     //     Ok(match *self {
// //     //         Primitive::IntSize => context.int_type(word_size())
// //     //       , Primitive::UintSize => context.int_type(word_size())
// //     //       , Primitive::Int(bits) => context.int_type(bits as usize)
// //     //       , Primitive::Uint(bits) => context.int_type(bits as usize)
// //     //       , Primitive::Float => context.float_type()
// //     //       , Primitive::Double => context.double_type()
// //     //       , Primitive::Byte => context.byte_type()
// //     //       , _ => unimplemented!() // TODO: figure this out
// //     //   })
// //         unimplemented!()
// //     }
// // }
<|endoftext|>


<commit_before>extern crate inkwell;

use self::inkwell::attributes::Attribute;
use self::inkwell::context::Context;

use std::ffi::CString;

#[test]
fn test_enum_attribute_kinds() {
    // Does not exist:
    assert_eq!(Attribute::get_named_enum_kind_id("foo"), 0);
    assert_eq!(Attribute::get_named_enum_kind_id("bar"), 0);

    // TODO: Document these kinds of attributes:
    // Function Attributes:
    assert_eq!(Attribute::get_named_enum_kind_id("allocsize"), 2);
    assert_eq!(Attribute::get_named_enum_kind_id("alwaysinline"), 3);
    assert_eq!(Attribute::get_named_enum_kind_id("argmemonly"), 4);
    assert_eq!(Attribute::get_named_enum_kind_id("builtin"), 5);
    assert_eq!(Attribute::get_named_enum_kind_id("cold"), 7);
    assert_eq!(Attribute::get_named_enum_kind_id("convergent"), 8);
    assert_eq!(Attribute::get_named_enum_kind_id("inaccessiblememonly"), 13);
    assert_eq!(Attribute::get_named_enum_kind_id("inaccessiblemem_or_argmemonly"), 14);
    assert_eq!(Attribute::get_named_enum_kind_id("inlinehint"), 15);
    assert_eq!(Attribute::get_named_enum_kind_id("jumptable"), 16);
    assert_eq!(Attribute::get_named_enum_kind_id("minsize"), 17);
    assert_eq!(Attribute::get_named_enum_kind_id("naked"), 18);
    assert_eq!(Attribute::get_named_enum_kind_id("nobuiltin"), 21);
    assert_eq!(Attribute::get_named_enum_kind_id("noduplicate"), 23);
    assert_eq!(Attribute::get_named_enum_kind_id("noimplicitfloat"), 24);
    assert_eq!(Attribute::get_named_enum_kind_id("noinline"), 25);
    assert_eq!(Attribute::get_named_enum_kind_id("norecurse"), 26);
    assert_eq!(Attribute::get_named_enum_kind_id("noredzone"), 27);
    assert_eq!(Attribute::get_named_enum_kind_id("noreturn"), 28);
    assert_eq!(Attribute::get_named_enum_kind_id("nounwind"), 29);
    assert_eq!(Attribute::get_named_enum_kind_id("nonlazybind"), 30);
    assert_eq!(Attribute::get_named_enum_kind_id("optsize"), 32);
    assert_eq!(Attribute::get_named_enum_kind_id("optnone"), 33);
    assert_eq!(Attribute::get_named_enum_kind_id("readnone"), 34);
    assert_eq!(Attribute::get_named_enum_kind_id("readonly"), 35);
    assert_eq!(Attribute::get_named_enum_kind_id("returns_twice"), 37);
    assert_eq!(Attribute::get_named_enum_kind_id("safestack"), 39);
    assert_eq!(Attribute::get_named_enum_kind_id("sanitize_address"), 40);
    assert_eq!(Attribute::get_named_enum_kind_id("sanitize_hwaddress"), 41);
    assert_eq!(Attribute::get_named_enum_kind_id("sanitize_memory"), 42);
    assert_eq!(Attribute::get_named_enum_kind_id("sanitize_thread"), 43);
    assert_eq!(Attribute::get_named_enum_kind_id("speculatable"), 44);
    assert_eq!(Attribute::get_named_enum_kind_id("alignstack"), 45);
    assert_eq!(Attribute::get_named_enum_kind_id("ssp"), 46);
    assert_eq!(Attribute::get_named_enum_kind_id("sspreq"), 47);
    assert_eq!(Attribute::get_named_enum_kind_id("sspstrong"), 48);
    assert_eq!(Attribute::get_named_enum_kind_id("strictfp"), 49);
    assert_eq!(Attribute::get_named_enum_kind_id("uwtable"), 53);
    assert_eq!(Attribute::get_named_enum_kind_id("writeonly"), 54);

    // REVIEW: The LLVM docs suggest these fn attrs exist, but don't turn up:
    // assert_eq!(Attribute::get_named_enum_kind_id("no-jump-tables"), 19);
    // assert_eq!(Attribute::get_named_enum_kind_id("null-pointer-is-valid"), 31);
    // assert_eq!(Attribute::get_named_enum_kind_id("optforfuzzing"), 32);
    // assert_eq!(Attribute::get_named_enum_kind_id("patchable-function"), 35);
    // assert_eq!(Attribute::get_named_enum_kind_id("probe-stack"), 36);
    // assert_eq!(Attribute::get_named_enum_kind_id("stack-probe-size"), 36);
    // assert_eq!(Attribute::get_named_enum_kind_id("no-stack-arg-probe"), 32);
    // assert_eq!(Attribute::get_named_enum_kind_id("thunk"), 45);
    // assert_eq!(Attribute::get_named_enum_kind_id("nocf_check"), 45);
    // assert_eq!(Attribute::get_named_enum_kind_id("shadowcallstack"), 45);

    // Parameter Attributes:
    assert_eq!(Attribute::get_named_enum_kind_id("align"), 1);
    assert_eq!(Attribute::get_named_enum_kind_id("byval"), 6);
    assert_eq!(Attribute::get_named_enum_kind_id("dereferenceable"), 9);
    assert_eq!(Attribute::get_named_enum_kind_id("dereferenceable_or_null"), 10);
    assert_eq!(Attribute::get_named_enum_kind_id("inalloca"), 11);
    assert_eq!(Attribute::get_named_enum_kind_id("inreg"), 12);
    assert_eq!(Attribute::get_named_enum_kind_id("nest"), 19);
    assert_eq!(Attribute::get_named_enum_kind_id("noalias"), 20);
    assert_eq!(Attribute::get_named_enum_kind_id("nocapture"), 22);
    assert_eq!(Attribute::get_named_enum_kind_id("nonnull"), 31);
    assert_eq!(Attribute::get_named_enum_kind_id("returned"), 36);
    assert_eq!(Attribute::get_named_enum_kind_id("signext"), 38);
    assert_eq!(Attribute::get_named_enum_kind_id("sret"), 50);
    assert_eq!(Attribute::get_named_enum_kind_id("swifterror"), 51);
    assert_eq!(Attribute::get_named_enum_kind_id("swiftself"), 52);
    assert_eq!(Attribute::get_named_enum_kind_id("zeroext"), 55);

    // REVIEW: Does last mean there is another kind at 56 we're missing?
    // or is it the next "free" slot
    assert_eq!(Attribute::get_last_enum_kind_id(), 56);
}

#[test]
fn test_enum_attributes() {
    assert_eq!(Attribute::get_last_enum_kind_id(), 56);

    let context = Context::create();
    let enum_attribute = context.create_enum_attribute(0, 10);

    assert!(enum_attribute.is_enum());
    assert!(!enum_attribute.is_string());

    assert_eq!(enum_attribute.get_enum_kind_id(), 0);
    assert_eq!(enum_attribute.get_enum_value(), 10);

    let enum_attribute2 = context.create_enum_attribute(3, 14);

    assert!(enum_attribute2.is_enum());
    assert!(!enum_attribute2.is_string());

    assert_eq!(enum_attribute2.get_enum_kind_id(), 3);
    assert_eq!(enum_attribute2.get_enum_value(), 14);

    let enum_attribute3 = context.create_enum_attribute(56, 20);

    assert!(enum_attribute3.is_enum());
    assert!(!enum_attribute3.is_string());

    assert_eq!(enum_attribute3.get_enum_kind_id(), 56);
    assert_eq!(enum_attribute3.get_enum_value(), 20);

    // This hasn't changed from 56, so it doesn't seem like
    // enum creation influences the kind ids
    assert_eq!(Attribute::get_last_enum_kind_id(), 56);
}

#[test]
fn test_string_attributes() {
    let context = Context::create();
    let string_attribute = context.create_string_attribute("my_key_123", "my_val");

    assert!(!string_attribute.is_enum());
    assert!(string_attribute.is_string());

    assert_eq!(*string_attribute.get_string_kind_id(), *CString::new("my_key_123").unwrap());
    assert_eq!(*string_attribute.get_string_value(), *CString::new("my_val").unwrap());
}
<commit_msg>Fixed attribute tests in 4.0 & 5.0<commit_after>extern crate inkwell;

use self::inkwell::attributes::Attribute;
use self::inkwell::context::Context;

use std::ffi::CString;

#[test]
fn test_enum_attribute_kinds() {
    // Does not exist:
    assert_eq!(Attribute::get_named_enum_kind_id("foo"), 0);
    assert_eq!(Attribute::get_named_enum_kind_id("bar"), 0);

    // TODO: Document these kinds of attributes:
    // Function Attributes:
    assert_eq!(Attribute::get_named_enum_kind_id("allocsize"), 2);
    assert_eq!(Attribute::get_named_enum_kind_id("alwaysinline"), 3);
    assert_eq!(Attribute::get_named_enum_kind_id("argmemonly"), 4);
    assert_eq!(Attribute::get_named_enum_kind_id("builtin"), 5);
    assert_eq!(Attribute::get_named_enum_kind_id("cold"), 7);
    assert_eq!(Attribute::get_named_enum_kind_id("convergent"), 8);
    assert_eq!(Attribute::get_named_enum_kind_id("inaccessiblememonly"), 13);
    assert_eq!(Attribute::get_named_enum_kind_id("inaccessiblemem_or_argmemonly"), 14);
    assert_eq!(Attribute::get_named_enum_kind_id("inlinehint"), 15);
    assert_eq!(Attribute::get_named_enum_kind_id("jumptable"), 16);
    assert_eq!(Attribute::get_named_enum_kind_id("minsize"), 17);
    assert_eq!(Attribute::get_named_enum_kind_id("naked"), 18);
    assert_eq!(Attribute::get_named_enum_kind_id("nobuiltin"), 21);
    assert_eq!(Attribute::get_named_enum_kind_id("noduplicate"), 23);
    assert_eq!(Attribute::get_named_enum_kind_id("noimplicitfloat"), 24);
    assert_eq!(Attribute::get_named_enum_kind_id("noinline"), 25);
    assert_eq!(Attribute::get_named_enum_kind_id("norecurse"), 26);
    assert_eq!(Attribute::get_named_enum_kind_id("noredzone"), 27);
    assert_eq!(Attribute::get_named_enum_kind_id("noreturn"), 28);
    assert_eq!(Attribute::get_named_enum_kind_id("nounwind"), 29);
    assert_eq!(Attribute::get_named_enum_kind_id("nonlazybind"), 30);
    assert_eq!(Attribute::get_named_enum_kind_id("optsize"), 32);
    assert_eq!(Attribute::get_named_enum_kind_id("optnone"), 33);
    assert_eq!(Attribute::get_named_enum_kind_id("readnone"), 34);
    assert_eq!(Attribute::get_named_enum_kind_id("readonly"), 35);
    assert_eq!(Attribute::get_named_enum_kind_id("returns_twice"), 37);
    assert_eq!(Attribute::get_named_enum_kind_id("safestack"), 39);
    assert_eq!(Attribute::get_named_enum_kind_id("sanitize_address"), 40);

    // REVIEW: The LLVM docs suggest these fn attrs exist, but don't turn up:
    // assert_eq!(Attribute::get_named_enum_kind_id("no-jump-tables"), 19);
    // assert_eq!(Attribute::get_named_enum_kind_id("null-pointer-is-valid"), 31);
    // assert_eq!(Attribute::get_named_enum_kind_id("optforfuzzing"), 32);
    // assert_eq!(Attribute::get_named_enum_kind_id("patchable-function"), 35);
    // assert_eq!(Attribute::get_named_enum_kind_id("probe-stack"), 36);
    // assert_eq!(Attribute::get_named_enum_kind_id("stack-probe-size"), 36);
    // assert_eq!(Attribute::get_named_enum_kind_id("no-stack-arg-probe"), 32);
    // assert_eq!(Attribute::get_named_enum_kind_id("thunk"), 45);
    // assert_eq!(Attribute::get_named_enum_kind_id("nocf_check"), 45);
    // assert_eq!(Attribute::get_named_enum_kind_id("shadowcallstack"), 45);

    // Parameter Attributes:
    assert_eq!(Attribute::get_named_enum_kind_id("align"), 1);
    assert_eq!(Attribute::get_named_enum_kind_id("byval"), 6);
    assert_eq!(Attribute::get_named_enum_kind_id("dereferenceable"), 9);
    assert_eq!(Attribute::get_named_enum_kind_id("dereferenceable_or_null"), 10);
    assert_eq!(Attribute::get_named_enum_kind_id("inalloca"), 11);
    assert_eq!(Attribute::get_named_enum_kind_id("inreg"), 12);
    assert_eq!(Attribute::get_named_enum_kind_id("nest"), 19);
    assert_eq!(Attribute::get_named_enum_kind_id("noalias"), 20);
    assert_eq!(Attribute::get_named_enum_kind_id("nocapture"), 22);
    assert_eq!(Attribute::get_named_enum_kind_id("nonnull"), 31);
    assert_eq!(Attribute::get_named_enum_kind_id("returned"), 36);
    assert_eq!(Attribute::get_named_enum_kind_id("signext"), 38);

    #[cfg(feature = "llvm4-0")]
    {
        // Function Attributes:
        // assert_eq!(Attribute::get_named_enum_kind_id("sanitize_hwaddress"), 41);
        assert_eq!(Attribute::get_named_enum_kind_id("sanitize_memory"), 41);
        // assert_eq!(Attribute::get_named_enum_kind_id("sanitize_thread"), 42);
        // assert_eq!(Attribute::get_named_enum_kind_id("speculatable"), 43);
        assert_eq!(Attribute::get_named_enum_kind_id("alignstack"), 43); // 43 vs 44
        assert_eq!(Attribute::get_named_enum_kind_id("ssp"), 44); // 44 vs 45
        assert_eq!(Attribute::get_named_enum_kind_id("sspreq"), 45); // 45 vs 46
        assert_eq!(Attribute::get_named_enum_kind_id("sspstrong"), 46); // 46 vs 47
        // assert_eq!(Attribute::get_named_enum_kind_id("strictfp"), 48);
        assert_eq!(Attribute::get_named_enum_kind_id("uwtable"), 50); // 50 vs 51 vs 53
        assert_eq!(Attribute::get_named_enum_kind_id("writeonly"), 51); // 51 vs 52 vs 54

        // Parameter Attributes:
        assert_eq!(Attribute::get_named_enum_kind_id("sret"), 47); // 47 vs 48 vs 50
        assert_eq!(Attribute::get_named_enum_kind_id("swifterror"), 48); // 48 vs 49 vs 51
        assert_eq!(Attribute::get_named_enum_kind_id("swiftself"), 49); // 49 vs 50 vs 52
        assert_eq!(Attribute::get_named_enum_kind_id("zeroext"), 52); // 52 vs 53 vs 55

        // REVIEW: Does last mean there is another kind at 53 we're missing?
        // or is it the next "free" slot
        assert_eq!(Attribute::get_last_enum_kind_id(), 53);
    }

    #[cfg(feature = "llvm5-0")]
    {
        // Function Attributes:
        // assert_eq!(Attribute::get_named_enum_kind_id("sanitize_hwaddress"), 41);
        assert_eq!(Attribute::get_named_enum_kind_id("sanitize_memory"), 41);
        assert_eq!(Attribute::get_named_enum_kind_id("sanitize_thread"), 42);
        assert_eq!(Attribute::get_named_enum_kind_id("speculatable"), 43);
        assert_eq!(Attribute::get_named_enum_kind_id("alignstack"), 44);
        assert_eq!(Attribute::get_named_enum_kind_id("ssp"), 45);
        assert_eq!(Attribute::get_named_enum_kind_id("sspreq"), 46);
        assert_eq!(Attribute::get_named_enum_kind_id("sspstrong"), 47);
        // assert_eq!(Attribute::get_named_enum_kind_id("strictfp"), 48);
        assert_eq!(Attribute::get_named_enum_kind_id("uwtable"), 51); // 51 vs 53
        assert_eq!(Attribute::get_named_enum_kind_id("writeonly"), 52); // 52 vs 54

        // Parameter Attributes:
        assert_eq!(Attribute::get_named_enum_kind_id("sret"), 48); // 48 vs 50
        assert_eq!(Attribute::get_named_enum_kind_id("swifterror"), 49); // 49 vs 51
        assert_eq!(Attribute::get_named_enum_kind_id("swiftself"), 50); // 50 vs 52
        assert_eq!(Attribute::get_named_enum_kind_id("zeroext"), 53); // 53 vs 55

        // REVIEW: Does last mean there is another kind at 54 we're missing?
        // or is it the next "free" slot
        assert_eq!(Attribute::get_last_enum_kind_id(), 54);
    }

    #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0")))]
    {
        // Function Attributes:
        assert_eq!(Attribute::get_named_enum_kind_id("sanitize_hwaddress"), 41);
        assert_eq!(Attribute::get_named_enum_kind_id("sanitize_memory"), 42);
        assert_eq!(Attribute::get_named_enum_kind_id("sanitize_thread"), 43);
        assert_eq!(Attribute::get_named_enum_kind_id("speculatable"), 44);
        assert_eq!(Attribute::get_named_enum_kind_id("alignstack"), 45);
        assert_eq!(Attribute::get_named_enum_kind_id("ssp"), 46);
        assert_eq!(Attribute::get_named_enum_kind_id("sspreq"), 47);
        assert_eq!(Attribute::get_named_enum_kind_id("sspstrong"), 48);
        assert_eq!(Attribute::get_named_enum_kind_id("strictfp"), 49);
        assert_eq!(Attribute::get_named_enum_kind_id("uwtable"), 53);
        assert_eq!(Attribute::get_named_enum_kind_id("writeonly"), 54);

        // Parameter Attributes:
        assert_eq!(Attribute::get_named_enum_kind_id("sret"), 50);
        assert_eq!(Attribute::get_named_enum_kind_id("swifterror"), 51);
        assert_eq!(Attribute::get_named_enum_kind_id("swiftself"), 52);
        assert_eq!(Attribute::get_named_enum_kind_id("zeroext"), 55);

        // REVIEW: Does last mean there is another kind at 56 we're missing?
        // or is it the next "free" slot
        assert_eq!(Attribute::get_last_enum_kind_id(), 56);
    }
}

#[test]
fn test_enum_attributes() {
    let context = Context::create();
    let enum_attribute = context.create_enum_attribute(0, 10);

    assert!(enum_attribute.is_enum());
    assert!(!enum_attribute.is_string());

    assert_eq!(enum_attribute.get_enum_kind_id(), 0);
    assert_eq!(enum_attribute.get_enum_value(), 10);

    let enum_attribute2 = context.create_enum_attribute(3, 14);

    assert!(enum_attribute2.is_enum());
    assert!(!enum_attribute2.is_string());

    assert_eq!(enum_attribute2.get_enum_kind_id(), 3);
    assert_eq!(enum_attribute2.get_enum_value(), 14);

    let enum_attribute3 = context.create_enum_attribute(56, 20);

    assert!(enum_attribute3.is_enum());
    assert!(!enum_attribute3.is_string());

    assert_eq!(enum_attribute3.get_enum_kind_id(), 56);
    assert_eq!(enum_attribute3.get_enum_value(), 20);
}

#[test]
fn test_string_attributes() {
    let context = Context::create();
    let string_attribute = context.create_string_attribute("my_key_123", "my_val");

    assert!(!string_attribute.is_enum());
    assert!(string_attribute.is_string());

    assert_eq!(*string_attribute.get_string_kind_id(), *CString::new("my_key_123").unwrap());
    assert_eq!(*string_attribute.get_string_value(), *CString::new("my_val").unwrap());
}
<|endoftext|>


<commit_before>//! simple model-checking tools for rust.
//!
//! aims to reduce the boiler plate required
//! to write model-based and linearizability tests.
//!
//! it can find linearizability violations in
//! implementations without having any knowledge
//! of their inner-workings, by running sequential
//! operations on different commands and then
//! trying to find a sequential ordering that results
//! in the same return values.
//!
//! model-based testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//!# fn main() {
//! model! {
//!     Model => let m = AtomicUsize::new(0),
//!     Implementation => let mut i: usize = 0,
//!     Add(usize)(v in 0usize..4) => {
//!         let expected = m.fetch_add(v, Ordering::SeqCst) + v;
//!         i += v;
//!         assert_eq!(expected, i);
//!     },
//!     Set(usize)(v in 0usize..4) => {
//!         m.store(v, Ordering::SeqCst);
//!         i = v;
//!     },
//!     Eq(usize)(v in 0usize..4) => {
//!         let expected = m.load(Ordering::SeqCst) == v;
//!         let actual = i == v;
//!         assert_eq!(expected, actual);
//!     },
//!     Cas((usize, usize))((old, new) in (0usize..4, 0usize..4)) => {
//!         let expected =
//!             m.compare_and_swap(old, new, Ordering::SeqCst);
//!         let actual = if i == old {
//!             i = new;
//!             old
//!         } else {
//!             i
//!         };
//!         assert_eq!(expected, actual);
//!     }
//! }
//!# }
//! ```
//!
//! linearizability testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//!# fn main() {
//! linearizable! {
//!     Implementation => let i = Shared::new(AtomicUsize::new(0)),
//!     BuggyAdd(usize)(v in 0usize..4) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         i.store(current + v, Ordering::SeqCst);
//!         current + v
//!     },
//!     Set(usize)(v in 0usize..4) -> () {
//!         i.store(v, Ordering::SeqCst)
//!     },
//!     BuggyCas((usize, usize))((old, new) in (0usize..4, 0usize..4)) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         if current == old {
//!             i.store(new, Ordering::SeqCst);
//!             new
//!         } else {
//!             current
//!         }
//!     }
//! }
//!# }
//! ```
extern crate permutohedron;

use std::ops::Deref;

pub struct Shared<T>(*mut T);

impl<T> Clone for Shared<T> {
    fn clone(&self) -> Shared<T> {
        *self
    }
}

impl<T> Copy for Shared<T> {}

unsafe impl<T> Sync for Shared<T> {}

unsafe impl<T> Send for Shared<T> {}

impl<T> Deref for Shared<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Shared<T> {
    pub fn new(inner: T) -> Shared<T> {
        Shared(Box::into_raw(Box::new(inner)))
    }
}

#[macro_export]
macro_rules! model {
    (
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        model! {
            Config => Config::with_cases(1000).clone_with_source_file(file!()),
            Model => $model,
            Implementation => $implementation,
            $($op ($($type),*) ($parm in $strategy) => $body),*
        }
    };
    (
        Config => $config:expr,
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        fn arb() -> BoxedStrategy<Vec<Op>> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                0..40,
            ).boxed()
        }

        let config = $config;
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |ops| {
            $model;
            $implementation;

            for op in ops {
                match *op {
                    $(Op::$op($parm) => $body),*
                };
            };
            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

#[macro_export]
macro_rules! linearizable {
    (
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) -> $ret:ty $body:block),*
    ) => {
        use std::thread;

        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug, Clone)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        #[derive(Debug, PartialEq)]
        enum Ret {
            $(
                $op($ret)
            ),*
        }

        fn arb() -> BoxedStrategy<(usize, Vec<Op>)> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                1..4,
            )
                .prop_flat_map(|ops| (0..ops.len(), Just(ops)))
                .boxed()
        }

        let config = Config::with_cases(10000).clone_with_source_file(file!());
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |&(split_point, ref ops)| {
            $implementation;

            let ops1 = ops[0..split_point].to_vec();
            let ops2 = ops[split_point..].to_vec();

            let t1 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops1 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let t2 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops2 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let r1 = t1.join().expect("thread should not panic");
            let r2 = t2.join().expect("thread should not panic");

            // try to find sequential walk through ops
            let o1 = ops[0..split_point].to_vec();
            let o2 = ops[split_point..].to_vec();

            let calls1: Vec<(Op, Ret)> = o1.into_iter().zip(r1.into_iter()).collect();
            let calls2: Vec<(Op, Ret)> = o2.into_iter().zip(r2.into_iter()).collect();
            let mut indexes = vec![0; calls1.len()];
            indexes.resize(calls1.len() + calls2.len(), 1);
            let calls = vec![calls1, calls2];

            let mut linearizable = false;

            let call_permutations = model::permutohedron_heap(&mut indexes);

            'outer: for walk in call_permutations {
                $implementation;

                let mut indexes = vec![0, 0];
                // println!("trying walk {:?}", walk);

                for idx in walk {
                    let (ref op, ref expected) = calls[idx][indexes[idx]];
                    indexes[idx] += 1;

                    match *op {
                        $(
                            Op::$op($parm) => {
                                let ret = Ret::$op($body);
                                if ret != *expected {
                                    continue 'outer;
                                }
                            }
                        ),*
                    }
                }

                linearizable = true;
                break;
            }

            assert!(linearizable, "operations are not linearizable: {:?}", calls);

            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

pub fn permutohedron_heap<'a, Data, T>(
    orig: &'a mut Data,
) -> permutohedron::Heap<'a, Data, T>
    where Data: 'a + Sized + AsMut<[T]>,
          T: 'a
{
    permutohedron::Heap::new(orig)
}
<commit_msg>Fixed remaining issues preventing a proper doctest compilation.<commit_after>//! simple model-checking tools for rust.
//!
//! aims to reduce the boiler plate required
//! to write model-based and linearizability tests.
//!
//! it can find linearizability violations in
//! implementations without having any knowledge
//! of their inner-workings, by running sequential
//! operations on different commands and then
//! trying to find a sequential ordering that results
//! in the same return values.
//!
//! model-based testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//!# fn main() {
//! model! {
//!     Model => let m = AtomicUsize::new(0),
//!     Implementation => let mut i: usize = 0,
//!     Add(usize)(v in 0usize..4) => {
//!         let expected = m.fetch_add(v, Ordering::SeqCst) + v;
//!         i += v;
//!         assert_eq!(expected, i);
//!     },
//!     Set(usize)(v in 0usize..4) => {
//!         m.store(v, Ordering::SeqCst);
//!         i = v;
//!     },
//!     Eq(usize)(v in 0usize..4) => {
//!         let expected = m.load(Ordering::SeqCst) == v;
//!         let actual = i == v;
//!         assert_eq!(expected, actual);
//!     },
//!     Cas((usize, usize))((old, new) in (0usize..4, 0usize..4)) => {
//!         let expected =
//!             m.compare_and_swap(old, new, Ordering::SeqCst);
//!         let actual = if i == old {
//!             i = new;
//!             old
//!         } else {
//!             i
//!         };
//!         assert_eq!(expected, actual);
//!     }
//! }
//!# }
//! ```
//!
//! linearizability testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//!# fn main() {
//! linearizable! {
//!     Implementation => let i = model::Shared::new(AtomicUsize::new(0)),
//!     BuggyAdd(usize)(v in 0usize..4) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         i.store(current + v, Ordering::SeqCst);
//!         current + v
//!     },
//!     Set(usize)(v in 0usize..4) -> () {
//!         i.store(v, Ordering::SeqCst)
//!     },
//!     BuggyCas((usize, usize))((old, new) in (0usize..4, 0usize..4)) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         if current == old {
//!             i.store(new, Ordering::SeqCst);
//!             new
//!         } else {
//!             current
//!         }
//!     }
//! }
//!# }
//! ```
extern crate permutohedron;

use std::ops::Deref;

pub struct Shared<T>(*mut T);

impl<T> Clone for Shared<T> {
    fn clone(&self) -> Shared<T> {
        *self
    }
}

impl<T> Copy for Shared<T> {}

unsafe impl<T> Sync for Shared<T> {}

unsafe impl<T> Send for Shared<T> {}

impl<T> Deref for Shared<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Shared<T> {
    pub fn new(inner: T) -> Shared<T> {
        Shared(Box::into_raw(Box::new(inner)))
    }
}

#[macro_export]
macro_rules! model {
    (
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        model! {
            Config => Config::with_cases(1000).clone_with_source_file(file!()),
            Model => $model,
            Implementation => $implementation,
            $($op ($($type),*) ($parm in $strategy) => $body),*
        }
    };
    (
        Config => $config:expr,
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        fn arb() -> BoxedStrategy<Vec<Op>> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                0..40,
            ).boxed()
        }

        let config = $config;
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |ops| {
            $model;
            $implementation;

            for op in ops {
                match *op {
                    $(Op::$op($parm) => $body),*
                };
            };
            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

#[macro_export]
macro_rules! linearizable {
    (
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) -> $ret:ty $body:block),*
    ) => {
        use std::thread;

        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug, Clone)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        #[derive(Debug, PartialEq)]
        enum Ret {
            $(
                $op($ret)
            ),*
        }

        fn arb() -> BoxedStrategy<(usize, Vec<Op>)> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                1..4,
            )
                .prop_flat_map(|ops| (0..ops.len(), Just(ops)))
                .boxed()
        }

        let config = Config::with_cases(10000).clone_with_source_file(file!());
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |&(split_point, ref ops)| {
            $implementation;

            let ops1 = ops[0..split_point].to_vec();
            let ops2 = ops[split_point..].to_vec();

            let t1 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops1 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let t2 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops2 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let r1 = t1.join().expect("thread should not panic");
            let r2 = t2.join().expect("thread should not panic");

            // try to find sequential walk through ops
            let o1 = ops[0..split_point].to_vec();
            let o2 = ops[split_point..].to_vec();

            let calls1: Vec<(Op, Ret)> = o1.into_iter().zip(r1.into_iter()).collect();
            let calls2: Vec<(Op, Ret)> = o2.into_iter().zip(r2.into_iter()).collect();
            let mut indexes = vec![0; calls1.len()];
            indexes.resize(calls1.len() + calls2.len(), 1);
            let calls = vec![calls1, calls2];

            let mut linearizable = false;

            let call_permutations = model::permutohedron_heap(&mut indexes);

            'outer: for walk in call_permutations {
                $implementation;

                let mut indexes = vec![0, 0];
                // println!("trying walk {:?}", walk);

                for idx in walk {
                    let (ref op, ref expected) = calls[idx][indexes[idx]];
                    indexes[idx] += 1;

                    match *op {
                        $(
                            Op::$op($parm) => {
                                let ret = Ret::$op($body);
                                if ret != *expected {
                                    continue 'outer;
                                }
                            }
                        ),*
                    }
                }

                linearizable = true;
                break;
            }

            assert!(linearizable, "operations are not linearizable: {:?}", calls);

            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

pub fn permutohedron_heap<'a, Data, T>(
    orig: &'a mut Data,
) -> permutohedron::Heap<'a, Data, T>
    where Data: 'a + Sized + AsMut<[T]>,
          T: 'a
{
    permutohedron::Heap::new(orig)
}
<|endoftext|>


<commit_before>use postgres::{
    Rows,
    GenericConnection,
    Statement
};

use postgres::Result as PostgresResult;
use postgres::types::ToSql;
use deuterium::{SqlContext, QueryToSql};

pub type PostgresPool = ::r2d2::Pool<::r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPooledConnection<'a> = ::r2d2::PooledConnection<
    'a,
    ::r2d2_postgres::PostgresConnectionManager,
>;

pub fn setup(cn_str: &str, pool_size: u32) -> PostgresPool {
    let manager = ::r2d2_postgres::PostgresConnectionManager::new(cn_str, ::postgres::SslMode::None);
    let config = ::r2d2::Config::builder()
        .pool_size(pool_size)
        .build();

    let handler = Box::new(::r2d2::NoopErrorHandler);
    ::r2d2::Pool::new(config, manager, handler).unwrap()
}

#[allow(missing_copy_implementations)]
pub struct PostgresAdapter;

impl PostgresAdapter {
    pub fn prepare_query<'conn>(query: &QueryToSql, cn: &'conn GenericConnection) -> (SqlContext, PostgresResult<Statement<'conn>>){
        let mut ctx = SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        let sql = query.to_final_sql(&mut ctx);

        (ctx, cn.prepare(sql.as_slice()))
    }

    pub fn prepare_params<'a>(
            ext_params: &[&'a ToSql],
            ctx_params: &'a[Box<ToSql + 'static>]
        ) -> Vec<&'a (ToSql + 'a)> {

        let mut final_params = vec![];

        for param in ext_params.iter() {
            final_params.push(*param);
        }

        for param in ctx_params.iter() {
            final_params.push(&**param);
        }

        final_params
    }

    pub fn query<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<Rows<'conn>> {
        stm.query(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }

    pub fn execute<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<u64> {
        stm.execute(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }
}

pub trait FromRow {
    fn from_row<T, L>(query: &::deuterium::SelectQuery<T, L, Self>, row: &::postgres::Row) -> Self;
}

pub fn from_row<T, L, M: FromRow>(query: &::deuterium::SelectQuery<T, L, M>, row: &::postgres::Row) -> M {
    FromRow::from_row(query, row)
}

#[macro_export]
macro_rules! to_sql_string_pg {
    ($query:expr) => ({
        let mut ctx = ::deuterium::SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        $query.to_final_sql(&mut ctx)
    })
}

#[macro_export]
macro_rules! query_pg {
    ($query:expr, $cn:expr, $params:expr, $rows:ident, $blk:block) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = match maybe_stm {
            Ok(stm) => stm,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        };

        let $rows = ::deuterium_orm::adapter::postgres::PostgresAdapter::query(&stm, $params, ctx.data());

        let $rows = match $rows {
            Ok($rows) => $rows,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            ),
        };

        $blk
    });
}

#[macro_export]
macro_rules! query_models_iter {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! query_models {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            let vec: Vec<_> = rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            }).collect();
            vec
        })
    )
}

#[macro_export]
macro_rules! query_model {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().take(1).next().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! exec_pg_safe {
    ($query:expr, $cn:expr, $params:expr) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = maybe_stm.unwrap();
        ::deuterium_orm::adapter::postgres::PostgresAdapter::execute(&stm, $params, ctx.data())
    })
}

#[macro_export]
macro_rules! exec_pg {
    ($query:expr, $cn:expr, $params:expr) => ({
        match exec_pg_safe!($query, $cn, $params) {
            Ok(res) => res,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        }
    })
}

#[macro_export]
macro_rules! try_pg {
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(::postgres::Error::IoError(err))
        }
    )
}

#[macro_export]
macro_rules! deuterium_enum {
    ($en:ty) => (
        impl ::postgres::types::FromSql for $en {
            fn from_sql<R: ::std::io::Read>(ty: &::postgres::types::Type, raw: &mut R) -> ::postgres::Result<$en> {
                use ::byteorder::{ReadBytesExt};
                let val = raw.read_u8();
                match val {
                    Ok(val) => Ok(::std::num::FromPrimitive::from_u8(val).unwrap()),
                    Err(_) => Err(::postgres::Error::WrongType(ty.clone()))
                }
            }

            fn accepts(_ty: &::postgres::types::Type) -> bool {
                true
            }
        }

        impl ::deuterium::ToSql for $en {
            fn to_sql(&self, ctx: &mut ::deuterium::SqlContext) -> String {
                let i = self.clone() as i16;
                i.to_predicate_value(ctx)
            }
        }

        impl ::deuterium::UntypedExpression for $en {
            fn expression_as_sql(&self) -> &ToSql {
                self
            }

            fn upcast_expression(&self) -> SharedExpression {
                let i = self.clone() as i16;
                ::std::rc::Rc::new(Box::new(i) as ::deuterium::BoxedExpression)
            }
        }

        impl ::deuterium::ToExpression<$en> for $en {}
        impl ::deuterium::ToExpression<i16> for $en {}
        impl ::deuterium::ToExpression<RawExpression> for $en {}

        impl ::deuterium::ToPredicateValue for $en {
            fn to_predicate_value(&self, ctx: &mut SqlContext) -> String {
                let i = self.clone() as i16;
                ctx.hold(Box::new(i))
            }
        }
    )
}
<commit_msg>fix(adapter): Use latest `r2d2` API<commit_after>use postgres::{
    Rows,
    GenericConnection,
    Statement
};

use postgres::Result as PostgresResult;
use postgres::types::ToSql;
use deuterium::{SqlContext, QueryToSql};

pub type PostgresPool = ::r2d2::Pool<::r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPooledConnection<'a> = ::r2d2::PooledConnection<
    'a,
    ::r2d2_postgres::PostgresConnectionManager,
>;

pub fn setup(cn_str: &str, pool_size: u32) -> PostgresPool {
    let manager = ::r2d2_postgres::PostgresConnectionManager::new(cn_str, ::postgres::SslMode::None).unwrap();
    let config = ::r2d2::Config::builder()
        .pool_size(pool_size)
        .build();

    let handler = Box::new(::r2d2::NoopErrorHandler);
    ::r2d2::Pool::new(config, manager, handler).unwrap()
}

#[allow(missing_copy_implementations)]
pub struct PostgresAdapter;

impl PostgresAdapter {
    pub fn prepare_query<'conn>(query: &QueryToSql, cn: &'conn GenericConnection) -> (SqlContext, PostgresResult<Statement<'conn>>){
        let mut ctx = SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        let sql = query.to_final_sql(&mut ctx);

        (ctx, cn.prepare(sql.as_slice()))
    }

    pub fn prepare_params<'a>(
            ext_params: &[&'a ToSql],
            ctx_params: &'a[Box<ToSql + 'static>]
        ) -> Vec<&'a (ToSql + 'a)> {

        let mut final_params = vec![];

        for param in ext_params.iter() {
            final_params.push(*param);
        }

        for param in ctx_params.iter() {
            final_params.push(&**param);
        }

        final_params
    }

    pub fn query<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<Rows<'conn>> {
        stm.query(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }

    pub fn execute<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<ToSql + 'static>]) -> PostgresResult<u64> {
        stm.execute(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }
}

pub trait FromRow {
    fn from_row<T, L>(query: &::deuterium::SelectQuery<T, L, Self>, row: &::postgres::Row) -> Self;
}

pub fn from_row<T, L, M: FromRow>(query: &::deuterium::SelectQuery<T, L, M>, row: &::postgres::Row) -> M {
    FromRow::from_row(query, row)
}

#[macro_export]
macro_rules! to_sql_string_pg {
    ($query:expr) => ({
        let mut ctx = ::deuterium::SqlContext::new(Box::new(::deuterium::sql::adapter::PostgreSqlAdapter));
        $query.to_final_sql(&mut ctx)
    })
}

#[macro_export]
macro_rules! query_pg {
    ($query:expr, $cn:expr, $params:expr, $rows:ident, $blk:block) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = match maybe_stm {
            Ok(stm) => stm,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        };

        let $rows = ::deuterium_orm::adapter::postgres::PostgresAdapter::query(&stm, $params, ctx.data());

        let $rows = match $rows {
            Ok($rows) => $rows,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            ),
        };

        $blk
    });
}

#[macro_export]
macro_rules! query_models_iter {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! query_models {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            let vec: Vec<_> = rows.iter().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            }).collect();
            vec
        })
    )
}

#[macro_export]
macro_rules! query_model {
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.iter().take(1).next().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
}

#[macro_export]
macro_rules! exec_pg_safe {
    ($query:expr, $cn:expr, $params:expr) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = maybe_stm.unwrap();
        ::deuterium_orm::adapter::postgres::PostgresAdapter::execute(&stm, $params, ctx.data())
    })
}

#[macro_export]
macro_rules! exec_pg {
    ($query:expr, $cn:expr, $params:expr) => ({
        match exec_pg_safe!($query, $cn, $params) {
            Ok(res) => res,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        }
    })
}

#[macro_export]
macro_rules! try_pg {
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(::postgres::Error::IoError(err))
        }
    )
}

#[macro_export]
macro_rules! deuterium_enum {
    ($en:ty) => (
        impl ::postgres::types::FromSql for $en {
            fn from_sql<R: ::std::io::Read>(ty: &::postgres::types::Type, raw: &mut R) -> ::postgres::Result<$en> {
                use ::byteorder::{ReadBytesExt};
                let val = raw.read_u8();
                match val {
                    Ok(val) => Ok(::std::num::FromPrimitive::from_u8(val).unwrap()),
                    Err(_) => Err(::postgres::Error::WrongType(ty.clone()))
                }
            }

            fn accepts(_ty: &::postgres::types::Type) -> bool {
                true
            }
        }

        impl ::deuterium::ToSql for $en {
            fn to_sql(&self, ctx: &mut ::deuterium::SqlContext) -> String {
                let i = self.clone() as i16;
                i.to_predicate_value(ctx)
            }
        }

        impl ::deuterium::UntypedExpression for $en {
            fn expression_as_sql(&self) -> &ToSql {
                self
            }

            fn upcast_expression(&self) -> SharedExpression {
                let i = self.clone() as i16;
                ::std::rc::Rc::new(Box::new(i) as ::deuterium::BoxedExpression)
            }
        }

        impl ::deuterium::ToExpression<$en> for $en {}
        impl ::deuterium::ToExpression<i16> for $en {}
        impl ::deuterium::ToExpression<RawExpression> for $en {}

        impl ::deuterium::ToPredicateValue for $en {
            fn to_predicate_value(&self, ctx: &mut SqlContext) -> String {
                let i = self.clone() as i16;
                ctx.hold(Box::new(i))
            }
        }
    )
}
<|endoftext|>


<commit_before>use linalg::matrix::Matrix;
use learning::optim::OptimAlgorithm;

struct GradientDesc {
	alpha: f64,
	iters: usize
}

impl OptimAlgorithm<Matrix<f64>> for GradientDesc {
	fn optimize(&self, start: Matrix<f64>, f: &Fn(Matrix<f64>) -> (f64, Matrix<f64>)) -> Matrix<f64> {

		let mut optimizing_val = start.clone();

		for _i in 0..self.iters {
			optimizing_val = optimizing_val.clone() - f(optimizing_val.clone()).1 * self.alpha;
		}
		optimizing_val
	}
} <commit_msg>Making optimization generic.<commit_after>use std::ops::{Mul, Sub};
use learning::optim::OptimAlgorithm;

pub struct GradientDesc {
	alpha: f64,
	iters: usize
}

impl<T: Clone + Mul<f64, Output=T> + Sub<T, Output=T>> OptimAlgorithm<T> for GradientDesc {
	fn optimize(&self, start: T, f: &Fn(T) -> (f64, T)) -> T {

		let mut optimizing_val = start.clone();

		for _i in 0..self.iters {
			optimizing_val = optimizing_val.clone() - f(optimizing_val.clone()).1 * self.alpha;
		}
		optimizing_val
	}
} <|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Fabian Schuiki

//! The subtyping mechanism.

use std::fmt::{self, Debug, Display};

/// An interface for dealing with subtypes.
pub trait Subtype: Debug + Display {
}
<commit_msg>vhdl: add preliminary enum subtype<commit_after>// Copyright (c) 2017-2018 Fabian Schuiki

//! The subtyping mechanism.

use std::fmt::{self, Debug, Display};

use ty2::{Type, TypeMark, Range, BigInt, EnumType, IntegerType, FloatingType, PhysicalType};

/// An interface for dealing with subtypes.
pub trait Subtype: Debug + Display {
}

/// A subtype of a scalar type.
///
/// Scalar types may be subtyped by a range constraint.
#[derive(Debug)]
pub struct ScalarSubtype<'t, T: Type + 't, C> {
    #[allow(dead_code)]
    resfn: Option<usize>,
    mark: &'t TypeMark<'t>,
    base: &'t T,
    con: Range<C>,
}

/// A subtype of an enumeration type.
pub type EnumSubtype<'t> = ScalarSubtype<'t, EnumType, usize>;

impl<'t> EnumSubtype<'t> {
    /// Create a new enumeration subtype.
    ///
    /// # Example
    ///
    /// ```
    /// use moore_vhdl::ty2::{Type, TypeMark, EnumType, EnumSubtype, Range};
    /// use moore_vhdl::common::name::get_name_table;
    ///
    /// let ty = EnumType::new(vec![
    ///     "first".into(),
    ///     "second".into(),
    ///     '0'.into(),
    ///     '1'.into(),
    /// ]);
    /// let tm = TypeMark::new(
    ///     get_name_table().intern("MY_TYPE", false),
    ///     &ty,
    /// );
    /// let subty = EnumSubtype::new(&tm, Range::ascending(1usize, 2usize));
    ///
    /// assert_eq!(format!("{}", subty), "MY_TYPE range second to '0'");
    /// ```
    pub fn new(mark: &'t TypeMark, con: Range<usize>) -> EnumSubtype<'t> {
        let base = mark.as_any().unwrap_enum();
        assert!(*con.upper() <= base.len());
        EnumSubtype {
            resfn: None,
            mark: mark,
            base: base,
            con: con,
        }
    }
}

impl<'t> Subtype for EnumSubtype<'t> {
}

impl<'t> Display for EnumSubtype<'t> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{} range {} {} {}",
            self.mark,
            self.base.literal(*self.con.left()),
            self.con.dir(),
            self.base.literal(*self.con.right()),
        )
	}
}

/// A subtype of an integer type.
pub type IntegerSubtype<'t> = ScalarSubtype<'t, IntegerType, BigInt>;

/// A subtype of a floating-point type.
pub type FloatingSubtype<'t> = ScalarSubtype<'t, FloatingType, f64>;

/// A subtype of a physical type.
pub type PhysicalSubtype<'t> = ScalarSubtype<'t, PhysicalType, BigInt>;
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;
use gtk::{ApplicationWindow, Button, FileChooserAction, FileChooserDialog,
          HeaderBar, ResponseType, Label, ToolButton};

use ::media::{Context, ContextMessage, Timestamp};
use ::media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    play_pause_btn: ToolButton,
    position_lbl: Label,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: Rc<RefCell<AudioController>>,

    context: Option<Context>,
    duration: u64,
    last_position: u64,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),
            position_lbl: builder.get_object("position-lbl").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            duration: 0,
            last_position: 0,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = this.clone();
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = this.clone();
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let this_rc = this.clone();
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => return,
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(25); // 40 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.borrow_mut().cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        if file_dlg.run() == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    )
    {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut message_iter = ui_rx.try_iter();

            let mut keep_going = true;
            for message in message_iter.next() {
                match message {
                    AsyncDone => {
                        println!("Received AsyncDone");
                    },
                    InitDone => {
                        println!("Received InitDone");

                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("... but no context available");

                        let duration = context.get_duration();
                        if duration.is_negative() {
                            panic!("Negative duration");
                        }
                        this_mut.duration = duration as u64;

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.borrow_mut().new_media(&context);

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        println!("Received Eos");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.remove_tracker();
                        let duration = this_mut.duration;
                        this_mut.tic(duration);

                        // TODO: exit tracker
                        this_mut.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn tic(&mut self, position: u64) {
        self.position_lbl.set_text(
            &format!("{}", Timestamp::from_nano(position as i64))
        );
        self.last_position = position;

        self.audio_ctrl.borrow_mut().tic(position);
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            let mut this_mut = this_rc.borrow_mut();

            if this_mut.keep_going {
                let position = this_mut.context.as_mut()
                    .expect("No context in tracker")
                    .get_position();
                if this_mut.last_position != position {
                    if position <= this_mut.duration {
                        this_mut.tic(position);
                    }
                }
            } else {
                this_mut.tracker_src = None;
                println!("Exiting tracker");
            }

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.position_lbl.set_text("00:00.000");

        let (ctx_tx, ui_rx) = channel();

        self.keep_going = true;
        self.register_listener(500, ui_rx);

        match Context::open_media_path(
                filepath,
                10_000_000_000,
                self.video_ctrl.video_box.clone(),
                ctx_tx
            )
            {
            Ok(context) => {
                self.context = Some(context);
                self.last_position = 0;
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<commit_msg>MainController: simplify tracker a bit (#25)<commit_after>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;
use gtk::{ApplicationWindow, Button, FileChooserAction, FileChooserDialog,
          HeaderBar, ResponseType, Label, ToolButton};

use ::media::{Context, ContextMessage, Timestamp};
use ::media::ContextMessage::*;

use super::{AudioController, InfoController, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    play_pause_btn: ToolButton,
    position_lbl: Label,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: Rc<RefCell<AudioController>>,

    context: Option<Context>,
    duration: u64,
    last_position: u64,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),
            position_lbl: builder.get_object("position-lbl").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            duration: 0,
            last_position: 0,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = this.clone();
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = this.clone();
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let this_rc = this.clone();
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => return,
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(25); // 40 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.borrow_mut().cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        if file_dlg.run() == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    )
    {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut message_iter = ui_rx.try_iter();

            let mut keep_going = true;
            for message in message_iter.next() {
                match message {
                    AsyncDone => {
                        println!("Received AsyncDone");
                    },
                    InitDone => {
                        println!("Received InitDone");

                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("... but no context available");

                        let duration = context.get_duration();
                        if duration.is_negative() {
                            panic!("Negative duration");
                        }
                        this_mut.duration = duration as u64;

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.borrow_mut().new_media(&context);

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        println!("Received Eos");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.remove_tracker();
                        let duration = this_mut.duration;
                        this_mut.tic(duration);

                        // TODO: exit tracker
                        this_mut.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn tic(&mut self, position: u64) {
        self.position_lbl.set_text(
            &format!("{}", Timestamp::from_nano(position as i64))
        );
        self.last_position = position;

        self.audio_ctrl.borrow_mut().tic(position);
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            let mut this_mut = this_rc.borrow_mut();

            let position = this_mut.context.as_mut()
                .expect("No context in tracker")
                .get_position();
            if this_mut.last_position != position
            && position <= this_mut.duration {
                this_mut.tic(position);
            }

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.position_lbl.set_text("00:00.000");

        let (ctx_tx, ui_rx) = channel();

        self.keep_going = true;
        self.register_listener(500, ui_rx);

        match Context::open_media_path(
                filepath,
                10_000_000_000,
                self.video_ctrl.video_box.clone(),
                ctx_tx
            )
            {
            Ok(context) => {
                self.context = Some(context);
                self.last_position = 0;
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>


<commit_before>use std::os::getenv;

struct HttpContext{
    request: Request,
    response: Response
}

impl HttpContext{
    fn create() -> HttpContext{
        HttpContext{
            request: Request::populate(),
            response: Response::new()
        }
    }
}

struct Request {
    path: ~str,
    querystring: ~str
}

impl Request {
    fn populate() -> Request {
        Request{
            path: getenv("PATH_INFO").unwrap_or(~""),
            querystring: getenv("QUERY_STRING").unwrap_or(~"")
        }
    }
}

struct Response{
    contenttype: ~str,
    body: ~str
}

impl Response{
    fn new() -> Response{
        Response{contenttype: ~"text/plain", body: ~""}
    }
}

struct Route {
    path: ~str,
    handler: ~fn(&mut HttpContext)
}

struct Router{
    routes: ~[Route],
}

impl Router{
    fn new() -> Router{
        Router{routes: ~[]}
    }
    fn add(&mut self, r: Route){
        self.routes.push(r);
    }
    fn execute(&self, c: &mut HttpContext) {
        for route in self.routes.iter(){
            if(route.path == c.request.path){
                (route.handler)(c);
            }
        }
    }
    fn controller<T>(~self, creator: ~fn(&HttpContext) -> T) -> ControllerBox<T>
    {
        ControllerBox{
            router: self,
            route: ~Route{path: ~"", handler: default_handler},
            creator: Some(creator)
        }
    }
}

trait HttpController{

}

struct ControllerBox<T>{
    router: ~Router,
    route: ~Route,
    creator: Option<~fn(&HttpContext) -> T>
}

impl<T> ControllerBox<T>{
    fn handles(@mut self, path: ~str) -> @mut ControllerBox<T>{
        self.route.path=path;
        self
    }
    fn with<'r>(&'r mut self, invoker: ~fn(&T)) -> &'r mut ControllerBox<T>{
        let tmp=self.creator.take();

        self.route.handler = |c| {
            match tmp {
                None => (),
                Some(t) => {
                    let ctrl=(t)(c);
                    invoker(&ctrl);
                }
            };
        };
        self
    }
}
/*
struct Meh{
    biz: ~fn(int) -> int
}

impl Meh{
    fn foo(@mut self
}
*/

fn default_handler(context: &mut HttpContext){
    context.response.body.push_str("404 not found");
}

fn index(context: &mut HttpContext){
    context.response.body.push_str("yay index");
}

fn foo(context: &mut HttpContext){
    context.response.body.push_str("yay foo");
}

fn main() {
    let mut context=HttpContext::create();
    let mut router=Router::new();
    router.add(Route{path: ~"", handler: index});
    router.add(Route{path: ~"/foo", handler: foo});
    router.execute(&mut context);
    println(context.response.contenttype);
    println("");
    println(context.response.body);
}<commit_msg>It does the same thing, except for this compiles for some reason<commit_after>use std::os::getenv;

struct HttpContext{
    request: Request,
    response: Response
}

impl HttpContext{
    fn create() -> HttpContext{
        HttpContext{
            request: Request::populate(),
            response: Response::new()
        }
    }
}

struct Request {
    path: ~str,
    querystring: ~str
}

impl Request {
    fn populate() -> Request {
        Request{
            path: getenv("PATH_INFO").unwrap_or(~""),
            querystring: getenv("QUERY_STRING").unwrap_or(~"")
        }
    }
}

struct Response{
    contenttype: ~str,
    body: ~str
}

impl Response{
    fn new() -> Response{
        Response{contenttype: ~"text/plain", body: ~""}
    }
}

struct Route {
    path: ~str,
    handler: ~fn(&mut HttpContext)
}

struct Router{
    routes: ~[Route],
}

impl Router{
    fn new() -> Router{
        Router{routes: ~[]}
    }
    fn add(&mut self, r: Route){
        self.routes.push(r);
    }
    fn execute(&self, c: &mut HttpContext) {
        for route in self.routes.iter(){
            if(route.path == c.request.path){
                (route.handler)(c);
            }
        }
    }
    fn controller<T>(~self, creator: ~fn(&HttpContext) -> T) -> ControllerBox<T>
    {
        ControllerBox{
            router: self,
            route: ~Route{path: ~"", handler: default_handler},
            creator: Some(creator)
        }
    }
}

trait HttpController{

}

struct ControllerBox<T>{
    router: ~Router,
    route: ~Route,
    creator: Option<~fn(&HttpContext) -> T>
}

impl<T> ControllerBox<T>{
    fn handles(@mut self, path: ~str) -> @mut ControllerBox<T>{
        self.route.path=path;
        self
    }
    fn with<'r>(&'r mut self, invoker: ~fn(&T)) -> &'r mut ControllerBox<T>{
        let tmp=self.creator.take();

        self.route.handler = |c| {
            match tmp {
                None => (),
                Some(ref t) => {
                    let ctrl=(*t)(c);
                    invoker(&ctrl);
                }
            };
        };
        self
    }
}
/*
struct Meh{
    biz: ~fn(int) -> int
}

impl Meh{
    fn foo(@mut self
}
*/

fn default_handler(context: &mut HttpContext){
    context.response.body.push_str("404 not found");
}

fn index(context: &mut HttpContext){
    context.response.body.push_str("yay index");
}

fn foo(context: &mut HttpContext){
    context.response.body.push_str("yay foo");
}

fn main() {
    let mut context=HttpContext::create();
    let mut router=Router::new();
    router.add(Route{path: ~"", handler: index});
    router.add(Route{path: ~"/foo", handler: foo});
    router.execute(&mut context);
    println(context.response.contenttype);
    println("");
    println(context.response.body);
}<|endoftext|>