<commit_before>//! A very simple wrapper for LLVM that can JIT functions written as IR strings.

extern crate llvm_sys as llvm;

use std::error::Error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::result::Result;
use std::ops::Drop;
use std::os::raw::c_char;
use std::sync::{Once, ONCE_INIT};

use llvm::execution_engine::LLVMMCJITCompilerOptions;
use llvm::analysis::LLVMVerifierFailureAction;
use llvm::transforms::pass_manager_builder as pmb;

#[cfg(test)]
mod tests;

static ONCE: Once = ONCE_INIT;
static mut initialize_failed: bool = false;

/// Error type returned by easy_ll.
#[derive(Debug)]
pub struct LlvmError(String);

impl LlvmError {
    fn new(description: &str) -> LlvmError { LlvmError(description.to_string()) }
}

impl fmt::Display for LlvmError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for LlvmError {
    fn description(&self) -> &str { &self.0 }

    fn cause(&self) -> Option<&Error> { None }
}

impl From<NulError> for LlvmError {
    fn from(_: NulError) -> LlvmError { LlvmError::new("Null byte in string") }
}

/// A compiled module returned by `compile_module`, wrapping a `run` function that takes `i64`
/// and returns `i64`. This structure includes (and manages) an LLVM execution engine, which is
/// freed when this structure is dropped.
#[derive(Debug)]
pub struct CompiledModule {
    context: llvm::prelude::LLVMContextRef,
    engine: Option<llvm::execution_engine::LLVMExecutionEngineRef>,
    function: Option<extern "C" fn(i64) -> i64>
}

impl CompiledModule {
    /// Call the module's `run` function.
    pub fn run(&self, arg: i64) -> i64 {
        (self.function.unwrap())(arg)
    }
}

impl Drop for CompiledModule {
    /// Disposes of the LLVM execution engine and compiled function.
    fn drop(&mut self) {
        unsafe {
            self.engine.map(|e| {
                llvm::execution_engine::LLVMDisposeExecutionEngine(e)
            });
            llvm::core::LLVMContextDispose(self.context);
        }
    }
}

/// Initialize LLVM or save an error message in `initialize_failed` if this does not work.
/// We call this function only once in cases some steps are expensive.
fn initialize() {
    unsafe {
        if llvm::target::LLVM_InitializeNativeTarget() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmPrinter() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmParser() != 0 {
            initialize_failed = true;
            return;
        }
        llvm::execution_engine::LLVMLinkInMCJIT();
    }
}

/// Compile a string of LLVM IR (in human readable format) into a `CompiledModule` that can then
/// be executed. The LLVM IR should contain an entry point function called `run` that takes `i64`
/// and returns `i64`, which will be called by `CompiledModule::run`.
pub fn compile_module(code: &str) -> Result<CompiledModule, LlvmError> {
    unsafe {
        // Initialize LLVM
        ONCE.call_once(|| initialize());
        if initialize_failed {
            return Err(LlvmError::new("LLVM initialization failed"))
        }

        // Create an LLVM context
        let context = llvm::core::LLVMContextCreate();
        if context.is_null() {
            return Err(LlvmError::new("LLVMContextCreate returned null"))
        }

        // Create a module
        let mut result = CompiledModule { context: context, engine: None, function: None };

        // Create a memory buffer to hold the code
        let code_len = code.len();
        let name = try!(CString::new("module"));
        let code = try!(CString::new(code));
        let buffer = llvm::core::LLVMCreateMemoryBufferWithMemoryRange(
            code.as_ptr(), code_len, name.as_ptr(), 0);
        if buffer.is_null() {
            return Err(LlvmError::new("LLVMCreateMemoryBufferWithMemoryRange failed"))
        }

        // Parse IR into a module
        let mut module = 0 as llvm::prelude::LLVMModuleRef;
        let mut error_str = 0 as *mut c_char;
        let result_code = llvm::ir_reader::LLVMParseIRInContext(
            context, buffer, &mut module, &mut error_str);
        if result_code != 0 {
            let msg = format!("Compile error: {}", CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }

        // Verify module
        let mut error_str = 0 as *mut c_char;
        let result_code = llvm::analysis::LLVMVerifyModule(
            module, LLVMVerifierFailureAction::LLVMReturnStatusAction, &mut error_str);
        if result_code != 0 {
            let msg = format!("Module verification failed: {}",
                CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }

        // Check that a "run" function exists and has type i64 -> i64
        let run_c_str = CString::new("run").unwrap().as_ptr();
        let func = llvm::core::LLVMGetNamedFunction(module, run_c_str);
        if func.is_null() {
            return Err(LlvmError::new("No run function in module"));
        }
        let c_str = llvm::core::LLVMPrintTypeToString(llvm::core::LLVMTypeOf(func));
        let func_type = CStr::from_ptr(c_str).to_str().unwrap();
        if func_type != "i64 (i64)*" {
            return Err(LlvmError(format!("Wrong function type: {}", func_type)));
        }

        // Optimize module
        let manager = llvm::core::LLVMCreatePassManager();
        if manager.is_null() {
            return Err(LlvmError::new("LLVMCreatePassManager returned null"))
        }
        let builder = pmb::LLVMPassManagerBuilderCreate();
        if builder.is_null() {
            return Err(LlvmError::new("LLVMPassManagerBuilderCreate returned null"))
        }
        // TODO: not clear we need both Module and LTO calls here; just LTO might work
        pmb::LLVMPassManagerBuilderSetOptLevel(builder, 2);
        pmb::LLVMPassManagerBuilderPopulateModulePassManager(builder, manager);
        pmb::LLVMPassManagerBuilderPopulateLTOPassManager(builder, manager, 1, 1);
        pmb::LLVMPassManagerBuilderDispose(builder);
        llvm::core::LLVMRunPassManager(manager, module);
        llvm::core::LLVMDisposePassManager(manager);

        // Create an execution engine
        let mut engine = 0 as llvm::execution_engine::LLVMExecutionEngineRef;
        let mut error_str = 0 as *mut c_char;
        let mut options: LLVMMCJITCompilerOptions = std::mem::uninitialized();
        let options_size = std::mem::size_of::<LLVMMCJITCompilerOptions>();
        llvm::execution_engine::LLVMInitializeMCJITCompilerOptions(&mut options, options_size);
        options.OptLevel = 2;
        let result_code = llvm::execution_engine::LLVMCreateMCJITCompilerForModule(
            &mut engine, module, &mut options, options_size, &mut error_str);
        if result_code != 0 {
            let msg = format!("Creating execution engine failed: {}",
                CStr::from_ptr(error_str).to_str().unwrap());
            return Err(LlvmError(msg));
        }
        result.engine = Some(engine);

        // Find the "run" function
        let func_address = llvm::execution_engine::LLVMGetFunctionAddress(engine, run_c_str);
        if func_address == 0 {
            return Err(LlvmError::new("No run function in module"))
        }
        let function: extern fn(i64) -> i64 = std::mem::transmute(func_address);
        result.function = Some(function);

        Ok(result)
    }
}<commit_msg>Nicer structure<commit_after>//! A very simple wrapper for LLVM that can JIT functions written as IR strings.

extern crate llvm_sys as llvm;

use std::error::Error;
use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::result::Result;
use std::ops::Drop;
use std::os::raw::c_char;
use std::sync::{Once, ONCE_INIT};

use llvm::prelude::{LLVMContextRef, LLVMModuleRef};
use llvm::execution_engine::{LLVMExecutionEngineRef, LLVMMCJITCompilerOptions};
use llvm::analysis::LLVMVerifierFailureAction;
use llvm::transforms::pass_manager_builder as pmb;

#[cfg(test)]
mod tests;

static ONCE: Once = ONCE_INIT;
static mut initialize_failed: bool = false;

/// Error type returned by easy_ll.
#[derive(Debug)]
pub struct LlvmError(String);

impl LlvmError {
    fn new(description: &str) -> LlvmError { LlvmError(description.to_string()) }
}

impl fmt::Display for LlvmError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for LlvmError {
    fn description(&self) -> &str { &self.0 }

    fn cause(&self) -> Option<&Error> { None }
}

impl From<NulError> for LlvmError {
    fn from(_: NulError) -> LlvmError { LlvmError::new("Null byte in string") }
}

/// The type of our "run" function pointer.
type RunFunc = extern "C" fn(i64) -> i64;

/// A compiled module returned by `compile_module`, wrapping a `run` function that takes `i64`
/// and returns `i64`. This structure includes (and manages) an LLVM execution engine, which is
/// freed when this structure is dropped.
#[derive(Debug)]
pub struct CompiledModule {
    context: LLVMContextRef,
    engine: Option<LLVMExecutionEngineRef>,
    function: Option<RunFunc>
}

impl CompiledModule {
    /// Call the module's `run` function.
    pub fn run(&self, arg: i64) -> i64 {
        (self.function.unwrap())(arg)
    }
}

impl Drop for CompiledModule {
    /// Disposes of the LLVM execution engine and compiled function.
    fn drop(&mut self) {
        unsafe {
            self.engine.map(|e| {
                llvm::execution_engine::LLVMDisposeExecutionEngine(e)
            });
            llvm::core::LLVMContextDispose(self.context);
        }
    }
}

/// Initialize LLVM or save an error message in `initialize_failed` if this does not work.
/// We call this function only once in cases some steps are expensive.
fn initialize() {
    unsafe {
        if llvm::target::LLVM_InitializeNativeTarget() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmPrinter() != 0 {
            initialize_failed = true;
            return;
        }
        if llvm::target::LLVM_InitializeNativeAsmParser() != 0 {
            initialize_failed = true;
            return;
        }
        llvm::execution_engine::LLVMLinkInMCJIT();
    }
}

/// Compile a string of LLVM IR (in human readable format) into a `CompiledModule` that can then
/// be executed. The LLVM IR should contain an entry point function called `run` that takes `i64`
/// and returns `i64`, which will be called by `CompiledModule::run`.
pub fn compile_module(code: &str) -> Result<CompiledModule, LlvmError> {
    unsafe {
        // Initialize LLVM
        ONCE.call_once(|| initialize());
        if initialize_failed {
            return Err(LlvmError::new("LLVM initialization failed"))
        }

        // Create an LLVM context
        let context = llvm::core::LLVMContextCreate();
        if context.is_null() {
            return Err(LlvmError::new("LLVMContextCreate returned null"))
        }

        // Create a CompiledModule to wrap the context and our result (will clean it on Drop).
        let mut result = CompiledModule { context: context, engine: None, function: None };

        // Parse the IR to get an LLVMModuleRef
        let module = try!(parse_module(context, code));

        // Validate and optimize the module
        try!(validate_module(module));
        try!(optimize_module(module));

        // Create an execution engine for the module and find its run function
        let engine = try!(create_exec_engine(module));
        result.engine = Some(engine);
        result.function = Some(try!(find_run_function(engine)));

        Ok(result)
    }
}

/// Parse a string of IR code into an `LLVMModuleRef` for the given context.
unsafe fn parse_module(context: LLVMContextRef, code: &str) -> Result<LLVMModuleRef, LlvmError> {
    // Create an LLVM memory buffer around the code
    let code_len = code.len();
    let name = try!(CString::new("module"));
    let code = try!(CString::new(code));
    let buffer = llvm::core::LLVMCreateMemoryBufferWithMemoryRange(
        code.as_ptr(), code_len, name.as_ptr(), 0);
    if buffer.is_null() {
        return Err(LlvmError::new("LLVMCreateMemoryBufferWithMemoryRange failed"))
    }

    // Parse IR into a module
    let mut module = 0 as LLVMModuleRef;
    let mut error_str = 0 as *mut c_char;
    let result_code = llvm::ir_reader::LLVMParseIRInContext(
        context, buffer, &mut module, &mut error_str);
    if result_code != 0 {
        let msg = format!("Compile error: {}", CStr::from_ptr(error_str).to_str().unwrap());
        return Err(LlvmError(msg));
    }

    Ok(module)
}

/// Validate a module for use by `easy_ll` (checks both LLVM soundness and that the module
/// has a run function with our expected signature).
unsafe fn validate_module(module: LLVMModuleRef) -> Result<(), LlvmError> {
    // Let LLVM verify basic structure of the module (e.g. phi nodes)
    let mut error_str = 0 as *mut c_char;
    let result_code = llvm::analysis::LLVMVerifyModule(
        module, LLVMVerifierFailureAction::LLVMReturnStatusAction, &mut error_str);
    if result_code != 0 {
        let msg = format!("Module verification failed: {}",
            CStr::from_ptr(error_str).to_str().unwrap());
        return Err(LlvmError(msg));
    }

    // Check that a "run" function exists and has type i64 -> i64
    let run_c_str = CString::new("run").unwrap().as_ptr();
    let func = llvm::core::LLVMGetNamedFunction(module, run_c_str);
    if func.is_null() {
        return Err(LlvmError::new("No run function in module"));
    }
    let c_str = llvm::core::LLVMPrintTypeToString(llvm::core::LLVMTypeOf(func));
    let func_type = CStr::from_ptr(c_str).to_str().unwrap();
    if func_type != "i64 (i64)*" {
        return Err(LlvmError(format!("Wrong function type: {}", func_type)));
    }

    Ok(())
}

/// Optimize an LLVM module using our chosen passes (currently uses standard passes for -O2).
unsafe fn optimize_module(module: LLVMModuleRef) -> Result<(), LlvmError> {
    let manager = llvm::core::LLVMCreatePassManager();
    if manager.is_null() {
        return Err(LlvmError::new("LLVMCreatePassManager returned null"))
    }
    let builder = pmb::LLVMPassManagerBuilderCreate();
    if builder.is_null() {
        return Err(LlvmError::new("LLVMPassManagerBuilderCreate returned null"))
    }
    // TODO: not clear we need both Module and LTO calls here; just LTO might work
    pmb::LLVMPassManagerBuilderSetOptLevel(builder, 2);
    pmb::LLVMPassManagerBuilderPopulateModulePassManager(builder, manager);
    pmb::LLVMPassManagerBuilderPopulateLTOPassManager(builder, manager, 1, 1);
    pmb::LLVMPassManagerBuilderDispose(builder);
    llvm::core::LLVMRunPassManager(manager, module);
    llvm::core::LLVMDisposePassManager(manager);
    Ok(())
}

/// Create an MCJIT execution engine for a given module.
unsafe fn create_exec_engine(module: LLVMModuleRef) -> Result<LLVMExecutionEngineRef, LlvmError> {
    let mut engine = 0 as LLVMExecutionEngineRef;
    let mut error_str = 0 as *mut c_char;
    let mut options: LLVMMCJITCompilerOptions = std::mem::uninitialized();
    let options_size = std::mem::size_of::<LLVMMCJITCompilerOptions>();
    llvm::execution_engine::LLVMInitializeMCJITCompilerOptions(&mut options, options_size);
    options.OptLevel = 2;
    let result_code = llvm::execution_engine::LLVMCreateMCJITCompilerForModule(
        &mut engine, module, &mut options, options_size, &mut error_str);
    if result_code != 0 {
        let msg = format!("Creating execution engine failed: {}",
            CStr::from_ptr(error_str).to_str().unwrap());
        return Err(LlvmError(msg));
    }
    Ok(engine)
}

/// Get a pointer to the "run" function in an execution engine.
unsafe fn find_run_function(engine: LLVMExecutionEngineRef) -> Result<RunFunc, LlvmError> {
    let run_c_str = CString::new("run").unwrap().as_ptr();
    let func_addr = llvm::execution_engine::LLVMGetFunctionAddress(engine, run_c_str);
    if func_addr == 0 {
        return Err(LlvmError::new("No run function in module"))
    }
    let function: RunFunc = std::mem::transmute(func_addr);
    Ok(function)
}<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;

#[macro_use]
use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> {
    type List ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Rc<Self::List>) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (&mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Rc<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Rc<Self::List>) -> Res ;

    fn fold<Res,Cons> (self:&Self, &mut A, &Self::List, Res, Cons) -> Res
        where Cons:Fn(&mut A, Res, &Hd) -> Res ;

    // TODO: Add derived operations (max, min, sum, etc.)
}

// Questions:
//  - Should `Name`s always be passed by reference?
//  - Do these Fn argss for fold need to be passed in `Rc<Box<_>>`s ?

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> {
    type Tree ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Rc<Self::Tree>, Rc<Self::Tree>) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Rc<Self::Tree>, Rc<Self::Tree>) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC> (&mut A, Self::Tree, Res, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Res, Leaf) -> Res
        ,      BinC:Fn(&mut A, Res, Bin ) -> Res ;

    fn fold2<Arg,Res,LeafC,BinC> (&mut A, Self::Tree, Arg, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Arg, Leaf) -> Res
        ,      BinC:Fn(&mut A, Arg, Bin, Res, Res ) -> Res ;
}

#[derive(Debug,PartialEq,Eq,Hash)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,Rc<List<A,Hd>>),
    Name(A::Name,Rc<List<A,Hd>>),
    Art(Art<List<A,Hd>, A::Loc>),
}

impl<A:Adapton+Debug+PartialEq+Eq+Hash,Hd:Debug+PartialEq+Eq+Hash> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                                 -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Rc<Self::List>)       -> Self::List { List::Cons(hd,tl) }
    fn name (_:&mut A, nm:A::Name, tl:Rc<Self::List>)  -> Self::List { List::Name(nm, tl) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>)     -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Rc<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Rc<Self::List>) -> Res
    {
        panic!("")
    }
    fn fold<Res,Cons> (self:&Self, st:&mut A, list:&Self::List, res:Res, consf:Cons) -> Res
        where Cons:Fn(&mut A, Res, &Hd) -> Res
    {
        match *list {
            List::Nil => res,
            List::Cons(ref hd, ref tl) => {
                let res = consf(st, res, hd) ;
                self.fold(st, &*tl, res, consf)
            },
            List::Name(_, ref tl) => self.fold(st, &*tl, res, consf),
            List::Art(ref art) => {
                let list = st.force(art) ;
                self.fold(st, &*list, res, consf)
            }
        }
    }
}

pub fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, list:&Rc<L::List>, left_tree:&Rc<T::Tree>)
     -> (Rc<T::Tree>, Rc<L::List>)
{
    L::elim (
        st, &list,
        /* Nil */  |st| ( Rc::new(T::nil(st)), Rc::new(L::nil(st)) ),
        /* Cons */ |st, hd, rest| {
            if my_hash( hd ) == 0 {
                let nil = Rc::new(T::nil(st)) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, rest, &nil ) ;
                let tree = Rc::new(T::bin ( st, hd.clone(), left_tree.clone(), right_tree )) ;
                tree_of_list_rec::<A,X,T,L> ( st, &rest, &tree )
            }
            else {
                let c = Rc::new(L::cons(st, hd.clone(), rest.clone())) ;
                (left_tree.clone(), c)
            }},
        /* Name */ |st, nm, rest| {
            if my_hash( nm ) == 0 {
                let nil = Rc::new(T::nil(st)) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, rest, &nil ) ;
                // TODO: Place left_ and right_ trees into articulations, named by name.
                let tree = Rc::new(T::name( st, nm.clone(), left_tree.clone(), right_tree )) ;
                tree_of_list_rec::<A,X,T,L> ( st, &rest, &tree )
            }
            else {
                let c = Rc::new(L::name(st, nm.clone(), rest.clone())) ;
                (left_tree.clone(), c)
            }}
        )
}
<commit_msg>wrote generic list elim<commit_after>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;

#[macro_use]
use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> {
    type List ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Rc<Self::List>) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (self:&Self, &mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Rc<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Rc<Self::List>) -> Res ;

    fn fold<Res,Cons> (self:&Self, &mut A, &Self::List, Res, Cons) -> Res
        where Cons:Fn(&mut A, Res, &Hd) -> Res ;

    // TODO: Add derived operations (max, min, sum, etc.)
}

// Questions:
//  - Should `Name`s always be passed by reference?
//  - Do these Fn argss for fold need to be passed in `Rc<Box<_>>`s ?

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> {
    type Tree ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Rc<Self::Tree>, Rc<Self::Tree>) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Rc<Self::Tree>, Rc<Self::Tree>) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC> (&mut A, Self::Tree, Res, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Res, Leaf) -> Res
        ,      BinC:Fn(&mut A, Res, Bin ) -> Res ;

    fn fold2<Arg,Res,LeafC,BinC> (&mut A, Self::Tree, Arg, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Arg, Leaf) -> Res
        ,      BinC:Fn(&mut A, Arg, Bin, Res, Res ) -> Res ;
}

#[derive(Debug,PartialEq,Eq,Hash)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,Rc<List<A,Hd>>),
    Name(A::Name,Rc<List<A,Hd>>),
    Art(Art<List<A,Hd>, A::Loc>),
}

impl<A:Adapton+Debug+PartialEq+Eq+Hash,Hd:Debug+PartialEq+Eq+Hash> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                                 -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Rc<Self::List>)       -> Self::List { List::Cons(hd,tl) }
    fn name (_:&mut A, nm:A::Name, tl:Rc<Self::List>)  -> Self::List { List::Name(nm, tl) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>)     -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (self:&Self, st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Rc<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Rc<Self::List>) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, tl),
            List::Name(ref nm, ref tl) => namef(st, nm, tl),
            List::Art(ref art) => {
                let list = st.force(art);
                self.elim(st, &*list, nilf, consf, namef)
            }
        }
    }
    fn fold<Res,Cons> (self:&Self, st:&mut A, list:&Self::List, res:Res, consf:Cons) -> Res
        where Cons:Fn(&mut A, Res, &Hd) -> Res
    {
        match *list {
            List::Nil => res,
            List::Cons(ref hd, ref tl) => {
                let res = consf(st, res, hd) ;
                self.fold(st, &*tl, res, consf)
            },
            List::Name(_, ref tl) => self.fold(st, &*tl, res, consf),
            List::Art(ref art) => {
                let list = st.force(art) ;
                self.fold(st, &*list, res, consf)
            }
        }
    }
}

pub fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (l:&L, st:&mut A, list:&Rc<L::List>, left_tree:&Rc<T::Tree>)
     -> (Rc<T::Tree>, Rc<L::List>)
{
    l.elim (
        st, &list,
        /* Nil */  |st| ( Rc::new(T::nil(st)), Rc::new(L::nil(st)) ),
        /* Cons */ |st, hd, rest| {
            if my_hash( hd ) == 0 {
                let nil = Rc::new(T::nil(st)) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( l, st, rest, &nil ) ;
                let tree = Rc::new(T::bin ( st, hd.clone(), left_tree.clone(), right_tree )) ;
                tree_of_list_rec::<A,X,T,L> ( l, st, &rest, &tree )
            }
            else {
                let rest = Rc::new(L::cons(st, hd.clone(), rest.clone())) ;
                (left_tree.clone(), rest)
            }},
        /* Name */ |st, nm, rest| {
            if my_hash( nm ) == 0 {
                let nil = Rc::new(T::nil(st)) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( l, st, rest, &nil ) ;
                // TODO: Place left_ and right_ trees into articulations, named by name.
                // TODO: Memoize the recursive calls to tree_of_list_rec.
                let tree = Rc::new(T::name( st, nm.clone(), left_tree.clone(), right_tree )) ;
                tree_of_list_rec::<A,X,T,L> ( l, st, &rest, &tree )
            }
            else {
                let rest = Rc::new(L::name(st, nm.clone(), rest.clone())) ;
                (left_tree.clone(), rest)
            }}
        )
}
<|endoftext|>


<commit_before>const NUM_BYTES: usize = 4096;
const NUM_REGISTERS: usize = 16;
const STACK_SIZE: usize = 48;

pub struct System {
    memory: [u8; NUM_BYTES],
    registers: [u8; NUM_REGISTERS],
    pc: u16,
    index: u16,
    stack: [u8; STACK_SIZE],
    sp: u8
}

impl System {
    pub fn new() -> Self {
        System {
            memory: [0; NUM_BYTES],
            registers: [0; NUM_REGISTERS],
            pc: 0,
            index: 0,
            stack: [0; STACK_SIZE],
            sp: 0
        }
    }
}
<commit_msg>read word from system memory<commit_after>const NUM_BYTES: usize = 4096;
const NUM_REGISTERS: usize = 16;
const STACK_SIZE: usize = 48;

pub struct System {
    memory: [u8; NUM_BYTES],
    registers: [u8; NUM_REGISTERS],
    pc: u16,
    index: u16,
    stack: [u8; STACK_SIZE],
    sp: u8
}

impl System{
    pub fn new() -> Self {
        System {
            memory: [0; NUM_BYTES],
            registers: [0; NUM_REGISTERS],
            pc: 0,
            index: 0,
            stack: [0; STACK_SIZE],
            sp: 0
        }
    }

    pub fn read_word(&self, address: usize) -> &[u8] {
        &self.memory[address..address + 2]
    }
}

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

    /** Load some test data into the system memory for the purposes of testing. */
    fn load_test_data(system: &mut System) {
        system.memory[0] = 0xAF;
        system.memory[1] = 0x7F;
        system.memory[NUM_BYTES / 2] = 0x77;
        system.memory[NUM_BYTES / 2 + 1] = 0x88;
        system.memory[NUM_BYTES - 2] = 0x3A;
        system.memory[NUM_BYTES - 1] = 0x01;
    }

    /** Read a word (two bytes) from the system memory. */
    #[test]
    fn read_word() {
        let mut system = System::new();
        load_test_data(&mut system);
        assert_eq!([0xAF, 0x7F], system.read_word(0));
        assert_eq!([0x77, 0x88], system.read_word(NUM_BYTES / 2));
        assert_eq!([0x3A, 0x01], system.read_word(NUM_BYTES - 2));
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::path::Path;
use std::process::Command;

use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};

fn main() {
    let mut version = String::from(env!("CARGO_PKG_VERSION"));
    if let Some(commit_hash) = commit_hash() {
        version = format!("{} ({})", version, commit_hash);
    }
    println!("cargo:rustc-env=VERSION={}", version);

    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();

    Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, ["GL_ARB_blend_func_extended"])
        .write_bindings(GlobalGenerator, &mut file)
        .unwrap();

    #[cfg(windows)]
    embed_resource::compile("./windows/windows.rc");
}

fn commit_hash() -> Option<String> {
    Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .ok()
        .and_then(|output| String::from_utf8(output.stdout).ok())
        .map(|hash| hash.trim().into())
}
<commit_msg>Omit git version hash when git command fails<commit_after>use std::env;
use std::fs::File;
use std::path::Path;
use std::process::Command;

use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};

fn main() {
    let mut version = String::from(env!("CARGO_PKG_VERSION"));
    if let Some(commit_hash) = commit_hash() {
        version = format!("{} ({})", version, commit_hash);
    }
    println!("cargo:rustc-env=VERSION={}", version);

    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();

    Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, ["GL_ARB_blend_func_extended"])
        .write_bindings(GlobalGenerator, &mut file)
        .unwrap();

    #[cfg(windows)]
    embed_resource::compile("./windows/windows.rc");
}

fn commit_hash() -> Option<String> {
    Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .ok()
        .filter(|output| output.status.success())
        .and_then(|output| String::from_utf8(output.stdout).ok())
        .map(|hash| hash.trim().into())
}
<|endoftext|>


<commit_before>extern crate mdbook;

use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
use mdbook::MDBook;
use std::path::Path;

fn example() -> CmdPreprocessor {
    CmdPreprocessor::new("nop-preprocessor".to_string(), "cargo run --example nop-preprocessor --".to_string())
}

#[test]
fn example_supports_whatever() {
    let cmd = example();

    let got = cmd.supports_renderer("whatever");

    assert_eq!(got, true);
}

#[test]
fn example_doesnt_support_not_supported() {
    let cmd = example();

    let got = cmd.supports_renderer("not-supported");

    assert_eq!(got, false);
}

#[test]
fn ask_the_preprocessor_to_blow_up() {
    let dummy_book = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("dummy_book");
    let mut md = MDBook::load(&dummy_book).unwrap();
    md.with_preprecessor(example());

    md.config.set("preprocessor.nop-preprocessor.blow-up", true).unwrap();

    let got = md.build();

    assert!(got.is_err());
}

#[test]
fn process_the_dummy_book() {
    let dummy_book = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("dummy_book");
    let mut md = MDBook::load(&dummy_book).unwrap();
    md.with_preprecessor(example());

    md.build().unwrap();
}
<commit_msg>Fixed a bug where the tests use the wrong dummy book<commit_after>extern crate mdbook;

mod dummy_book;

use dummy_book::DummyBook;
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
use mdbook::MDBook;

fn example() -> CmdPreprocessor {
    CmdPreprocessor::new("nop-preprocessor".to_string(), "cargo run --example nop-preprocessor --".to_string())
}

#[test]
fn example_supports_whatever() {
    let cmd = example();

    let got = cmd.supports_renderer("whatever");

    assert_eq!(got, true);
}

#[test]
fn example_doesnt_support_not_supported() {
    let cmd = example();

    let got = cmd.supports_renderer("not-supported");

    assert_eq!(got, false);
}

#[test]
fn ask_the_preprocessor_to_blow_up() {
    let dummy_book = DummyBook::new();
    let temp = dummy_book.build().unwrap();
    let mut md = MDBook::load(temp.path()).unwrap();
    md.with_preprecessor(example());

    md.config.set("preprocessor.nop-preprocessor.blow-up", true).unwrap();

    let got = md.build();

    assert!(got.is_err());
}

#[test]
fn process_the_dummy_book() {
    let dummy_book = DummyBook::new();
    let temp = dummy_book.build().unwrap();
    let mut md = MDBook::load(temp.path()).unwrap();
    md.with_preprecessor(example());

    md.build().unwrap();
}
<|endoftext|>


<commit_before>#[cfg(feature = "use_std")]
use std::error::Error;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};

use std::iter::ExactSizeIterator;

use either::Either;

use crate::size_hint;

/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
/// During the execution of exactly_one the iterator must be mutated.  This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Clone)]
pub struct ExactlyOneError<I>
where
    I: Iterator,
{
    first_two: Option<Either<[I::Item; 2], I::Item>>,
    inner: I,
}

impl<I> ExactlyOneError<I>
where
    I: Iterator,
{
    /// Creates a new `ExactlyOneErr` iterator.
    pub(crate) fn new(first_two: Option<Either<[I::Item; 2], I::Item>>, inner: I) -> Self {
        Self { first_two, inner }
    }

    fn additional_len(&self) -> usize {
        match self.first_two {
            Some(Either::Left(_)) => 2,
            Some(Either::Right(_)) => 1,
            None => 0,
        }
    }
}

impl<I> Iterator for ExactlyOneError<I>
where
    I: Iterator,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.first_two.take() {
            Some(Either::Left([first, second])) => {
                self.first_two = Some(Either::Right(second));
                Some(first)
            },
            Some(Either::Right(second)) => {
                Some(second)
            }
            None => {
                self.inner.next()
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
    }
}

impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}

impl<I> Display for ExactlyOneError<I>
    where I: Iterator
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let additional = self.additional_len();
        if additional > 0 {
            write!(f, "got at least 2 elements when exactly one was expected")
        } else {
            write!(f, "got zero elements when exactly one was expected")
        }
    }
}

impl<I> Debug for ExactlyOneError<I>
    where I: Iterator,
          I::Item: Debug,
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match &self.first_two {
            Some(Either::Left([first, second])) => {
                write!(f, "ExactlyOneError[{:?}, {:?}, ...]", first, second)
            },
            Some(Either::Right(second)) => {
                write!(f, "ExactlyOneError[{:?}, ...]", second)
            }
            None => {
                write!(f, "ExactlyOneError[...]")
            }
        }
    }
}

#[cfg(feature = "use_std")]
impl<I> Error for ExactlyOneError<I>  where I: Iterator, I::Item: Debug, {}

<commit_msg>Make Debug impl a bit more useful<commit_after>#[cfg(feature = "use_std")]
use std::error::Error;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};

use std::iter::ExactSizeIterator;

use either::Either;

use crate::size_hint;

/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
/// During the execution of exactly_one the iterator must be mutated.  This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Clone)]
pub struct ExactlyOneError<I>
where
    I: Iterator,
{
    first_two: Option<Either<[I::Item; 2], I::Item>>,
    inner: I,
}

impl<I> ExactlyOneError<I>
where
    I: Iterator,
{
    /// Creates a new `ExactlyOneErr` iterator.
    pub(crate) fn new(first_two: Option<Either<[I::Item; 2], I::Item>>, inner: I) -> Self {
        Self { first_two, inner }
    }

    fn additional_len(&self) -> usize {
        match self.first_two {
            Some(Either::Left(_)) => 2,
            Some(Either::Right(_)) => 1,
            None => 0,
        }
    }
}

impl<I> Iterator for ExactlyOneError<I>
where
    I: Iterator,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.first_two.take() {
            Some(Either::Left([first, second])) => {
                self.first_two = Some(Either::Right(second));
                Some(first)
            },
            Some(Either::Right(second)) => {
                Some(second)
            }
            None => {
                self.inner.next()
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
    }
}

impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}

impl<I> Display for ExactlyOneError<I>
    where I: Iterator,
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let additional = self.additional_len();
        if additional > 0 {
            write!(f, "got at least 2 elements when exactly one was expected")
        } else {
            write!(f, "got zero elements when exactly one was expected")
        }
    }
}

impl<I> Debug for ExactlyOneError<I>
    where I: Iterator + Debug,
          I::Item: Debug,
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match &self.first_two {
            Some(Either::Left([first, second])) => {
                write!(f, "ExactlyOneError[First: {:?}, Second: {:?}, RemainingIter: {:?}]", first, second, self.inner)
            },
            Some(Either::Right(second)) => {
                write!(f, "ExactlyOneError[Second: {:?}, RemainingIter: {:?}]", second, self.inner)
            }
            None => {
                write!(f, "ExactlyOneError[RemainingIter: {:?}]", self.inner)
            }
        }
    }
}

#[cfg(feature = "use_std")]
impl<I> Error for ExactlyOneError<I>  where I: Iterator + Debug, I::Item: Debug, {}

<|endoftext|>


<commit_before>use ef_tests::*;
use rayon::prelude::*;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

fn yaml_files_in_test_dir(dir: &Path) -> Vec<PathBuf> {
    let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("eth2.0-spec-tests")
        .join("tests")
        .join(dir);

    assert!(
        base_path.exists(),
        format!(
            "Unable to locate {:?}. Did you init git submoules?",
            base_path
        )
    );

    let mut paths: Vec<PathBuf> = WalkDir::new(base_path)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter_map(|entry| {
            if entry.file_type().is_file() {
                match entry.file_name().to_str() {
                    Some(f) if f.ends_with(".yaml") => Some(entry.path().to_path_buf()),
                    Some(f) if f.ends_with(".yml") => Some(entry.path().to_path_buf()),
                    _ => None,
                }
            } else {
                None
            }
        })
        .collect();

    // Reverse the file order. Assuming files come in lexicographical order, executing tests in
    // reverse means we get the "minimal" tests before the "mainnet" tests. This makes life easier
    // for debugging.
    paths.reverse();
    paths
}

#[test]
#[cfg(feature = "fake_crypto")]
fn ssz_generic() {
    yaml_files_in_test_dir(&Path::new("ssz_generic"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[cfg(feature = "fake_crypto")]
fn ssz_static() {
    yaml_files_in_test_dir(&Path::new("ssz_static"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn shuffling() {
    yaml_files_in_test_dir(&Path::new("shuffling").join("core"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_deposit() {
    yaml_files_in_test_dir(&Path::new("operations").join("deposit"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_transfer() {
    yaml_files_in_test_dir(&Path::new("operations").join("transfer"))
        .into_par_iter()
        .rev()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_exit() {
    yaml_files_in_test_dir(&Path::new("operations").join("voluntary_exit"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_proposer_slashing() {
    yaml_files_in_test_dir(&Path::new("operations").join("proposer_slashing"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_attester_slashing() {
    yaml_files_in_test_dir(&Path::new("operations").join("attester_slashing"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_attestation() {
    yaml_files_in_test_dir(&Path::new("operations").join("attestation"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_block_header() {
    yaml_files_in_test_dir(&Path::new("operations").join("block_header"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn sanity_blocks() {
    yaml_files_in_test_dir(&Path::new("sanity").join("blocks"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn sanity_slots() {
    yaml_files_in_test_dir(&Path::new("sanity").join("slots"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls() {
    yaml_files_in_test_dir(&Path::new("bls"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn epoch_processing_crosslinks() {
    yaml_files_in_test_dir(&Path::new("epoch_processing").join("crosslinks"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn epoch_processing_registry_updates() {
    yaml_files_in_test_dir(&Path::new("epoch_processing").join("registry_updates"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}
<commit_msg>Add should_panic to incomplete ef_tests<commit_after>use ef_tests::*;
use rayon::prelude::*;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

fn yaml_files_in_test_dir(dir: &Path) -> Vec<PathBuf> {
    let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("eth2.0-spec-tests")
        .join("tests")
        .join(dir);

    assert!(
        base_path.exists(),
        format!(
            "Unable to locate {:?}. Did you init git submoules?",
            base_path
        )
    );

    let mut paths: Vec<PathBuf> = WalkDir::new(base_path)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter_map(|entry| {
            if entry.file_type().is_file() {
                match entry.file_name().to_str() {
                    Some(f) if f.ends_with(".yaml") => Some(entry.path().to_path_buf()),
                    Some(f) if f.ends_with(".yml") => Some(entry.path().to_path_buf()),
                    _ => None,
                }
            } else {
                None
            }
        })
        .collect();

    // Reverse the file order. Assuming files come in lexicographical order, executing tests in
    // reverse means we get the "minimal" tests before the "mainnet" tests. This makes life easier
    // for debugging.
    paths.reverse();
    paths
}

#[test]
#[cfg(feature = "fake_crypto")]
fn ssz_generic() {
    yaml_files_in_test_dir(&Path::new("ssz_generic"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[cfg(feature = "fake_crypto")]
fn ssz_static() {
    yaml_files_in_test_dir(&Path::new("ssz_static"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn shuffling() {
    yaml_files_in_test_dir(&Path::new("shuffling").join("core"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_deposit() {
    yaml_files_in_test_dir(&Path::new("operations").join("deposit"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_transfer() {
    yaml_files_in_test_dir(&Path::new("operations").join("transfer"))
        .into_par_iter()
        .rev()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_exit() {
    yaml_files_in_test_dir(&Path::new("operations").join("voluntary_exit"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[should_panic]
fn operations_proposer_slashing() {
    yaml_files_in_test_dir(&Path::new("operations").join("proposer_slashing"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[should_panic]
fn operations_attester_slashing() {
    yaml_files_in_test_dir(&Path::new("operations").join("attester_slashing"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[should_panic]
fn operations_attestation() {
    yaml_files_in_test_dir(&Path::new("operations").join("attestation"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn operations_block_header() {
    yaml_files_in_test_dir(&Path::new("operations").join("block_header"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[should_panic]
fn sanity_blocks() {
    yaml_files_in_test_dir(&Path::new("sanity").join("blocks"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn sanity_slots() {
    yaml_files_in_test_dir(&Path::new("sanity").join("slots"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls() {
    yaml_files_in_test_dir(&Path::new("bls"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn epoch_processing_crosslinks() {
    yaml_files_in_test_dir(&Path::new("epoch_processing").join("crosslinks"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}

#[test]
fn epoch_processing_registry_updates() {
    yaml_files_in_test_dir(&Path::new("epoch_processing").join("registry_updates"))
        .into_par_iter()
        .for_each(|file| {
            Doc::assert_tests_pass(file);
        });
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use super::cluster::{Cluster, Simulator};
use super::node::new_node_cluster;
use super::server::new_server_cluster;
use super::util::*;
use tikv::pd::PdClient;
use super::pd::TestPdClient;

fn check_available<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();
    let engine = cluster.get_engine(1);

    let stats = pd_client.get_store_stats(1).unwrap();
    assert_eq!(stats.get_region_count(), 2);

    let value = vec![0;1024];
    for i in 0..1000 {
        let last_available = stats.get_available();
        cluster.must_put(format!("k{}", i).as_bytes(), &value);
        engine.flush(true).unwrap();
        sleep_ms(20);

        let stats = pd_client.get_store_stats(1).unwrap();
        // Because the available is for disk size, even we add data
        // other process may reduce data too. so here we try to
        // check available size changed.
        if stats.get_available() != last_available {
            return;
        }
    }

    panic!("available not changed")
}

fn test_simple_store_stats<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();

    cluster.cfg.raft_store.pd_store_heartbeat_tick_interval = 20;
    cluster.run();

    // wait store reports stats.
    for _ in 0..100 {
        sleep_ms(20);

        if pd_client.get_store_stats(1).is_some() {
            break;
        }
    }

    let engine = cluster.get_engine(1);
    engine.flush(true).unwrap();
    let last_stats = pd_client.get_store_stats(1).unwrap();
    assert_eq!(last_stats.get_region_count(), 1);

    cluster.must_put(b"k1", b"v1");
    cluster.must_put(b"k3", b"v3");

    let region = pd_client.get_region(b"").unwrap();
    cluster.must_split(&region, b"k2");
    engine.flush(true).unwrap();

    // wait report region count after split
    for _ in 0..100 {
        sleep_ms(20);

        let stats = pd_client.get_store_stats(1).unwrap();
        if stats.get_region_count() == 2 {
            break;
        }
    }

    let stats = pd_client.get_store_stats(1).unwrap();
    assert_eq!(stats.get_region_count(), 2);

    check_available(cluster);
}

#[test]
fn test_node_simple_store_stats() {
    let mut cluster = new_node_cluster(0, 1);
    test_simple_store_stats(&mut cluster);
}

#[test]
fn test_server_simple_store_stats() {
    let mut cluster = new_server_cluster(0, 1);
    test_simple_store_stats(&mut cluster);
}

#[test]
fn test_server_store_snap_stats() {
    let mut cluster = new_server_cluster(0, 2);
    cluster.cfg.raft_store.pd_store_heartbeat_tick_interval = 600000;

    let pd_client = cluster.pd_client.clone();
    // Disable default max peer number check.
    pd_client.disable_default_rule();

    let r1 = cluster.run_conf_change();

    // make a big snapshot
    for i in 0..2 * 1024 {
        let key = format!("{:01024}", i);
        let value = format!("{:01024}", i);
        cluster.must_put(key.as_bytes(), value.as_bytes());
    }

    pd_client.must_add_peer(r1, new_peer(2, 2));

    must_detect_snap(&pd_client);

    // wait snapshot finish.
    sleep_ms(100);

    // remove the peer so we can't do any snapshot now.
    pd_client.must_remove_peer(r1, new_peer(2, 2));
    cluster.must_put(b"k2", b"v2");

    must_not_detect_snap(&pd_client);
}

fn must_detect_snap(pd_client: &Arc<TestPdClient>) {
    for _ in 0..200 {
        sleep_ms(10);

        if let Some(stats) = pd_client.get_store_stats(1) {
            if stats.get_sending_snap_count() > 0 || stats.get_receiving_snap_count() > 0 {
                return;
            }
        }
    }

    panic!("must detect snapshot sending/receiving");
}

fn must_not_detect_snap(pd_client: &Arc<TestPdClient>) {
    for _ in 0..200 {
        sleep_ms(10);

        if let Some(stats) = pd_client.get_store_stats(1) {
            if stats.get_sending_snap_count() == 0 && stats.get_receiving_snap_count() == 0 {
                return;
            }
        }
    }

    panic!("must not detect snapshot sending/receiving");
}
<commit_msg>tests: check snapshot in all nodes  (#1793)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use super::cluster::{Cluster, Simulator};
use super::node::new_node_cluster;
use super::server::new_server_cluster;
use super::util::*;
use tikv::pd::PdClient;
use super::pd::TestPdClient;

fn check_available<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();
    let engine = cluster.get_engine(1);

    let stats = pd_client.get_store_stats(1).unwrap();
    assert_eq!(stats.get_region_count(), 2);

    let value = vec![0;1024];
    for i in 0..1000 {
        let last_available = stats.get_available();
        cluster.must_put(format!("k{}", i).as_bytes(), &value);
        engine.flush(true).unwrap();
        sleep_ms(20);

        let stats = pd_client.get_store_stats(1).unwrap();
        // Because the available is for disk size, even we add data
        // other process may reduce data too. so here we try to
        // check available size changed.
        if stats.get_available() != last_available {
            return;
        }
    }

    panic!("available not changed")
}

fn test_simple_store_stats<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();

    cluster.cfg.raft_store.pd_store_heartbeat_tick_interval = 20;
    cluster.run();

    // wait store reports stats.
    for _ in 0..100 {
        sleep_ms(20);

        if pd_client.get_store_stats(1).is_some() {
            break;
        }
    }

    let engine = cluster.get_engine(1);
    engine.flush(true).unwrap();
    let last_stats = pd_client.get_store_stats(1).unwrap();
    assert_eq!(last_stats.get_region_count(), 1);

    cluster.must_put(b"k1", b"v1");
    cluster.must_put(b"k3", b"v3");

    let region = pd_client.get_region(b"").unwrap();
    cluster.must_split(&region, b"k2");
    engine.flush(true).unwrap();

    // wait report region count after split
    for _ in 0..100 {
        sleep_ms(20);

        let stats = pd_client.get_store_stats(1).unwrap();
        if stats.get_region_count() == 2 {
            break;
        }
    }

    let stats = pd_client.get_store_stats(1).unwrap();
    assert_eq!(stats.get_region_count(), 2);

    check_available(cluster);
}

#[test]
fn test_node_simple_store_stats() {
    let mut cluster = new_node_cluster(0, 1);
    test_simple_store_stats(&mut cluster);
}

#[test]
fn test_server_simple_store_stats() {
    let mut cluster = new_server_cluster(0, 1);
    test_simple_store_stats(&mut cluster);
}

#[test]
fn test_server_store_snap_stats() {
    let mut cluster = new_server_cluster(0, 2);
    cluster.cfg.raft_store.pd_store_heartbeat_tick_interval = 600000;

    let pd_client = cluster.pd_client.clone();
    // Disable default max peer number check.
    pd_client.disable_default_rule();

    let r1 = cluster.run_conf_change();

    // make a big snapshot
    for i in 0..2 * 1024 {
        let key = format!("{:01024}", i);
        let value = format!("{:01024}", i);
        cluster.must_put(key.as_bytes(), value.as_bytes());
    }

    pd_client.must_add_peer(r1, new_peer(2, 2));

    must_detect_snap(&pd_client, &[1, 2]);

    // wait snapshot finish.
    sleep_ms(100);

    // remove the peer so we can't do any snapshot now.
    pd_client.must_remove_peer(r1, new_peer(2, 2));
    cluster.must_put(b"k2", b"v2");

    must_not_detect_snap(&pd_client);
}

fn must_detect_snap(pd_client: &Arc<TestPdClient>, nodes: &[u64]) {
    for _ in 0..200 {
        sleep_ms(10);

        for id in nodes {
            if let Some(stats) = pd_client.get_store_stats(*id) {
                if stats.get_sending_snap_count() > 0 || stats.get_receiving_snap_count() > 0 {
                    return;
                }
            }
        }
    }

    panic!("must detect snapshot sending/receiving");
}

fn must_not_detect_snap(pd_client: &Arc<TestPdClient>) {
    for _ in 0..200 {
        sleep_ms(10);

        if let Some(stats) = pd_client.get_store_stats(1) {
            if stats.get_sending_snap_count() == 0 && stats.get_receiving_snap_count() == 0 {
                return;
            }
        }
    }

    panic!("must not detect snapshot sending/receiving");
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::*;
use matches::matches;

/// **What it does:** Checks for `if` conditions that use blocks to contain an
/// expression.
///
/// **Why is this bad?** It isn't really Rust style, same as using parentheses
/// to contain expressions.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if { true } ..
/// ```
declare_clippy_lint! {
    pub BLOCK_IN_IF_CONDITION_EXPR,
    style,
    "braces that can be eliminated in conditions, e.g. `if { true } ...`"
}

/// **What it does:** Checks for `if` conditions that use blocks containing
/// statements, or conditions that use closures with blocks.
///
/// **Why is this bad?** Using blocks in the condition makes it hard to read.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if { let x = somefunc(); x } ..
/// // or
/// if somefunc(|x| { x == 47 }) ..
/// ```
declare_clippy_lint! {
    pub BLOCK_IN_IF_CONDITION_STMT,
    style,
    "complex blocks in conditions, e.g. `if { let x = true; x } ...`"
}

#[derive(Copy, Clone)]
pub struct BlockInIfCondition;

impl LintPass for BlockInIfCondition {
    fn get_lints(&self) -> LintArray {
        lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT)
    }
}

struct ExVisitor<'a, 'tcx: 'a> {
    found_block: Option<&'tcx Expr>,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx Expr) {
        if let ExprKind::Closure(_, _, eid, _, _) = expr.node {
            let body = self.cx.tcx.hir().body(eid);
            let ex = &body.value;
            if matches!(ex.node, ExprKind::Block(_, _)) && !in_macro(body.value.span) {
                self.found_block = Some(ex);
                return;
            }
        }
        walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
                                     instead, move the block or closure higher and bind it with a 'let'";

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if let ExprKind::If(ref check, ref then, _) = expr.node {
            if let ExprKind::Block(ref block, _) = check.node {
                if block.rules == DefaultBlock {
                    if block.stmts.is_empty() {
                        if let Some(ref ex) = block.expr {
                            // don't dig into the expression here, just suggest that they remove
                            // the block
                            if in_macro(expr.span) || differing_macro_contexts(expr.span, ex.span) {
                                return;
                            }
                            span_help_and_lint(
                                cx,
                                BLOCK_IN_IF_CONDITION_EXPR,
                                check.span,
                                BRACED_EXPR_MESSAGE,
                                &format!(
                                    "try\nif {} {} ... ",
                                    snippet_block(cx, ex.span, ".."),
                                    snippet_block(cx, then.span, "..")
                                ),
                            );
                        }
                    } else {
                        let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
                        if in_macro(span) || differing_macro_contexts(expr.span, span) {
                            return;
                        }
                        // move block higher
                        span_help_and_lint(
                            cx,
                            BLOCK_IN_IF_CONDITION_STMT,
                            check.span,
                            COMPLEX_BLOCK_MESSAGE,
                            &format!(
                                "try\nlet res = {};\nif res {} ... ",
                                snippet_block(cx, block.span, ".."),
                                snippet_block(cx, then.span, "..")
                            ),
                        );
                    }
                }
            } else {
                let mut visitor = ExVisitor { found_block: None, cx };
                walk_expr(&mut visitor, check);
                if let Some(block) = visitor.found_block {
                    span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);
                }
            }
        }
    }
}
<commit_msg>Use match ergonomics for block_in_if_condition lint<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::*;
use matches::matches;

/// **What it does:** Checks for `if` conditions that use blocks to contain an
/// expression.
///
/// **Why is this bad?** It isn't really Rust style, same as using parentheses
/// to contain expressions.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if { true } ..
/// ```
declare_clippy_lint! {
    pub BLOCK_IN_IF_CONDITION_EXPR,
    style,
    "braces that can be eliminated in conditions, e.g. `if { true } ...`"
}

/// **What it does:** Checks for `if` conditions that use blocks containing
/// statements, or conditions that use closures with blocks.
///
/// **Why is this bad?** Using blocks in the condition makes it hard to read.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if { let x = somefunc(); x } ..
/// // or
/// if somefunc(|x| { x == 47 }) ..
/// ```
declare_clippy_lint! {
    pub BLOCK_IN_IF_CONDITION_STMT,
    style,
    "complex blocks in conditions, e.g. `if { let x = true; x } ...`"
}

#[derive(Copy, Clone)]
pub struct BlockInIfCondition;

impl LintPass for BlockInIfCondition {
    fn get_lints(&self) -> LintArray {
        lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT)
    }
}

struct ExVisitor<'a, 'tcx: 'a> {
    found_block: Option<&'tcx Expr>,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx Expr) {
        if let ExprKind::Closure(_, _, eid, _, _) = expr.node {
            let body = self.cx.tcx.hir().body(eid);
            let ex = &body.value;
            if matches!(ex.node, ExprKind::Block(_, _)) && !in_macro(body.value.span) {
                self.found_block = Some(ex);
                return;
            }
        }
        walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
                                     instead, move the block or closure higher and bind it with a 'let'";

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if let ExprKind::If(check, then, _) = &expr.node {
            if let ExprKind::Block(block, _) = &check.node {
                if block.rules == DefaultBlock {
                    if block.stmts.is_empty() {
                        if let Some(ex) = &block.expr {
                            // don't dig into the expression here, just suggest that they remove
                            // the block
                            if in_macro(expr.span) || differing_macro_contexts(expr.span, ex.span) {
                                return;
                            }
                            span_help_and_lint(
                                cx,
                                BLOCK_IN_IF_CONDITION_EXPR,
                                check.span,
                                BRACED_EXPR_MESSAGE,
                                &format!(
                                    "try\nif {} {} ... ",
                                    snippet_block(cx, ex.span, ".."),
                                    snippet_block(cx, then.span, "..")
                                ),
                            );
                        }
                    } else {
                        let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
                        if in_macro(span) || differing_macro_contexts(expr.span, span) {
                            return;
                        }
                        // move block higher
                        span_help_and_lint(
                            cx,
                            BLOCK_IN_IF_CONDITION_STMT,
                            check.span,
                            COMPLEX_BLOCK_MESSAGE,
                            &format!(
                                "try\nlet res = {};\nif res {} ... ",
                                snippet_block(cx, block.span, ".."),
                                snippet_block(cx, then.span, "..")
                            ),
                        );
                    }
                }
            } else {
                let mut visitor = ExVisitor { found_block: None, cx };
                walk_expr(&mut visitor, check);
                if let Some(block) = visitor.found_block {
                    span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::old_io::timer::{sleep};
use std::time::duration::{Duration};
use std::{thread};
use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize};
use std::sync::atomic::Ordering::{SeqCst};

use spsc::unbounded::{new};
use super::{Select, Selectable};

fn ms_sleep(ms: i64) {
    sleep(Duration::milliseconds(ms));
}

#[test]
fn no_wait_one() {
    let (send, recv) = new();
    send.send(1u8).unwrap();
    let select = Select::new();
    select.add(&recv);
    assert!(select.wait(&mut [0]).len() == 1);
}

#[test]
fn wait_one() {
    let (send, recv) = new();
    thread::spawn(move || {
        ms_sleep(100);
        send.send(1u8).unwrap();
    });
    let select = Select::new();
    select.add(&recv);
    assert!(select.wait(&mut [0]) == &mut [recv.id()][..]);
}

#[test]
fn ready_list_one() {
    let (send, recv) = new();
    let select = Select::new();
    select.add(&recv);
    send.send(1u8).unwrap();
    assert!(select.check_ready_list(&mut [0]) == &mut [recv.id()][..]);
}

#[test]
fn no_wait_two() {
    let (send, recv) = new();
    let (send2, recv2) = new();
    send.send(1u8).unwrap();
    send2.send(1u8).unwrap();
    let select = Select::new();
    select.add(&recv);
    select.add(&recv2);
    assert!(select.wait(&mut [0, 0]).len() == 2);
}

#[test]
fn wait_two() {
    let (send, recv) = new();
    let (send2, recv2) = new();
    thread::spawn(move || {
        ms_sleep(100);
        send.send(1u8).unwrap();
    });
    thread::spawn(move || {
        ms_sleep(200);
        send2.send(1u8).unwrap();
    });
    let select = Select::new();
    select.add(&recv);
    select.add(&recv2);
    let mut saw1 = false;
    'outer: loop {
        let mut buf = [0, 0];
        for &mut id in select.wait(&mut buf) {
            if id == recv.id() && recv.recv_sync().is_err() {
                saw1 = true;
            }
            if id == recv2.id() && recv2.recv_sync().is_err() {
                break 'outer;
            }
        }
    }
    assert!(saw1);
}

#[test]
fn select_wrong_thread() {
    // Check that cross thread selecting works.

    let (send1, recv1) = new();
    let (send2, recv2) = new();
    let id1 = recv1.id();
    let id2 = recv2.id();
    let select1 = Arc::new(Select::new());
    let select2 = select1.clone();
    let thread = thread::scoped(move || {
        select2.add(&recv2);
        send2.send(1u8).unwrap();
        ms_sleep(100);
        // clear the second channel so that wait below will remove it from the ready list
        recv2.recv_sync().unwrap();
        assert_eq!(select2.wait(&mut [0, 0]), &mut [id1][..]);
    });
    select1.add(&recv1);
    assert_eq!(select1.wait(&mut [0, 0]), &mut [id2][..]);
    send1.send(2u8).unwrap();
    // make sure that we wait for the other thread before dropping anything else
    drop(thread);
}

#[test]
fn select_chance() {
    // Check that only one selecting thread wakes up.

    let counter1 = Arc::new(AtomicUsize::new(0));
    let counter2 = counter1.clone();
    let counter3 = counter1.clone();
    let (send, recv) = new();
    let select1 = Arc::new(Select::new());
    let select2 = select1.clone();
    select1.add(&recv);
    thread::spawn(move || {
        select1.wait(&mut []);
        counter2.fetch_add(1, SeqCst);
    });
    thread::spawn(move || {
        select2.wait(&mut []);
        counter3.fetch_add(1, SeqCst);
    });
    ms_sleep(100);
    send.send(1u8).unwrap();
    ms_sleep(100);
    assert_eq!(counter1.swap(0, SeqCst), 1);
}
<commit_msg>fix Select test<commit_after>use std::old_io::timer::{sleep};
use std::time::duration::{Duration};
use std::{thread};
use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize};
use std::sync::atomic::Ordering::{SeqCst};

use spsc::unbounded::{new};
use super::{Select, Selectable};

fn ms_sleep(ms: i64) {
    sleep(Duration::milliseconds(ms));
}

#[test]
fn no_wait_one() {
    let (send, recv) = new();
    send.send(1u8).unwrap();
    let select = Select::new();
    select.add(&recv);
    assert!(select.wait(&mut [0]).len() == 1);
}

#[test]
fn wait_one() {
    let (send, recv) = new();
    thread::spawn(move || {
        ms_sleep(100);
        send.send(1u8).unwrap();
    });
    let select = Select::new();
    select.add(&recv);
    assert!(select.wait(&mut [0]) == &mut [recv.id()][..]);
}

#[test]
fn ready_list_one() {
    let (send, recv) = new();
    let select = Select::new();
    select.add(&recv);
    send.send(1u8).unwrap();
    assert!(select.wait_timeout(&mut [0], None) == &mut [recv.id()][..]);
}

#[test]
fn no_wait_two() {
    let (send, recv) = new();
    let (send2, recv2) = new();
    send.send(1u8).unwrap();
    send2.send(1u8).unwrap();
    let select = Select::new();
    select.add(&recv);
    select.add(&recv2);
    assert!(select.wait(&mut [0, 0]).len() == 2);
}

#[test]
fn wait_two() {
    let (send, recv) = new();
    let (send2, recv2) = new();
    thread::spawn(move || {
        ms_sleep(100);
        send.send(1u8).unwrap();
    });
    thread::spawn(move || {
        ms_sleep(200);
        send2.send(1u8).unwrap();
    });
    let select = Select::new();
    select.add(&recv);
    select.add(&recv2);
    let mut saw1 = false;
    'outer: loop {
        let mut buf = [0, 0];
        for &mut id in select.wait(&mut buf) {
            if id == recv.id() && recv.recv_sync().is_err() {
                saw1 = true;
            }
            if id == recv2.id() && recv2.recv_sync().is_err() {
                break 'outer;
            }
        }
    }
    assert!(saw1);
}

#[test]
fn select_wrong_thread() {
    // Check that cross thread selecting works.

    let (send1, recv1) = new();
    let (send2, recv2) = new();
    let id1 = recv1.id();
    let id2 = recv2.id();
    let select1 = Arc::new(Select::new());
    let select2 = select1.clone();
    let thread = thread::scoped(move || {
        select2.add(&recv2);
        send2.send(1u8).unwrap();
        ms_sleep(100);
        // clear the second channel so that wait below will remove it from the ready list
        recv2.recv_sync().unwrap();
        assert_eq!(select2.wait(&mut [0, 0]), &mut [id1][..]);
    });
    select1.add(&recv1);
    assert_eq!(select1.wait(&mut [0, 0]), &mut [id2][..]);
    send1.send(2u8).unwrap();
    // make sure that we wait for the other thread before dropping anything else
    drop(thread);
}

#[test]
fn select_chance() {
    // Check that only one selecting thread wakes up.

    let counter1 = Arc::new(AtomicUsize::new(0));
    let counter2 = counter1.clone();
    let counter3 = counter1.clone();
    let (send, recv) = new();
    let select1 = Arc::new(Select::new());
    let select2 = select1.clone();
    select1.add(&recv);
    thread::spawn(move || {
        select1.wait(&mut []);
        counter2.fetch_add(1, SeqCst);
    });
    thread::spawn(move || {
        select2.wait(&mut []);
        counter3.fetch_add(1, SeqCst);
    });
    ms_sleep(100);
    send.send(1u8).unwrap();
    ms_sleep(100);
    assert_eq!(counter1.swap(0, SeqCst), 1);
}
<|endoftext|>


<commit_before>pub use self::{
	browse::*,
	connection::*,
	enumerate_domains::*,
	query_record::*,
	records::Record,
	register::*,
	resolve::*,
	resolve_host::*,
};

mod browse;
mod connection;
mod enumerate_domains;
mod query_record;
mod records;
mod register;
mod resolve;
mod resolve_host;

use crate::dns_consts::{
	Class,
	Type,
};
use std::os::raw::c_char;

/// Purge record from cache
///
/// See [`DNSServiceReconfirmRecord`](https://developer.apple.com/documentation/dnssd/1804726-dnsservicereconfirmrecord).
#[doc(alias = "DNSServiceReconfirmRecord")]
pub fn reconfirm_record(
	interface: crate::interface::Interface,
	fullname: &str,
	rr_type: Type,
	rr_class: Class,
	rdata: &[u8],
) -> ::std::io::Result<()> {
	crate::init();

	let fullname = crate::cstr::CStr::from(&fullname)?;
	crate::inner::reconfirm_record(
		0, // no flags
		interface.into_raw(),
		&fullname,
		rr_type,
		rr_class,
		rdata,
	);

	Ok(())
}

/// Full name consiting of (up to) three parts
pub struct FullName<'a> {
	/// (unescaped) service name (becomes single label in full name)
	pub service: Option<&'a str>,
	/// registration type (valid names don't need escaping)
	pub reg_type: &'a str,
	/// (escaped) domain name (most names don't need escaping)
	pub domain: &'a str,
}

impl<'a> FullName<'a> {
	/// Escape and concatenate all three parts to a full name
	///
	/// See [`DNSServiceConstructFullName`](https://developer.apple.com/documentation/dnssd/1804753-dnsserviceconstructfullname)
	#[doc(alias = "DNSServiceConstructFullName")]
	pub fn construct(&self) -> ::std::io::Result<String> {
		use std::io;

		let service = crate::cstr::NullableCStr::from(&self.service)?;
		let reg_type = crate::cstr::CStr::from(&self.reg_type)?;
		let domain = crate::cstr::CStr::from(&self.domain)?;

		const SIZE: usize = crate::ffi::MAX_DOMAIN_NAME;
		let mut buf: Vec<u8> = Vec::new();
		buf.reserve(SIZE);
		let result = unsafe {
			crate::ffi::DNSServiceConstructFullName(
				buf.as_mut_ptr() as *mut c_char,
				service.as_ptr(),
				reg_type.as_ptr(),
				domain.as_ptr(),
			)
		};

		if result != 0 {
			// manual only mentions a single possible error (kDNSServiceErr_BadParam), so we use a static io::Error here for now
			// TODO: convert to our normal `Error` type?
			return Err(io::Error::new(io::ErrorKind::InvalidInput, "BadParam"));
		}

		unsafe {
			// ensure NUL termination (MAX_DOMAIN_NAME includes space for trailing NUL, so content must fit)
			buf.as_mut_ptr().wrapping_add(SIZE).write(0);
			buf.set_len(libc::strlen(buf.as_ptr() as *const libc::c_char));
		};

		String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
	}
}
<commit_msg>fix out of bounds write (off by one) in previous commit, use safer way<commit_after>pub use self::{
	browse::*,
	connection::*,
	enumerate_domains::*,
	query_record::*,
	records::Record,
	register::*,
	resolve::*,
	resolve_host::*,
};

mod browse;
mod connection;
mod enumerate_domains;
mod query_record;
mod records;
mod register;
mod resolve;
mod resolve_host;

use crate::dns_consts::{
	Class,
	Type,
};
use std::os::raw::c_char;

/// Purge record from cache
///
/// See [`DNSServiceReconfirmRecord`](https://developer.apple.com/documentation/dnssd/1804726-dnsservicereconfirmrecord).
#[doc(alias = "DNSServiceReconfirmRecord")]
pub fn reconfirm_record(
	interface: crate::interface::Interface,
	fullname: &str,
	rr_type: Type,
	rr_class: Class,
	rdata: &[u8],
) -> ::std::io::Result<()> {
	crate::init();

	let fullname = crate::cstr::CStr::from(&fullname)?;
	crate::inner::reconfirm_record(
		0, // no flags
		interface.into_raw(),
		&fullname,
		rr_type,
		rr_class,
		rdata,
	);

	Ok(())
}

/// Full name consiting of (up to) three parts
pub struct FullName<'a> {
	/// (unescaped) service name (becomes single label in full name)
	pub service: Option<&'a str>,
	/// registration type (valid names don't need escaping)
	pub reg_type: &'a str,
	/// (escaped) domain name (most names don't need escaping)
	pub domain: &'a str,
}

impl<'a> FullName<'a> {
	/// Escape and concatenate all three parts to a full name
	///
	/// See [`DNSServiceConstructFullName`](https://developer.apple.com/documentation/dnssd/1804753-dnsserviceconstructfullname)
	#[doc(alias = "DNSServiceConstructFullName")]
	pub fn construct(&self) -> ::std::io::Result<String> {
		use std::io;

		let service = crate::cstr::NullableCStr::from(&self.service)?;
		let reg_type = crate::cstr::CStr::from(&self.reg_type)?;
		let domain = crate::cstr::CStr::from(&self.domain)?;

		const SIZE: usize = crate::ffi::MAX_DOMAIN_NAME;
		let mut buf: Vec<u8> = Vec::new();
		buf.reserve(SIZE);
		let result = unsafe {
			crate::ffi::DNSServiceConstructFullName(
				buf.as_mut_ptr() as *mut c_char,
				service.as_ptr(),
				reg_type.as_ptr(),
				domain.as_ptr(),
			)
		};

		if result != 0 {
			// manual only mentions a single possible error (kDNSServiceErr_BadParam), so we use a static io::Error here for now
			// TODO: convert to our normal `Error` type?
			return Err(io::Error::new(io::ErrorKind::InvalidInput, "BadParam"));
		}

		// ensure NUL termination (MAX_DOMAIN_NAME includes space for trailing NUL, so content must fit)
		buf.spare_capacity_mut()[SIZE - 1].write(0);
		unsafe {
			buf.set_len(libc::strlen(buf.as_ptr() as *const libc::c_char));
		};

		String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
	}
}
<|endoftext|>