<commit_before>#![feature(test)]
#![feature(step_by)]
extern crate raw_nbits_vec;
extern crate test;
extern crate num;

mod tests {
    macro_rules! bench_test {
        ($(($m: ident, $nbits: ident, $storage: ident)),*) => {
            mod get {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            let n = test::black_box(100);
                            let mut vec: NbitsVec<$nbits, $storage> = NbitsVec::with_capacity(n);
                            unsafe { vec.set_len(n) }
                            b.iter(|| {
                                (0..n).fold(0, |_a, i| vec.get(i));
                            })
                        }
                    }
                )*
            }
            mod resize {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        use num::Zero;
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            let n = test::black_box(100);
                            let mut vec: NbitsVec<$nbits, $storage> = NbitsVec::new();
                            b.iter(|| {
                                for i in (0..n).step_by(10) {
                                    vec.resize(i, $storage::zero());
                                }
                            })
                        }
                    }
                )*
            }
            mod set {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            b.iter(|| {
                                let n = test::black_box(100);
                                let mut vec: NbitsVec<As1bits> = NbitsVec::with_capacity(n);
                                unsafe { vec.set_len(n) };
                                for i in 0..n {
                                    vec.set(i, i);
                                }
                            });
                        }
                    }
                )*
            }
            mod new {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            b.iter(|| {
                                let n = test::black_box(100);
                                let vec: NbitsVec<As1bits> = NbitsVec::with_capacity(n);
                                vec
                            });
                        }
                    }
                 )*
            }
            mod push {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn push(b: &mut Bencher) {
                            let n = test::black_box(100);
                            let mut vec: NbitsVec<As1bits> = NbitsVec::with_capacity(n);
                            b.iter(|| {
                                for i in 0..n {
                                    vec.push(i)
                                }
                            });
                        }
                    }
                 )*
            }
        }
    }
    bench_test! {
        (test_4bits_usize, As4bits, usize),
        (test_4bits_u64, As4bits, u64),
        (test_4bits_u32, As4bits, u32),
        (test_4bits_u16, As4bits, u16),
        (test_4bits_u8, As4bits, u8),
        (test_3bits_usize, As3bits, usize),
        (test_3bits_u64, As3bits, u64),
        (test_3bits_u32, As3bits, u32),
        (test_3bits_u16, As3bits, u16),
        (test_3bits_u8, As3bits, u8),
        (test_2bits_usize, As2bits, usize),
        (test_2bits_u64, As2bits, u64),
        (test_2bits_u32, As2bits, u32),
        (test_2bits_u16, As2bits, u16),
        (test_2bits_u8, As2bits, u8),
        (test_1bits_usize, As1bits, usize),
        (test_1bits_u64, As1bits, u64),
        (test_1bits_u32, As1bits, u32),
        (test_1bits_u16, As1bits, u16),
        (test_1bits_u8, As1bits, u8)
    }
}
<commit_msg>Apply changes to bench tests.<commit_after>#![feature(test)]
#![feature(step_by)]
extern crate raw_nbits_vec;
extern crate test;
extern crate num;

mod tests {
    macro_rules! bench_test {
        ($(($m: ident, $nbits: ident, $storage: ident)),*) => {
            mod get {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            let n = test::black_box(100);
                            let mut vec: NbitsVec<$nbits, $storage> = NbitsVec::with_capacity(n);
                            unsafe { vec.set_len(n) }
                            b.iter(|| {
                                (0..n).fold(0, |_a, i| vec.get(i));
                            })
                        }
                    }
                )*
            }
            mod resize {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        use num::Zero;
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            let n = test::black_box(100);
                            let mut vec: NbitsVec<$nbits, $storage> = NbitsVec::new();
                            b.iter(|| {
                                for i in (0..n).step_by(10) {
                                    vec.resize(i, $storage::zero());
                                }
                            })
                        }
                    }
                )*
            }
            mod set {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            b.iter(|| {
                                let n = test::black_box(100);
                                let mut vec: NbitsVec<$nbits, $storage> = NbitsVec::with_capacity(n);
                                unsafe { vec.set_len(n) };
                                for i in 0..n {
                                    vec.set(i, ::num::cast(i).unwrap());
                                }
                            });
                        }
                    }
                )*
            }
            mod new {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn bench(b: &mut Bencher) {
                            b.iter(|| {
                                let n = test::black_box(100);
                                let vec: NbitsVec<$nbits, $storage> = NbitsVec::with_capacity(n);
                                vec
                            });
                        }
                    }
                 )*
            }
            mod push {
                $(
                    mod $m {
                        use raw_nbits_vec::*;
                        use test::{self, Bencher};
                        #[bench]
                        fn push(b: &mut Bencher) {
                            let n = test::black_box(100);
                            let mut vec: NbitsVec<$nbits, $storage> = NbitsVec::with_capacity(n);
                            b.iter(|| {
                                for i in 0..n {
                                    vec.push(::num::cast(i).unwrap())
                                }
                            });
                        }
                    }
                 )*
            }
        }
    }
    bench_test! {
        (test_4bits_usize, N4, usize),
        (test_4bits_u64, N4, u64),
        (test_4bits_u32, N4, u32),
        (test_4bits_u16, N4, u16),
        (test_4bits_u8, N4, u8),
        (test_3bits_usize, N3, usize),
        (test_3bits_u64, N3, u64),
        (test_3bits_u32, N3, u32),
        (test_3bits_u16, N3, u16),
        (test_3bits_u8, N3, u8),
        (test_2bits_usize, N2, usize),
        (test_2bits_u64, N2, u64),
        (test_2bits_u32, N2, u32),
        (test_2bits_u16, N2, u16),
        (test_2bits_u8, N2, u8),
        (test_1bits_usize, N1, usize),
        (test_1bits_u64, N1, u64),
        (test_1bits_u32, N1, u32),
        (test_1bits_u16, N1, u16),
        (test_1bits_u8, N1, u8)
    }
}
<|endoftext|>


<commit_before>pub struct Handler;

impl Handler {
    pub unsafe fn new() -> Handler {
        Handler
    }
}

#[cfg_attr(test, allow(dead_code))]
pub unsafe fn init() {}

pub unsafe fn cleanup() {}
<commit_msg>Remove unnecessary stack overflow handler stub for sgx.<commit_after>#[cfg_attr(test, allow(dead_code))]
pub unsafe fn init() {}

pub unsafe fn cleanup() {}
<|endoftext|>


<commit_before>use alloc::boxed::{Box, FnBox};

use super::stack::Stack;

#[cfg(target_arch = "x86")]
mod x86;

#[cfg(target_arch = "x86_64")]
mod x86_64;

mod imp {
    #[cfg(target_arch = "x86")]
    pub use super::x86::*;

    #[cfg(target_arch = "x86_64")]
    pub use super::x86_64::*;
}

/// A thread has to be wrapped by a calling function. This function
/// is responsible to setup/cleanup for the actual closure that the user wants
/// to call. This closure is passed as first parameter to the wrapping function
/// and is named 'f' here. This pointer *IS* extracted from a Box via a call
/// to Box::into_raw. The wrapper function is now responsible for its proper
/// deallocation when the thread is terminated
pub type WrapperFn = extern "C" fn(f: *mut u8) -> !;

#[derive(Debug)]
pub struct Context {
    regs: imp::Registers,
}

impl Context {
    pub unsafe fn empty() -> Self {
        Context {
            regs: imp::Registers::empty(),
        }
    }

    pub unsafe fn new<F>(wrapper: WrapperFn, mut f: F, stack: &mut Stack) -> Self
        where F: FnMut() -> (), F: Send + 'static {
        let fun = || {
            f();
        };
        let boxed_fun: Box<FnBox()> = Box::new(fun);

        let fun_ptr = Box::into_raw(Box::new(boxed_fun)) as *mut u8;

        Context {
            regs: imp::Registers::new(wrapper, fun_ptr, stack.top().unwrap()),
        }
    }

    /// Replace the current context with ourself and save the current inside
    /// out_context.
    pub unsafe fn switch_with(&self, out_context: &mut Context) {
        imp::registers_switch(&mut out_context.regs, &self.regs);
    }
}
<commit_msg>thread: Correct a bug due to ownership<commit_after>use alloc::boxed::{Box, FnBox};

use super::stack::Stack;

#[cfg(target_arch = "x86")]
mod x86;

#[cfg(target_arch = "x86_64")]
mod x86_64;

mod imp {
    #[cfg(target_arch = "x86")]
    pub use super::x86::*;

    #[cfg(target_arch = "x86_64")]
    pub use super::x86_64::*;
}

/// A thread has to be wrapped by a calling function. This function
/// is responsible to setup/cleanup for the actual closure that the user wants
/// to call. This closure is passed as first parameter to the wrapping function
/// and is named 'f' here. This pointer *IS* extracted from a Box via a call
/// to Box::into_raw. The wrapper function is now responsible for its proper
/// deallocation when the thread is terminated
pub type WrapperFn = extern "C" fn(f: *mut u8) -> !;

#[derive(Debug)]
pub struct Context {
    regs: imp::Registers,
}

impl Context {
    pub unsafe fn empty() -> Self {
        Context {
            regs: imp::Registers::empty(),
        }
    }

    pub unsafe fn new<F>(wrapper: WrapperFn, mut f: F, stack: &mut Stack) -> Self
        where F: FnMut() -> (), F: Send + 'static {
        let fun = move || {
            f();
        };
        let boxed_fun: Box<FnBox()> = Box::new(fun);

        let fun_ptr = Box::into_raw(Box::new(boxed_fun)) as *mut u8;

        Context {
            regs: imp::Registers::new(wrapper, fun_ptr, stack.top().unwrap()),
        }
    }

    /// Replace the current context with ourself and save the current inside
    /// out_context.
    pub unsafe fn switch_with(&self, out_context: &mut Context) {
        imp::registers_switch(&mut out_context.regs, &self.regs);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, All Contributors (see CONTRIBUTORS file)
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_export]
macro_rules! builtins {
    ($file: expr) => {
    lazy_static! {
      static ref BUILTIN_FILE: &'static [u8] = include_bytes!($file);

      static ref BUILTIN_DEFS: Vec<Vec<u8>> = ::pumpkinscript::textparser::programs(*BUILTIN_FILE).unwrap().1;

      static ref BUILTINS: ::std::collections::BTreeMap<&'static [u8], Vec<u8>> = {
          let mut map = ::std::collections::BTreeMap::new();
          let ref defs : Vec<Vec<u8>> = *BUILTIN_DEFS;
          for definition in defs {
              match ::pumpkinscript::binparser::instruction(definition.as_slice()) {
                  ::pumpkinscript::ParseResult::Done(&[0x81, b':', ref rest..], _) => {
                      let instruction = &definition[0..definition.len() - rest.len() - 2];
                      map.insert(instruction, Vec::from(rest));
                  },
                  other => panic!("builtin definition parse error {:?}", other)
              }
          }
          map
      };
    }};
}

#[macro_export]
macro_rules! handle_builtins {
    () => {
        #[inline]
        fn handle_builtins(&mut self,
                           env: &mut Env<'a>,
                           instruction: &'a [u8],
                           _: EnvId)
                           -> PassResult<'a> {
            if BUILTINS.contains_key(instruction) {
                let vec = BUILTINS.get(instruction).unwrap();
                env.program.push(vec.as_slice());
                Ok(())
            } else {
                Err(Error::UnknownInstruction)
            }
        }
    };
}

#[macro_export]
macro_rules! handle_error {
    ($env: expr, $err: expr) => {
       handle_error!($env, $err, Ok(()))
    };
    ($env: expr, $err: expr, $body: expr) => {{
        if $env.tracking_errors > 0 {
            $env.aborting_try.push($err);
            $body
        } else {
            return Err($err)
        }
    }};
}

#[macro_export]
macro_rules! stack_pop {
    ($env: expr) => {
        match $env.pop() {
            None => {
                return Err(error_empty_stack!())
            }
            Some(e) => {
                e
            }
        }
    }
}

#[macro_export]
macro_rules! return_unless_instructions_equal {
    ($instruction: expr, $exp: expr) => {
        if $instruction != $exp {
            return Err(Error::UnknownInstruction)
        }
    };
}

#[macro_export]
macro_rules! error_program {
    ($desc: expr, $details: expr, $code: expr) => {{
        let mut error = Vec::new();

        write_size_header!($desc, error);
        error.extend_from_slice($desc);

        if $details.len() > 0 {
            write_size!($details.len() + offset_by_size($details.len()), error);
        }

        write_size_header!($details, error);
        error.extend_from_slice($details);

        error.extend_from_slice($code);

        Error::ProgramError(error)
    }}
}

#[macro_export]
macro_rules! error_database {
    ($err: expr) => {{
        let vec = Vec::new();

        error_program!(
            $err.description().as_bytes(),
            &vec,
            ERROR_DATABASE
        )
    }}
}

#[macro_export]
macro_rules! error_no_transaction {
    () => {{
        let vec = Vec::new();
        error_program!(
            "No transaction".as_bytes(),
            &vec,
            ERROR_NO_TX
        )
    }}
}

#[macro_export]
macro_rules! error_unknown_key {
    ($key: expr) => {{
        error_program!(
            "Unknown key".as_bytes(),
            $key,
            ERROR_UNKNOWN_KEY
        )
    }}
}

#[macro_export]
macro_rules! error_duplicate_key {
    ($key: expr) => {{
        error_program!(
            "Duplicate key".as_bytes(),
            $key,
            ERROR_DUPLICATE_KEY
        )
    }}
}

#[macro_export]
macro_rules! error_decoding {
    () => {{
        let vec = Vec::new();
        error_program!(
            "Decoding error".as_bytes(),
            &vec,
            ERROR_DECODING
        )
    }}
}

#[macro_export]
macro_rules! error_empty_stack {
    () => {{
        let vec = Vec::new();
        error_program!(
            "Empty stack".as_bytes(),
            &vec,
            ERROR_EMPTY_STACK
        )
    }}
}

#[macro_export]
macro_rules! error_invalid_value {
    ($value: expr) => {{
        error_program!(
            "Invalid value".as_bytes(),
            &$value,
            ERROR_INVALID_VALUE
        )
    }}
}

#[macro_export]
macro_rules! error_no_value {
    () => {{
        let vec = Vec::new();
        error_program!(
            "No value".as_bytes(),
            &vec,
            ERROR_NO_VALUE
        )
    }}
}

#[macro_export]
macro_rules! error_unknown_instruction {
    ($instruction: expr) => { {
        let (_, w) = binparser::instruction_or_internal_instruction($instruction).unwrap();

        let instruction = match str::from_utf8(&w[1..]) {
            Ok(instruction) => instruction,
            Err(_) => "Error parsing instruction"
        };

        let desc = format!("Unknown instruction: {}", instruction);
        let desc_bytes = desc.as_bytes();

        error_program!(
            desc_bytes,
            $instruction,
            ERROR_UNKNOWN_INSTRUCTION
        )
    } }
}

#[macro_export]
macro_rules! alloc_slice {
    ($size: expr, $env: expr) => {{
        let slice = $env.alloc($size);
        if slice.is_err() {
            return Err(slice.unwrap_err());
        }
        slice.unwrap()
    }};
}

#[macro_export]
macro_rules! alloc_and_write {
    ($bytes: expr, $env: expr) => {{
        let slice = alloc_slice!($bytes.len(), $env);
        slice.copy_from_slice($bytes);
        slice
    }};
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! eval {
        ($script: expr, $env: ident, $expr: expr) => {
           eval!($script, $env, _result, $expr);
        };
        ($script: expr, $env: ident, $result: ident, $expr: expr) => {{
           let (sender, receiver) = mpsc::channel();
           eval!($script, $env, $result, sender, receiver, $expr);
        }};
        ($script: expr, $env: ident, $result: ident, $sender: expr, $receiver: ident, $expr: expr) => {
          {
            use $crate::script::SchedulerHandle;
            let dir = TempDir::new("pumpkindb").unwrap();
            let path = dir.path().to_str().unwrap();
            fs::create_dir_all(path).expect("can't create directory");
            let env = unsafe {
                lmdb::EnvBuilder::new()
                    .expect("can't create env builder")
                    .open(path, lmdb::open::NOTLS, 0o600)
                    .expect("can't open env")
            };

            let db = Arc::new(storage::Storage::new(&env));
            crossbeam::scope(|scope| {
                let mut nvmem = MmapedFile::new_anonymous(20).unwrap();
                let region = nvmem.claim(20).unwrap();
                let timestamp = Arc::new(timestamp::Timestamp::new(region));
                let mut simple = messaging::Simple::new();
                let messaging_accessor = simple.accessor();
                let publisher_thread = scope.spawn(move || simple.run());
                let publisher_clone = messaging_accessor.clone();
                let subscriber_clone = messaging_accessor.clone();
                let timestamp_clone = timestamp.clone();
                let (mut scheduler, sender) = Scheduler::new(
                    dispatcher::StandardDispatcher::new(db.clone(), publisher_clone.clone(), subscriber_clone.clone(),
                    timestamp_clone));
                let handle = scope.spawn(move || scheduler.run());
                let script = parse($script).unwrap();
                let (callback, receiver) = mpsc::channel::<ResponseMessage>();
                sender.schedule_env(EnvId::new(),
                                    script.clone(), callback, Box::new($sender));
                match receiver.recv() {
                   Ok(ResponseMessage::EnvTerminated(_, stack, stack_size)) => {
                      sender.shutdown();
                      messaging_accessor.shutdown();
                      let $result = Ok::<(), Error>(());
                      let mut stack_ = Vec::with_capacity(stack.len());
                      for i in 0..(&stack).len() {
                          stack_.push((&stack[i]).as_slice());
                      }
                      let mut $env = Env::new_with_stack(stack_, stack_size).unwrap();
                      $expr;
                   }
                   Ok(ResponseMessage::EnvFailed(_, err, stack, stack_size)) => {
                      sender.shutdown();
                      messaging_accessor.shutdown();
                      let $result = Err::<(), Error>(err);
                      let stack = stack.unwrap();
                      let mut stack_ = Vec::with_capacity(stack.len());
                      for i in 0..(&stack).len() {
                          stack_.push((&stack)[i].as_slice());
                      }
                      let mut $env = Env::new_with_stack(stack_, stack_size.unwrap()).unwrap();
                      $expr;
                   }
                   Err(err) => {
                      sender.shutdown();
                      messaging_accessor.shutdown();
                      panic!("recv error: {:?}", err);
                   }
                }
                let _ = handle.join();
                let _ = publisher_thread.join();
          });
        };
      }
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! bench_eval {
        ($script: expr, $b: expr) => {
          {
            use $crate::script::SchedulerHandle;
            let dir = TempDir::new("pumpkindb").unwrap();
            let path = dir.path().to_str().unwrap();
            fs::create_dir_all(path).expect("can't create directory");
            let env = unsafe {
                let mut builder = lmdb::EnvBuilder::new().expect("can't create env builder");
                builder.set_mapsize(1024 * 1024 * 1024).expect("can't set mapsize");
                builder.open(path, lmdb::open::NOTLS, 0o600).expect("can't open env")
            };

            let db = Arc::new(storage::Storage::new(&env));
            let cpus = ::num_cpus::get();
            crossbeam::scope(|scope| {
                let mut simple = messaging::Simple::new();
                let messaging_accessor = simple.accessor();
                let messaging_accessor_ = simple.accessor();
                let simple_thread = scope.spawn(move || simple.run());
                let mut nvmem = MmapedFile::new_anonymous(20).unwrap();
                let region = nvmem.claim(20).unwrap();
                let timestamp = Arc::new(timestamp::Timestamp::new(region));

                let mut handles = vec![];
                let mut senders = vec![];
                for i in 0..cpus {
                    let publisher_clone = messaging_accessor.clone();
                    let subscriber_clone = messaging_accessor.clone();
                    let timestamp_clone = timestamp.clone();
                    let (mut scheduler, sender) = Scheduler::new(
                        dispatcher::StandardDispatcher::new(db.clone(), publisher_clone.clone(), subscriber_clone.clone(),
                        timestamp_clone));
                    let storage = db.clone();
                    let handle = scope.spawn(move || scheduler.run());
                    handles.push(handle);
                    senders.push(sender.clone());
                }
                let original_senders = senders.clone();
                let script = parse($script).unwrap();
                $b.iter(move || {
                    let (callback, receiver) = mpsc::channel::<ResponseMessage>();
                    let (sender0, _) = mpsc::channel();
                    let _ = senders.clone().schedule_env(EnvId::new(),
                                           script.clone(), callback, Box::new(sender0));
                    match receiver.recv() {
                       Ok(ResponseMessage::EnvTerminated(_, stack, stack_size)) => (),
                       Ok(ResponseMessage::EnvFailed(_, err, stack, stack_size)) => {
                          senders.shutdown();
                          messaging_accessor.shutdown();
                          panic!("error: {:?}", err);
                       }
                       Err(err) => {
                          senders.shutdown();
                          messaging_accessor.shutdown();
                          panic!("recv error: {:?}", err);
                       }
                    }
                });
                original_senders.shutdown();
                messaging_accessor_.shutdown();
                for handle in handles {
                   handle.join();
                }
                simple_thread.join();
          });
        };
      }
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! data {
    ($ptr:expr) => {
        {
          let (_, size) = binparser::data_size($ptr).unwrap();
          &$ptr[offset_by_size(size)..$ptr.len()]
        }
    };
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! parsed_data {
        ($s: expr) => {
           data!(parse($s).unwrap().as_slice())
        };
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! assert_error {
    ($result: expr, $expected: expr) => {{
        assert!($result.is_err());
        let error = $result.err().unwrap();
        assert!(matches!(error, Error::ProgramError(_)));
        if let Error::ProgramError(inner) = error {
            assert_eq!(inner, parsed_data!($expected));
        } else {
        }
    }};
}
<commit_msg>Problem: unnecessary vector allocation in `builtins!` macro<commit_after>// Copyright (c) 2017, All Contributors (see CONTRIBUTORS file)
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_export]
macro_rules! builtins {
    ($file: expr) => {
    lazy_static! {
      static ref BUILTIN_FILE: &'static [u8] = include_bytes!($file);

      static ref BUILTIN_DEFS: Vec<Vec<u8>> = ::pumpkinscript::textparser::programs(*BUILTIN_FILE).unwrap().1;

      static ref BUILTINS: ::std::collections::BTreeMap<&'static [u8], &'static [u8]> = {
          let mut map = ::std::collections::BTreeMap::new();
          let ref defs : Vec<Vec<u8>> = *BUILTIN_DEFS;
          for definition in defs {
              match ::pumpkinscript::binparser::instruction(&definition) {
                  ::pumpkinscript::ParseResult::Done(&[0x81, b':', ref rest..], _) => {
                      let instruction = &definition[0..definition.len() - rest.len() - 2];
                      map.insert(instruction, rest);
                  },
                  other => panic!("builtin definition parse error {:?}", other)
              }
          }
          map
      };
    }};
}

#[macro_export]
macro_rules! handle_builtins {
    () => {
        #[inline]
        fn handle_builtins(&mut self,
                           env: &mut Env<'a>,
                           instruction: &'a [u8],
                           _: EnvId)
                           -> PassResult<'a> {
            match BUILTINS.get(instruction) {
               Some(val) => {
                  env.program.push(val);
                  Ok(())
               },
               None => Err(Error::UnknownInstruction),
            }
        }
    };
}

#[macro_export]
macro_rules! handle_error {
    ($env: expr, $err: expr) => {
       handle_error!($env, $err, Ok(()))
    };
    ($env: expr, $err: expr, $body: expr) => {{
        if $env.tracking_errors > 0 {
            $env.aborting_try.push($err);
            $body
        } else {
            return Err($err)
        }
    }};
}

#[macro_export]
macro_rules! stack_pop {
    ($env: expr) => {
        match $env.pop() {
            None => {
                return Err(error_empty_stack!())
            }
            Some(e) => {
                e
            }
        }
    }
}

#[macro_export]
macro_rules! return_unless_instructions_equal {
    ($instruction: expr, $exp: expr) => {
        if $instruction != $exp {
            return Err(Error::UnknownInstruction)
        }
    };
}

#[macro_export]
macro_rules! error_program {
    ($desc: expr, $details: expr, $code: expr) => {{
        let mut error = Vec::new();

        write_size_header!($desc, error);
        error.extend_from_slice($desc);

        if $details.len() > 0 {
            write_size!($details.len() + offset_by_size($details.len()), error);
        }

        write_size_header!($details, error);
        error.extend_from_slice($details);

        error.extend_from_slice($code);

        Error::ProgramError(error)
    }}
}

#[macro_export]
macro_rules! error_database {
    ($err: expr) => {{
        let vec = Vec::new();

        error_program!(
            $err.description().as_bytes(),
            &vec,
            ERROR_DATABASE
        )
    }}
}

#[macro_export]
macro_rules! error_no_transaction {
    () => {{
        let vec = Vec::new();
        error_program!(
            "No transaction".as_bytes(),
            &vec,
            ERROR_NO_TX
        )
    }}
}

#[macro_export]
macro_rules! error_unknown_key {
    ($key: expr) => {{
        error_program!(
            "Unknown key".as_bytes(),
            $key,
            ERROR_UNKNOWN_KEY
        )
    }}
}

#[macro_export]
macro_rules! error_duplicate_key {
    ($key: expr) => {{
        error_program!(
            "Duplicate key".as_bytes(),
            $key,
            ERROR_DUPLICATE_KEY
        )
    }}
}

#[macro_export]
macro_rules! error_decoding {
    () => {{
        let vec = Vec::new();
        error_program!(
            "Decoding error".as_bytes(),
            &vec,
            ERROR_DECODING
        )
    }}
}

#[macro_export]
macro_rules! error_empty_stack {
    () => {{
        let vec = Vec::new();
        error_program!(
            "Empty stack".as_bytes(),
            &vec,
            ERROR_EMPTY_STACK
        )
    }}
}

#[macro_export]
macro_rules! error_invalid_value {
    ($value: expr) => {{
        error_program!(
            "Invalid value".as_bytes(),
            &$value,
            ERROR_INVALID_VALUE
        )
    }}
}

#[macro_export]
macro_rules! error_no_value {
    () => {{
        let vec = Vec::new();
        error_program!(
            "No value".as_bytes(),
            &vec,
            ERROR_NO_VALUE
        )
    }}
}

#[macro_export]
macro_rules! error_unknown_instruction {
    ($instruction: expr) => { {
        let (_, w) = binparser::instruction_or_internal_instruction($instruction).unwrap();

        let instruction = match str::from_utf8(&w[1..]) {
            Ok(instruction) => instruction,
            Err(_) => "Error parsing instruction"
        };

        let desc = format!("Unknown instruction: {}", instruction);
        let desc_bytes = desc.as_bytes();

        error_program!(
            desc_bytes,
            $instruction,
            ERROR_UNKNOWN_INSTRUCTION
        )
    } }
}

#[macro_export]
macro_rules! alloc_slice {
    ($size: expr, $env: expr) => {{
        let slice = $env.alloc($size);
        if slice.is_err() {
            return Err(slice.unwrap_err());
        }
        slice.unwrap()
    }};
}

#[macro_export]
macro_rules! alloc_and_write {
    ($bytes: expr, $env: expr) => {{
        let slice = alloc_slice!($bytes.len(), $env);
        slice.copy_from_slice($bytes);
        slice
    }};
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! eval {
        ($script: expr, $env: ident, $expr: expr) => {
           eval!($script, $env, _result, $expr);
        };
        ($script: expr, $env: ident, $result: ident, $expr: expr) => {{
           let (sender, receiver) = mpsc::channel();
           eval!($script, $env, $result, sender, receiver, $expr);
        }};
        ($script: expr, $env: ident, $result: ident, $sender: expr, $receiver: ident, $expr: expr) => {
          {
            use $crate::script::SchedulerHandle;
            let dir = TempDir::new("pumpkindb").unwrap();
            let path = dir.path().to_str().unwrap();
            fs::create_dir_all(path).expect("can't create directory");
            let env = unsafe {
                lmdb::EnvBuilder::new()
                    .expect("can't create env builder")
                    .open(path, lmdb::open::NOTLS, 0o600)
                    .expect("can't open env")
            };

            let db = Arc::new(storage::Storage::new(&env));
            crossbeam::scope(|scope| {
                let mut nvmem = MmapedFile::new_anonymous(20).unwrap();
                let region = nvmem.claim(20).unwrap();
                let timestamp = Arc::new(timestamp::Timestamp::new(region));
                let mut simple = messaging::Simple::new();
                let messaging_accessor = simple.accessor();
                let publisher_thread = scope.spawn(move || simple.run());
                let publisher_clone = messaging_accessor.clone();
                let subscriber_clone = messaging_accessor.clone();
                let timestamp_clone = timestamp.clone();
                let (mut scheduler, sender) = Scheduler::new(
                    dispatcher::StandardDispatcher::new(db.clone(), publisher_clone.clone(), subscriber_clone.clone(),
                    timestamp_clone));
                let handle = scope.spawn(move || scheduler.run());
                let script = parse($script).unwrap();
                let (callback, receiver) = mpsc::channel::<ResponseMessage>();
                sender.schedule_env(EnvId::new(),
                                    script.clone(), callback, Box::new($sender));
                match receiver.recv() {
                   Ok(ResponseMessage::EnvTerminated(_, stack, stack_size)) => {
                      sender.shutdown();
                      messaging_accessor.shutdown();
                      let $result = Ok::<(), Error>(());
                      let mut stack_ = Vec::with_capacity(stack.len());
                      for i in 0..(&stack).len() {
                          stack_.push((&stack[i]).as_slice());
                      }
                      let mut $env = Env::new_with_stack(stack_, stack_size).unwrap();
                      $expr;
                   }
                   Ok(ResponseMessage::EnvFailed(_, err, stack, stack_size)) => {
                      sender.shutdown();
                      messaging_accessor.shutdown();
                      let $result = Err::<(), Error>(err);
                      let stack = stack.unwrap();
                      let mut stack_ = Vec::with_capacity(stack.len());
                      for i in 0..(&stack).len() {
                          stack_.push((&stack)[i].as_slice());
                      }
                      let mut $env = Env::new_with_stack(stack_, stack_size.unwrap()).unwrap();
                      $expr;
                   }
                   Err(err) => {
                      sender.shutdown();
                      messaging_accessor.shutdown();
                      panic!("recv error: {:?}", err);
                   }
                }
                let _ = handle.join();
                let _ = publisher_thread.join();
          });
        };
      }
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! bench_eval {
        ($script: expr, $b: expr) => {
          {
            use $crate::script::SchedulerHandle;
            let dir = TempDir::new("pumpkindb").unwrap();
            let path = dir.path().to_str().unwrap();
            fs::create_dir_all(path).expect("can't create directory");
            let env = unsafe {
                let mut builder = lmdb::EnvBuilder::new().expect("can't create env builder");
                builder.set_mapsize(1024 * 1024 * 1024).expect("can't set mapsize");
                builder.open(path, lmdb::open::NOTLS, 0o600).expect("can't open env")
            };

            let db = Arc::new(storage::Storage::new(&env));
            let cpus = ::num_cpus::get();
            crossbeam::scope(|scope| {
                let mut simple = messaging::Simple::new();
                let messaging_accessor = simple.accessor();
                let messaging_accessor_ = simple.accessor();
                let simple_thread = scope.spawn(move || simple.run());
                let mut nvmem = MmapedFile::new_anonymous(20).unwrap();
                let region = nvmem.claim(20).unwrap();
                let timestamp = Arc::new(timestamp::Timestamp::new(region));

                let mut handles = vec![];
                let mut senders = vec![];
                for i in 0..cpus {
                    let publisher_clone = messaging_accessor.clone();
                    let subscriber_clone = messaging_accessor.clone();
                    let timestamp_clone = timestamp.clone();
                    let (mut scheduler, sender) = Scheduler::new(
                        dispatcher::StandardDispatcher::new(db.clone(), publisher_clone.clone(), subscriber_clone.clone(),
                        timestamp_clone));
                    let storage = db.clone();
                    let handle = scope.spawn(move || scheduler.run());
                    handles.push(handle);
                    senders.push(sender.clone());
                }
                let original_senders = senders.clone();
                let script = parse($script).unwrap();
                $b.iter(move || {
                    let (callback, receiver) = mpsc::channel::<ResponseMessage>();
                    let (sender0, _) = mpsc::channel();
                    let _ = senders.clone().schedule_env(EnvId::new(),
                                           script.clone(), callback, Box::new(sender0));
                    match receiver.recv() {
                       Ok(ResponseMessage::EnvTerminated(_, stack, stack_size)) => (),
                       Ok(ResponseMessage::EnvFailed(_, err, stack, stack_size)) => {
                          senders.shutdown();
                          messaging_accessor.shutdown();
                          panic!("error: {:?}", err);
                       }
                       Err(err) => {
                          senders.shutdown();
                          messaging_accessor.shutdown();
                          panic!("recv error: {:?}", err);
                       }
                    }
                });
                original_senders.shutdown();
                messaging_accessor_.shutdown();
                for handle in handles {
                   handle.join();
                }
                simple_thread.join();
          });
        };
      }
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! data {
    ($ptr:expr) => {
        {
          let (_, size) = binparser::data_size($ptr).unwrap();
          &$ptr[offset_by_size(size)..$ptr.len()]
        }
    };
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! parsed_data {
        ($s: expr) => {
           data!(parse($s).unwrap().as_slice())
        };
}

// TODO: use or remove?
#[allow(unused_macros)]
#[cfg(test)]
macro_rules! assert_error {
    ($result: expr, $expected: expr) => {{
        assert!($result.is_err());
        let error = $result.err().unwrap();
        assert!(matches!(error, Error::ProgramError(_)));
        if let Error::ProgramError(inner) = error {
            assert_eq!(inner, parsed_data!($expected));
        } else {
        }
    }};
}
<|endoftext|>


<commit_before>#![warn(clippy::single_match)]

fn dummy() {}

fn single_match() {
    let x = Some(1u8);

    match x {
        Some(y) => {
            println!("{:?}", y);
        },
        _ => (),
    };

    let x = Some(1u8);
    match x {
        // Note the missing block braces.
        // We suggest `if let Some(y) = x { .. }` because the macro
        // is expanded before we can do anything.
        Some(y) => println!("{:?}", y),
        _ => (),
    }

    let z = (1u8, 1u8);
    match z {
        (2..=3, 7..=9) => dummy(),
        _ => {},
    };

    // Not linted (pattern guards used)
    match x {
        Some(y) if y == 0 => println!("{:?}", y),
        _ => (),
    }

    // Not linted (no block with statements in the single arm)
    match z {
        (2..=3, 7..=9) => println!("{:?}", z),
        _ => println!("nope"),
    }
}

enum Foo {
    Bar,
    Baz(u8),
}
use std::borrow::Cow;
use Foo::*;

fn single_match_know_enum() {
    let x = Some(1u8);
    let y: Result<_, i8> = Ok(1i8);

    match x {
        Some(y) => dummy(),
        None => (),
    };

    match y {
        Ok(y) => dummy(),
        Err(..) => (),
    };

    let c = Cow::Borrowed("");

    match c {
        Cow::Borrowed(..) => dummy(),
        Cow::Owned(..) => (),
    };

    let z = Foo::Bar;
    // no warning
    match z {
        Bar => println!("42"),
        Baz(_) => (),
    }

    match z {
        Baz(_) => println!("42"),
        Bar => (),
    }
}

fn main() {}
<commit_msg>Added test for single_match in macro<commit_after>#![warn(clippy::single_match)]

fn dummy() {}

fn single_match() {
    let x = Some(1u8);

    match x {
        Some(y) => {
            println!("{:?}", y);
        },
        _ => (),
    };

    let x = Some(1u8);
    match x {
        // Note the missing block braces.
        // We suggest `if let Some(y) = x { .. }` because the macro
        // is expanded before we can do anything.
        Some(y) => println!("{:?}", y),
        _ => (),
    }

    let z = (1u8, 1u8);
    match z {
        (2..=3, 7..=9) => dummy(),
        _ => {},
    };

    // Not linted (pattern guards used)
    match x {
        Some(y) if y == 0 => println!("{:?}", y),
        _ => (),
    }

    // Not linted (no block with statements in the single arm)
    match z {
        (2..=3, 7..=9) => println!("{:?}", z),
        _ => println!("nope"),
    }
}

enum Foo {
    Bar,
    Baz(u8),
}
use std::borrow::Cow;
use Foo::*;

fn single_match_know_enum() {
    let x = Some(1u8);
    let y: Result<_, i8> = Ok(1i8);

    match x {
        Some(y) => dummy(),
        None => (),
    };

    match y {
        Ok(y) => dummy(),
        Err(..) => (),
    };

    let c = Cow::Borrowed("");

    match c {
        Cow::Borrowed(..) => dummy(),
        Cow::Owned(..) => (),
    };

    let z = Foo::Bar;
    // no warning
    match z {
        Bar => println!("42"),
        Baz(_) => (),
    }

    match z {
        Baz(_) => println!("42"),
        Bar => (),
    }
}

macro_rules! single_match {
    ($num:literal) => {
        match $num {
            15 => println!("15"),
            _ => (),
        }
    };
}

fn main() {single_match!(5);}
<|endoftext|>


<commit_before>//! Collection types.

#![stable(feature = "rust1", since = "1.0.0")]

#[cfg(not(no_global_oom_handling))]
pub mod binary_heap;
#[cfg(not(no_global_oom_handling))]
mod btree;
#[cfg(not(no_global_oom_handling))]
pub mod linked_list;
#[cfg(not(no_global_oom_handling))]
pub mod vec_deque;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_map {
    //! A map based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::map::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_set {
    //! A set based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::set::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use binary_heap::BinaryHeap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_map::BTreeMap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_set::BTreeSet;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use linked_list::LinkedList;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use vec_deque::VecDeque;

use crate::alloc::{Layout, LayoutError};
use core::fmt::Display;

/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub struct TryReserveError {
    kind: TryReserveErrorKind,
}

impl TryReserveError {
    /// Details about the allocation that caused the error
    #[inline]
    #[unstable(
        feature = "try_reserve_kind",
        reason = "Uncertain how much info should be exposed",
        issue = "48043"
    )]
    pub fn kind(&self) -> TryReserveErrorKind {
        self.kind.clone()
    }
}

/// Details of the allocation that caused a `TryReserveError`
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
pub enum TryReserveErrorKind {
    /// Error due to the computed capacity exceeding the collection's maximum
    /// (usually `isize::MAX` bytes).
    CapacityOverflow,

    /// The memory allocator returned an error
    AllocError {
        /// The layout of allocation request that failed
        layout: Layout,

        #[doc(hidden)]
        #[unstable(
            feature = "container_error_extra",
            issue = "none",
            reason = "\
            Enable exposing the allocator’s custom error value \
            if an associated type is added in the future: \
            https://github.com/rust-lang/wg-allocators/issues/23"
        )]
        non_exhaustive: (),
    },
}

#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
impl From<TryReserveErrorKind> for TryReserveError {
    #[inline]
    fn from(kind: TryReserveErrorKind) -> Self {
        Self { kind }
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl From<LayoutError> for TryReserveError {
    /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
    #[inline]
    fn from(_: LayoutError) -> Self {
        TryReserveErrorKind::CapacityOverflow.into()
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl Display for TryReserveError {
    fn fmt(
        &self,
        fmt: &mut core::fmt::Formatter<'_>,
    ) -> core::result::Result<(), core::fmt::Error> {
        fmt.write_str("memory allocation failed")?;
        let reason = match self.kind {
            TryReserveErrorKind::CapacityOverflow => {
                " because the computed capacity exceeded the collection's maximum"
            }
            TryReserveErrorKind::AllocError { .. } => {
                " because the memory allocator returned a error"
            }
        };
        fmt.write_str(reason)
    }
}

/// An intermediate trait for specialization of `Extend`.
#[doc(hidden)]
trait SpecExtend<I: IntoIterator> {
    /// Extends `self` with the contents of the given iterator.
    fn spec_extend(&mut self, iter: I);
}
<commit_msg>Don't stabilize creation of TryReserveError instances<commit_after>//! Collection types.

#![stable(feature = "rust1", since = "1.0.0")]

#[cfg(not(no_global_oom_handling))]
pub mod binary_heap;
#[cfg(not(no_global_oom_handling))]
mod btree;
#[cfg(not(no_global_oom_handling))]
pub mod linked_list;
#[cfg(not(no_global_oom_handling))]
pub mod vec_deque;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_map {
    //! A map based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::map::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_set {
    //! A set based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::set::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use binary_heap::BinaryHeap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_map::BTreeMap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_set::BTreeSet;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use linked_list::LinkedList;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use vec_deque::VecDeque;

use crate::alloc::{Layout, LayoutError};
use core::fmt::Display;

/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub struct TryReserveError {
    kind: TryReserveErrorKind,
}

impl TryReserveError {
    /// Details about the allocation that caused the error
    #[inline]
    #[unstable(
        feature = "try_reserve_kind",
        reason = "Uncertain how much info should be exposed",
        issue = "48043"
    )]
    pub fn kind(&self) -> TryReserveErrorKind {
        self.kind.clone()
    }
}

/// Details of the allocation that caused a `TryReserveError`
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
pub enum TryReserveErrorKind {
    /// Error due to the computed capacity exceeding the collection's maximum
    /// (usually `isize::MAX` bytes).
    CapacityOverflow,

    /// The memory allocator returned an error
    AllocError {
        /// The layout of allocation request that failed
        layout: Layout,

        #[doc(hidden)]
        #[unstable(
            feature = "container_error_extra",
            issue = "none",
            reason = "\
            Enable exposing the allocator’s custom error value \
            if an associated type is added in the future: \
            https://github.com/rust-lang/wg-allocators/issues/23"
        )]
        non_exhaustive: (),
    },
}

#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
impl From<TryReserveErrorKind> for TryReserveError {
    #[inline]
    fn from(kind: TryReserveErrorKind) -> Self {
        Self { kind }
    }
}

#[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")]
impl From<LayoutError> for TryReserveErrorKind {
    /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
    #[inline]
    fn from(_: LayoutError) -> Self {
        TryReserveErrorKind::CapacityOverflow
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl Display for TryReserveError {
    fn fmt(
        &self,
        fmt: &mut core::fmt::Formatter<'_>,
    ) -> core::result::Result<(), core::fmt::Error> {
        fmt.write_str("memory allocation failed")?;
        let reason = match self.kind {
            TryReserveErrorKind::CapacityOverflow => {
                " because the computed capacity exceeded the collection's maximum"
            }
            TryReserveErrorKind::AllocError { .. } => {
                " because the memory allocator returned a error"
            }
        };
        fmt.write_str(reason)
    }
}

/// An intermediate trait for specialization of `Extend`.
#[doc(hidden)]
trait SpecExtend<I: IntoIterator> {
    /// Extends `self` with the contents of the given iterator.
    fn spec_extend(&mut self, iter: I);
}
<|endoftext|>


<commit_before>use crate::actions::Action;
use crate::Role;
use mcts::{statistics, SearchSettings};
use rand::Rng;
use search_graph;
use std::{cmp, mem};

#[derive(Clone, Debug)]
pub struct Game {}

impl statistics::two_player::PlayerMapping for Role {
  fn player_one() -> Self {
    Role::Dwarf
  }
  fn player_two() -> Self {
    Role::Troll
  }
  fn resolve_player(&self) -> statistics::two_player::Player {
    match *self {
      Role::Dwarf => statistics::two_player::Player::One,
      Role::Troll => statistics::two_player::Player::Two,
    }
  }
}

impl mcts::game::State for crate::state::State {
  type Action = Action;
  type PlayerId = Role;

  fn active_player(&self) -> &Role {
    &self.active_role()
  }

  fn for_actions<F>(&self, mut f: F)
  where
    F: FnMut(Action) -> mcts::game::LoopControl,
  {
    let mut actions = self.actions();
    loop {
      match actions.next() {
        Some(a) => {
          match f(a) {
            mcts::game::LoopControl::Continue => continue,
            mcts::game::LoopControl::Break => break,
          }
        }
        None => break,
      }
    }
  }

  fn do_action(&mut self, action: &Action) {
    self.do_action(action);
  }
}

impl mcts::game::Game for Game {
  type Action = Action;
  type PlayerId = Role;
  type Payoff = statistics::two_player::ScoredPayoff;
  type State = crate::state::State;
  type Statistics = statistics::two_player::ScoredStatistics<Role>;

  fn payoff_of(state: &Self::State) -> Option<Self::Payoff> {
    if state.terminated() {
      let mut dwarf = 0u32;
      let mut troll = 0u32;
      for (_, c) in state.cells().cells_iter() {
        match c {
          crate::board::Content::Occupied(crate::board::Token::Dwarf) => dwarf += 1,
          crate::board::Content::Occupied(crate::board::Token::Troll) => troll += 4,
          _ => (),
        }
      }
      Some(statistics::two_player::ScoredPayoff {
        visits: 1,
        score_one: dwarf,
        score_two: troll,
      })
    } else {
      None
    }
  }
}

/// Controls how a game action is selected by the [MCTS
/// agent](struct.Agent.html) after MCTS search has terminated and all
/// statistics have been gathered.
#[derive(Debug, Clone, Copy)]
pub enum ActionSelect {
  /// Select the action that was visited the most times.
  VisitCount,
  /// Select the action with the best UCB score.
  Ucb,
}

/// Controls how graph compaction is done by the [MCTS agent](struct.Agent.html)
/// before each round of MCTS search.
#[derive(Debug, Clone, Copy)]
pub enum GraphCompact {
  /// Prune the search graph so that the current game state and all its
  /// descendants are retained, but game states that are not reachable from the
  /// current game state are removed.
  Prune,
  /// Clear the entire search graph.
  Clear,
  /// Retain the entire contents of the search graph.
  Retain,
}

type SearchGraph =
  search_graph::Graph<crate::state::State, mcts::graph::VertexData, mcts::graph::EdgeData<Game>>;

pub struct Agent<R: Rng> {
  settings: SearchSettings,
  iterations: u32,
  rng: R,
  action_select: ActionSelect,
  graph_compact: GraphCompact,
  graph: SearchGraph,
}

impl<R: Rng> Agent<R> {
  pub fn new(
    settings: SearchSettings,
    iterations: u32,
    rng: R,
    action_select: ActionSelect,
    graph_compact: GraphCompact,
  ) -> Self {
    Agent {
      settings,
      iterations,
      rng,
      action_select,
      graph_compact,
      graph: SearchGraph::new(),
    }
  }
}

impl<R: Rng + Send> crate::agent::Agent for Agent<R> {
  fn propose_action(&mut self, state: &crate::state::State) -> crate::agent::Result {
    match self.graph_compact {
      GraphCompact::Prune => {
        if let Some(node) = self.graph.find_node_mut(state) {
          search_graph::view::of_node(node, |view, node| {
            view.retain_reachable_from(Some(node).into_iter());
          });
        } else {
          mem::swap(&mut self.graph, &mut SearchGraph::new());
        }
      }
      GraphCompact::Clear => mem::swap(&mut self.graph, &mut SearchGraph::new()),
      GraphCompact::Retain => (),
    }

    // Borrow/copy stuff out of self because the closure passed to of_graph
    // can't borrow self.
    let (rng, graph, settings, iterations, action_select) = (
      &mut self.rng,
      &mut self.graph,
      self.settings.clone(),
      self.iterations,
      self.action_select,
    );
    search_graph::view::of_graph(graph, |view| -> crate::agent::Result {
      let mut rollout = mcts::RolloutPhase::initialize(rng, settings, state.clone(), view);
      for _ in 0..iterations {
        let scoring = match rollout.rollout::<mcts::ucb::Rollout>() {
          Ok(s) => s,
          Err(e) => return Err(Box::new(e)),
        };
        let backprop = match scoring.score::<mcts::simulation::RandomSimulator>() {
          Ok(b) => b,
          Err(e) => return Err(Box::new(e)),
        };
        rollout = backprop
          .backprop::<mcts::ucb::BestParentBackprop>()
          .expand();
      }
      let (rng, view) = rollout.recover_components();

      let root = view.find_node(state).unwrap();
      let best_action: Action = match action_select {
        ActionSelect::Ucb => {
          match mcts::ucb::find_best_child(&view, root, settings.explore_bias, rng) {
            Ok(child) => view[child].action().clone(),
            Err(e) => return Err(Box::new(e)),
          }
        }
        ActionSelect::VisitCount => {
          let mut children = view.children(root);
          let mut best_child = children.next().unwrap();
          let mut best_child_visits = view[best_child].statistics.visits();
          let mut reservoir_count = 1u32;
          for child in children {
            let visits = view[child].statistics.visits();
            match visits.cmp(&best_child_visits) {
              cmp::Ordering::Less => continue,
              cmp::Ordering::Equal => {
                reservoir_count += 1;
                if !rng.gen_bool(1.0f64 / (reservoir_count as f64)) {
                  continue;
                }
              }
              cmp::Ordering::Greater => reservoir_count = 1,
            }
            best_child = child;
            best_child_visits = visits;
          }
          view[best_child].action().clone()
        }
      };
      Ok(best_action)
    })
  }
}
<commit_msg>Use new score method for computing MCTS payoff.<commit_after>use crate::actions::Action;
use crate::Role;
use mcts::{statistics, SearchSettings};
use rand::Rng;
use search_graph;
use std::{cmp, mem};

#[derive(Clone, Debug)]
pub struct Game {}

impl statistics::two_player::PlayerMapping for Role {
  fn player_one() -> Self {
    Role::Dwarf
  }
  fn player_two() -> Self {
    Role::Troll
  }
  fn resolve_player(&self) -> statistics::two_player::Player {
    match *self {
      Role::Dwarf => statistics::two_player::Player::One,
      Role::Troll => statistics::two_player::Player::Two,
    }
  }
}

impl mcts::game::State for crate::state::State {
  type Action = Action;
  type PlayerId = Role;

  fn active_player(&self) -> &Role {
    &self.active_role()
  }

  fn for_actions<F>(&self, mut f: F)
  where
    F: FnMut(Action) -> mcts::game::LoopControl,
  {
    let mut actions = self.actions();
    loop {
      match actions.next() {
        Some(a) => {
          match f(a) {
            mcts::game::LoopControl::Continue => continue,
            mcts::game::LoopControl::Break => break,
          }
        }
        None => break,
      }
    }
  }

  fn do_action(&mut self, action: &Action) {
    self.do_action(action);
  }
}

impl mcts::game::Game for Game {
  type Action = Action;
  type PlayerId = Role;
  type Payoff = statistics::two_player::ScoredPayoff;
  type State = crate::state::State;
  type Statistics = statistics::two_player::ScoredStatistics<Role>;

  fn payoff_of(state: &Self::State) -> Option<Self::Payoff> {
    if state.terminated() {
      Some(statistics::two_player::ScoredPayoff {
        visits: 1,
        score_one: state.score(Role::Dwarf) as u32,
        score_two: state.score(Role::Troll) as u32,
      })
    } else {
      None
    }
  }
}

/// Controls how a game action is selected by the [MCTS
/// agent](struct.Agent.html) after MCTS search has terminated and all
/// statistics have been gathered.
#[derive(Debug, Clone, Copy)]
pub enum ActionSelect {
  /// Select the action that was visited the most times.
  VisitCount,
  /// Select the action with the best UCB score.
  Ucb,
}

/// Controls how graph compaction is done by the [MCTS agent](struct.Agent.html)
/// before each round of MCTS search.
#[derive(Debug, Clone, Copy)]
pub enum GraphCompact {
  /// Prune the search graph so that the current game state and all its
  /// descendants are retained, but game states that are not reachable from the
  /// current game state are removed.
  Prune,
  /// Clear the entire search graph.
  Clear,
  /// Retain the entire contents of the search graph.
  Retain,
}

type SearchGraph =
  search_graph::Graph<crate::state::State, mcts::graph::VertexData, mcts::graph::EdgeData<Game>>;

pub struct Agent<R: Rng> {
  settings: SearchSettings,
  iterations: u32,
  rng: R,
  action_select: ActionSelect,
  graph_compact: GraphCompact,
  graph: SearchGraph,
}

impl<R: Rng> Agent<R> {
  pub fn new(
    settings: SearchSettings,
    iterations: u32,
    rng: R,
    action_select: ActionSelect,
    graph_compact: GraphCompact,
  ) -> Self {
    Agent {
      settings,
      iterations,
      rng,
      action_select,
      graph_compact,
      graph: SearchGraph::new(),
    }
  }
}

impl<R: Rng + Send> crate::agent::Agent for Agent<R> {
  fn propose_action(&mut self, state: &crate::state::State) -> crate::agent::Result {
    match self.graph_compact {
      GraphCompact::Prune => {
        if let Some(node) = self.graph.find_node_mut(state) {
          search_graph::view::of_node(node, |view, node| {
            view.retain_reachable_from(Some(node).into_iter());
          });
        } else {
          mem::swap(&mut self.graph, &mut SearchGraph::new());
        }
      }
      GraphCompact::Clear => mem::swap(&mut self.graph, &mut SearchGraph::new()),
      GraphCompact::Retain => (),
    }

    // Borrow/copy stuff out of self because the closure passed to of_graph
    // can't borrow self.
    let (rng, graph, settings, iterations, action_select) = (
      &mut self.rng,
      &mut self.graph,
      self.settings.clone(),
      self.iterations,
      self.action_select,
    );
    search_graph::view::of_graph(graph, |view| -> crate::agent::Result {
      let mut rollout = mcts::RolloutPhase::initialize(rng, settings, state.clone(), view);
      for _ in 0..iterations {
        let scoring = match rollout.rollout::<mcts::ucb::Rollout>() {
          Ok(s) => s,
          Err(e) => return Err(Box::new(e)),
        };
        let backprop = match scoring.score::<mcts::simulation::RandomSimulator>() {
          Ok(b) => b,
          Err(e) => return Err(Box::new(e)),
        };
        rollout = backprop
          .backprop::<mcts::ucb::BestParentBackprop>()
          .expand();
      }
      let (rng, view) = rollout.recover_components();

      let root = view.find_node(state).unwrap();
      let best_action: Action = match action_select {
        ActionSelect::Ucb => {
          match mcts::ucb::find_best_child(&view, root, settings.explore_bias, rng) {
            Ok(child) => view[child].action().clone(),
            Err(e) => return Err(Box::new(e)),
          }
        }
        ActionSelect::VisitCount => {
          let mut children = view.children(root);
          let mut best_child = children.next().unwrap();
          let mut best_child_visits = view[best_child].statistics.visits();
          let mut reservoir_count = 1u32;
          for child in children {
            let visits = view[child].statistics.visits();
            match visits.cmp(&best_child_visits) {
              cmp::Ordering::Less => continue,
              cmp::Ordering::Equal => {
                reservoir_count += 1;
                if !rng.gen_bool(1.0f64 / (reservoir_count as f64)) {
                  continue;
                }
              }
              cmp::Ordering::Greater => reservoir_count = 1,
            }
            best_child = child;
            best_child_visits = visits;
          }
          view[best_child].action().clone()
        }
      };
      Ok(best_action)
    })
  }
}
<|endoftext|>


<commit_before>//! Types for working with [`File`].
//!
//! [`File`]: struct.File.html

mod create;
mod open;

pub use self::create::CreateFuture;
pub use self::open::OpenFuture;

use tokio_io::{AsyncRead, AsyncWrite};

use futures::Poll;

use std::fs::{File as StdFile, Metadata, Permissions};
use std::io::{self, Read, Write, Seek};
use std::path::Path;

/// A reference to an open file on the filesystem.
///
/// This is a specialized version of [`std::fs::File`][std] for usage from the
/// Tokio runtime.
///
/// An instance of a `File` can be read and/or written depending on what options
/// it was opened with. Files also implement Seek to alter the logical cursor
/// that the file contains internally.
///
/// Files are automatically closed when they go out of scope.
///
/// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
#[derive(Debug)]
pub struct File {
    std: Option<StdFile>,
}

impl File {
    /// Attempts to open a file in read-only mode.
    ///
    /// # Errors
    ///
    /// `OpenFuture` results in an error if called from outside of the Tokio
    /// runtime or if the underlying [`open`] call results in an error.
    ///
    /// [`open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
    pub fn open
(path: P) -> OpenFuture

    where P: AsRef<Path> + Send + 'static,
    {
        OpenFuture::new(path)
    }

    /// Opens a file in write-only mode.
    ///
    /// This function will create a file if it does not exist, and will truncate
    /// it if it does.
    ///
    /// `CreateFuture` results in an error if called from outside of the Tokio
    /// runtime or if the underlying [`create`] call results in an error.
    ///
    /// [`create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create
    pub fn create
(path: P) -> CreateFuture

    where P: AsRef<Path> + Send + 'static,
    {
        CreateFuture::new(path)
    }

    /// Convert a [`std::fs::File`][std] to a `tokio_fs::File`.
    ///
    /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
    pub(crate) fn from_std(std: StdFile) -> File {
        File { std: Some(std) }
    }

    /// Seek to an offset, in bytes, in a stream.
    ///
    /// A seek beyond the end of a stream is allowed, but implementation
    /// defined.
    ///
    /// If the seek operation completed successfully, this method returns the
    /// new position from the start of the stream. That position can be used
    /// later with `SeekFrom::Start`.
    ///
    /// # Errors
    ///
    /// Seeking to a negative offset is considered an error.
    pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error> {
        ::blocking_io(|| self.std().seek(pos))
    }

    /// Attempts to sync all OS-internal metadata to disk.
    ///
    /// This function will attempt to ensure that all in-core data reaches the
    /// filesystem before returning.
    pub fn poll_sync_all(&mut self) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().sync_all())
    }

    /// This function is similar to `poll_sync_all`, except that it may not
    /// synchronize file metadata to the filesystem.
    ///
    /// This is intended for use cases that must synchronize content, but don't
    /// need the metadata on disk. The goal of this method is to reduce disk
    /// operations.
    ///
    /// Note that some platforms may simply implement this in terms of `poll_sync_all`.
    pub fn poll_sync_data(&mut self) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().sync_data())
    }

    /// Truncates or extends the underlying file, updating the size of this file to become size.
    ///
    /// If the size is less than the current file's size, then the file will be
    /// shrunk. If it is greater than the current file's size, then the file
    /// will be extended to size and have all of the intermediate data filled in
    /// with 0s.
    ///
    /// # Errors
    ///
    /// This function will return an error if the file is not opened for
    /// writing.
    pub fn poll_set_len(&mut self, size: u64) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().set_len(size))
    }

    /// Queries metadata about the underlying file.
    pub fn poll_metadata(&mut self) -> Poll<Metadata, io::Error> {
        ::blocking_io(|| self.std().metadata())
    }

    /// Create a new `File` instance that shares the same underlying file handle
    /// as the existing `File` instance. Reads, writes, and seeks will affect both
    /// File instances simultaneously.
    pub fn poll_try_clone(&mut self) -> Poll<File, io::Error> {
        ::blocking_io(|| {
            let std = self.std().try_clone()?;
            Ok(File::from_std(std))
        })
    }

    /// Changes the permissions on the underlying file.
    ///
    /// # Platform-specific behavior
    ///
    /// This function currently corresponds to the `fchmod` function on Unix and
    /// the `SetFileInformationByHandle` function on Windows. Note that, this
    /// [may change in the future][changes].
    ///
    /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior
    ///
    /// # Errors
    ///
    /// This function will return an error if the user lacks permission change
    /// attributes on the underlying file. It may also return an error in other
    /// os-specific unspecified cases.
    pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().set_permissions(perm))
    }

    fn std(&mut self) -> &mut StdFile {
        self.std.as_mut().expect("`File` instance already shutdown")
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        ::would_block(|| self.std().read(buf))
    }
}

impl AsyncRead for File {
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        false
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        ::would_block(|| self.std().write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        ::would_block(|| self.std().flush())
    }
}

impl AsyncWrite for File {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        ::blocking_io(|| {
            self.std = None;
            Ok(())
        })
    }
}

impl Drop for File {
    fn drop(&mut self) {
        if let Some(_std) = self.std.take() {
            // This is probably fine as closing a file *shouldn't* be a blocking
            // operation. That said, ideally `shutdown` is called first.
        }
    }
}
<commit_msg>Fixed broken link in tokio-fs documentation (#352)<commit_after>//! Types for working with [`File`].
//!
//! [`File`]: file/struct.File.html

mod create;
mod open;

pub use self::create::CreateFuture;
pub use self::open::OpenFuture;

use tokio_io::{AsyncRead, AsyncWrite};

use futures::Poll;

use std::fs::{File as StdFile, Metadata, Permissions};
use std::io::{self, Read, Write, Seek};
use std::path::Path;

/// A reference to an open file on the filesystem.
///
/// This is a specialized version of [`std::fs::File`][std] for usage from the
/// Tokio runtime.
///
/// An instance of a `File` can be read and/or written depending on what options
/// it was opened with. Files also implement Seek to alter the logical cursor
/// that the file contains internally.
///
/// Files are automatically closed when they go out of scope.
///
/// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
#[derive(Debug)]
pub struct File {
    std: Option<StdFile>,
}

impl File {
    /// Attempts to open a file in read-only mode.
    ///
    /// # Errors
    ///
    /// `OpenFuture` results in an error if called from outside of the Tokio
    /// runtime or if the underlying [`open`] call results in an error.
    ///
    /// [`open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
    pub fn open
(path: P) -> OpenFuture

    where P: AsRef<Path> + Send + 'static,
    {
        OpenFuture::new(path)
    }

    /// Opens a file in write-only mode.
    ///
    /// This function will create a file if it does not exist, and will truncate
    /// it if it does.
    ///
    /// `CreateFuture` results in an error if called from outside of the Tokio
    /// runtime or if the underlying [`create`] call results in an error.
    ///
    /// [`create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create
    pub fn create
(path: P) -> CreateFuture

    where P: AsRef<Path> + Send + 'static,
    {
        CreateFuture::new(path)
    }

    /// Convert a [`std::fs::File`][std] to a `tokio_fs::File`.
    ///
    /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html
    pub(crate) fn from_std(std: StdFile) -> File {
        File { std: Some(std) }
    }

    /// Seek to an offset, in bytes, in a stream.
    ///
    /// A seek beyond the end of a stream is allowed, but implementation
    /// defined.
    ///
    /// If the seek operation completed successfully, this method returns the
    /// new position from the start of the stream. That position can be used
    /// later with `SeekFrom::Start`.
    ///
    /// # Errors
    ///
    /// Seeking to a negative offset is considered an error.
    pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error> {
        ::blocking_io(|| self.std().seek(pos))
    }

    /// Attempts to sync all OS-internal metadata to disk.
    ///
    /// This function will attempt to ensure that all in-core data reaches the
    /// filesystem before returning.
    pub fn poll_sync_all(&mut self) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().sync_all())
    }

    /// This function is similar to `poll_sync_all`, except that it may not
    /// synchronize file metadata to the filesystem.
    ///
    /// This is intended for use cases that must synchronize content, but don't
    /// need the metadata on disk. The goal of this method is to reduce disk
    /// operations.
    ///
    /// Note that some platforms may simply implement this in terms of `poll_sync_all`.
    pub fn poll_sync_data(&mut self) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().sync_data())
    }

    /// Truncates or extends the underlying file, updating the size of this file to become size.
    ///
    /// If the size is less than the current file's size, then the file will be
    /// shrunk. If it is greater than the current file's size, then the file
    /// will be extended to size and have all of the intermediate data filled in
    /// with 0s.
    ///
    /// # Errors
    ///
    /// This function will return an error if the file is not opened for
    /// writing.
    pub fn poll_set_len(&mut self, size: u64) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().set_len(size))
    }

    /// Queries metadata about the underlying file.
    pub fn poll_metadata(&mut self) -> Poll<Metadata, io::Error> {
        ::blocking_io(|| self.std().metadata())
    }

    /// Create a new `File` instance that shares the same underlying file handle
    /// as the existing `File` instance. Reads, writes, and seeks will affect both
    /// File instances simultaneously.
    pub fn poll_try_clone(&mut self) -> Poll<File, io::Error> {
        ::blocking_io(|| {
            let std = self.std().try_clone()?;
            Ok(File::from_std(std))
        })
    }

    /// Changes the permissions on the underlying file.
    ///
    /// # Platform-specific behavior
    ///
    /// This function currently corresponds to the `fchmod` function on Unix and
    /// the `SetFileInformationByHandle` function on Windows. Note that, this
    /// [may change in the future][changes].
    ///
    /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior
    ///
    /// # Errors
    ///
    /// This function will return an error if the user lacks permission change
    /// attributes on the underlying file. It may also return an error in other
    /// os-specific unspecified cases.
    pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error> {
        ::blocking_io(|| self.std().set_permissions(perm))
    }

    fn std(&mut self) -> &mut StdFile {
        self.std.as_mut().expect("`File` instance already shutdown")
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        ::would_block(|| self.std().read(buf))
    }
}

impl AsyncRead for File {
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        false
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        ::would_block(|| self.std().write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        ::would_block(|| self.std().flush())
    }
}

impl AsyncWrite for File {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        ::blocking_io(|| {
            self.std = None;
            Ok(())
        })
    }
}

impl Drop for File {
    fn drop(&mut self) {
        if let Some(_std) = self.std.take() {
            // This is probably fine as closing a file *shouldn't* be a blocking
            // operation. That said, ideally `shutdown` is called first.
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::SocketAddr;
use std::collections::VecDeque;
use time::{get_time, Timespec};

use mio;

use super::messages::RawMessage;

use super::node::RequestData;
use super::crypto::PublicKey;

mod network;
mod connection;

pub use self::network::{Network, NetworkConfiguration, PeerId, EventSet};

pub type EventsConfiguration = mio::EventLoopConfig;

pub type EventLoop = mio::EventLoop<MioAdapter>;

// FIXME: move this into node module
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Timeout {
    Status,
    Round(u64, u32),
    Request(RequestData, Option<PublicKey>),
    PeerExchange,
}

pub struct InternalMessage;

pub enum Event {
    Incoming(RawMessage),
    Internal(InternalMessage),
    Timeout(Timeout),
    Error(io::Error),
    Terminate,
}

pub struct Events {
    event_loop: EventLoop,
    queue: MioAdapter,
}

pub struct MioAdapter {
    events: VecDeque<Event>,
    network: Network,
}

impl MioAdapter {
    fn new(network: Network) -> MioAdapter {
        MioAdapter {
            // FIXME: configurable capacity?
            events: VecDeque::new(),
            network: network,
        }
    }

    fn push(&mut self, event: Event) {
        self.events.push_back(event)
    }

    fn pop(&mut self) -> Option<Event> {
        self.events.pop_front()
    }
}

impl mio::Handler for MioAdapter {
    type Timeout = Timeout;
    type Message = InternalMessage;

    fn ready(&mut self, event_loop: &mut EventLoop, token: mio::Token, events: mio::EventSet) {
        // TODO: remove unwrap here
        while let Some(buf) = self.network.io(event_loop, token, events).unwrap() {
            self.push(Event::Incoming(RawMessage::new(buf)));
        }
    }

    fn notify(&mut self, _: &mut EventLoop, msg: Self::Message) {
        self.push(Event::Internal(msg));
    }

    fn timeout(&mut self, _: &mut EventLoop, timeout: Self::Timeout) {
        self.push(Event::Timeout(timeout));
    }

    fn interrupted(&mut self, _: &mut EventLoop) {
        self.push(Event::Terminate);
    }
}

pub trait Reactor {
    fn get_time(&self) -> Timespec;
    fn poll(&mut self) -> Event;
    fn bind(&mut self) -> ::std::io::Result<()>;
    fn send_to(&mut self, address: &SocketAddr, message: RawMessage) -> io::Result<()>;
    fn address(&self) -> SocketAddr;
    fn add_timeout(&mut self, timeout: Timeout, time: Timespec);
}

impl Events {
    pub fn with_config(config: EventsConfiguration, network: Network) -> io::Result<Events> {
        // TODO: using EventLoopConfig + capacity of queue
        Ok(Events {
            event_loop: EventLoop::configured(config)?,
            queue: MioAdapter::new(network),
        })
    }
}

impl Reactor for Events {
    fn get_time(&self) -> Timespec {
        get_time()
    }

    fn poll(&mut self) -> Event {
        loop {
            if let Some(event) = self.queue.pop() {
                return event;
            }
            if let Err(err) = self.event_loop.run_once(&mut self.queue, None) {
                self.queue.push(Event::Error(err))
            }
        }
    }

    fn bind(&mut self) -> ::std::io::Result<()> {
        self.queue.network.bind(&mut self.event_loop)
    }

    fn send_to(&mut self, address: &SocketAddr, message: RawMessage) -> io::Result<()> {
        self.queue.network.send_to(&mut self.event_loop, address, message)
    }

    fn address(&self) -> SocketAddr {
        *self.queue.network.address()
    }

    fn add_timeout(&mut self, timeout: Timeout, time: Timespec) {
        let ms = (time - self.get_time()).num_milliseconds();
        if ms < 0 {
            self.queue.push(Event::Timeout(timeout))
        } else {
            // FIXME: remove unwrap here
            // TODO: use mio::Timeout
            self.event_loop.timeout_ms(timeout, ms as u64).unwrap();
        }
    }
}
<commit_msg>Add some network tests<commit_after>use std::io;
use std::net::SocketAddr;
use std::collections::VecDeque;
use time::{get_time, Timespec};

use mio;

use super::messages::RawMessage;

use super::node::RequestData;
use super::crypto::PublicKey;

mod network;
mod connection;

pub use self::network::{Network, NetworkConfiguration, PeerId, EventSet};

pub type EventsConfiguration = mio::EventLoopConfig;

pub type EventLoop = mio::EventLoop<MioAdapter>;

// FIXME: move this into node module
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Timeout {
    Status,
    Round(u64, u32),
    Request(RequestData, Option<PublicKey>),
    PeerExchange,
}

pub struct InternalMessage;

pub enum Event {
    Incoming(RawMessage),
    Internal(InternalMessage),
    Timeout(Timeout),
    Error(io::Error),
    Terminate,
}

pub struct Events {
    event_loop: EventLoop,
    queue: MioAdapter,
}

pub struct MioAdapter {
    events: VecDeque<Event>,
    network: Network,
}

impl MioAdapter {
    fn new(network: Network) -> MioAdapter {
        MioAdapter {
            // FIXME: configurable capacity?
            events: VecDeque::new(),
            network: network,
        }
    }

    fn push(&mut self, event: Event) {
        self.events.push_back(event)
    }

    fn pop(&mut self) -> Option<Event> {
        self.events.pop_front()
    }
}

impl mio::Handler for MioAdapter {
    type Timeout = Timeout;
    type Message = InternalMessage;

    fn ready(&mut self, event_loop: &mut EventLoop, token: mio::Token, events: mio::EventSet) {
        // TODO: remove unwrap here
        while let Some(buf) = self.network.io(event_loop, token, events).unwrap() {
            self.push(Event::Incoming(RawMessage::new(buf)));
        }
    }

    fn notify(&mut self, _: &mut EventLoop, msg: Self::Message) {
        self.push(Event::Internal(msg));
    }

    fn timeout(&mut self, _: &mut EventLoop, timeout: Self::Timeout) {
        self.push(Event::Timeout(timeout));
    }

    fn interrupted(&mut self, _: &mut EventLoop) {
        self.push(Event::Terminate);
    }
}

pub trait Reactor {
    fn get_time(&self) -> Timespec;
    fn poll(&mut self) -> Event;
    fn bind(&mut self) -> ::std::io::Result<()>;
    fn send_to(&mut self, address: &SocketAddr, message: RawMessage) -> io::Result<()>;
    fn address(&self) -> SocketAddr;
    fn add_timeout(&mut self, timeout: Timeout, time: Timespec);
}

impl Events {
    pub fn with_config(config: EventsConfiguration, network: Network) -> io::Result<Events> {
        // TODO: using EventLoopConfig + capacity of queue
        Ok(Events {
            event_loop: EventLoop::configured(config)?,
            queue: MioAdapter::new(network),
        })
    }
}

impl Reactor for Events {
    fn get_time(&self) -> Timespec {
        get_time()
    }

    fn poll(&mut self) -> Event {
        loop {
            if let Some(event) = self.queue.pop() {
                return event;
            }
            if let Err(err) = self.event_loop.run_once(&mut self.queue, None) {
                self.queue.push(Event::Error(err))
            }
        }
    }

    fn bind(&mut self) -> ::std::io::Result<()> {
        self.queue.network.bind(&mut self.event_loop)
    }

    fn send_to(&mut self, address: &SocketAddr, message: RawMessage) -> io::Result<()> {
        self.queue.network.send_to(&mut self.event_loop, address, message)
    }

    fn address(&self) -> SocketAddr {
        *self.queue.network.address()
    }

    fn add_timeout(&mut self, timeout: Timeout, time: Timespec) {
        let ms = (time - self.get_time()).num_milliseconds();
        if ms < 0 {
            self.queue.push(Event::Timeout(timeout))
        } else {
            // FIXME: remove unwrap here
            // TODO: use mio::Timeout
            self.event_loop.timeout_ms(timeout, ms as u64).unwrap();
        }
    }
}

#[cfg(test)]
mod tests {
    use std::{time, thread};
    use std::net::SocketAddr;

    use time::Duration;

    use super::{Events, Reactor, EventsConfiguration, Event, Timeout};
    use super::{Network, NetworkConfiguration};

    use ::messages::{MessageWriter, RawMessage};
    use ::crypto::gen_keypair;

    impl Events {
        fn with_addr(addr: SocketAddr) -> Events {
            let network = Network::with_config(NetworkConfiguration {
                listen_address: addr,
                max_incoming_connections: 128,
                max_outgoing_connections: 128
            });
            Events::with_config(EventsConfiguration::new(), network).unwrap()
        }

        fn wait_for_msg(&mut self) -> Option<RawMessage> {
            let time = self.get_time() + Duration::milliseconds(5000);
            self.add_timeout(Timeout::Status, time);
            loop {
                match self.poll() {
                    Event::Incoming(msg) => return Some(msg),
                    Event::Timeout(_) => return None,
                    Event::Error(_) => return None,
                    _ => {}
                }
            }
        }

        fn wait_for_bind(&mut self) {
            self.bind().unwrap();
            thread::sleep(time::Duration::from_millis(100));
        }
    }

    fn gen_message(id: u16, len: usize) -> RawMessage {
        let writer = MessageWriter::new(id, len);
        RawMessage::new(writer.sign(&gen_keypair().1))
    }

    #[test]
    fn big_data() {
        let addrs: [SocketAddr; 2] = [
            "127.0.0.1:8200".parse().unwrap(),
            "127.0.0.1:8201".parse().unwrap()
        ];

        let m1 = gen_message(15, 1000000);
        let m2 = gen_message(16, 400);

        let t1;
        {
            let m1 = m1.clone();
            let m2 = m2.clone();
            t1 = thread::spawn(move || {
                let mut e = Events::with_addr(addrs[0].clone());
                e.wait_for_bind();
                e.send_to(&addrs[1], m1).unwrap();
                assert_eq!(e.wait_for_msg(), Some(m2));
            });
        }

        let t2;
        {
            let m1 = m1.clone();
            let m2 = m2.clone();
            t2 = thread::spawn(move || {
                let mut e = Events::with_addr(addrs[1].clone());
                e.wait_for_bind();
                e.send_to(&addrs[0], m2).unwrap();
                assert_eq!(e.wait_for_msg(), Some(m1));
            });
        }

        t2.join().unwrap();
        t1.join().unwrap();
    }

    #[test]
    fn reconnect() {
        let addrs: [SocketAddr; 2] = [
            "127.0.0.1:9000".parse().unwrap(),
            "127.0.0.1:9001".parse().unwrap()
        ];

        let m1 = gen_message(15, 250);
        let m2 = gen_message(16, 400);
        let m3 = gen_message(17, 600);

        let t1;
        {
            let m1 = m1.clone();
            let m2 = m2.clone();
            let m3 = m3.clone();
            t1 = thread::spawn(move || {
                {
                    let mut e = Events::with_addr(addrs[0].clone());
                    e.wait_for_bind();
                    println!("t1: connection opened");
                    println!("t1: send m1 to t2");
                    e.send_to(&addrs[1], m1).unwrap();
                    println!("t1: wait for m2");
                    assert_eq!(e.wait_for_msg(), Some(m2));
                    println!("t1: received m2 from t2");
                    drop(e);
                }
                println!("t1: connection closed");
                {
                    let mut e = Events::with_addr(addrs[0].clone());
                    e.wait_for_bind();
                    println!("t1: connection reopened");
                    println!("t1: send m3 to t2");
                    e.send_to(&addrs[1], m3.clone()).unwrap();
                    println!("t1: wait for m3");
                    assert_eq!(e.wait_for_msg(), Some(m3));
                    println!("t1: received m3 from t2");
                }
            });
        }

        let t2;
        {
            let m1 = m1.clone();
            let m2 = m2.clone();
            let m3 = m3.clone();
            t2 = thread::spawn(move || {
                {
                    let mut e = Events::with_addr(addrs[1].clone());
                    e.wait_for_bind();
                    println!("t2: connection opened");
                    println!("t2: send m2 to t1");
                    e.send_to(&addrs[0], m2).unwrap();
                    println!("t2: wait for m1");
                    assert_eq!(e.wait_for_msg(), Some(m1));
                    println!("t2: received m1 from t1");
                    println!("t2: wait for m3");
                    assert_eq!(e.wait_for_msg(), Some(m3.clone()));
                    println!("t2: received m3 from t1");
                    drop(e);
                }
                println!("t2: connection closed");
                {
                    println!("t2: connection reopened");
                    let mut e = Events::with_addr(addrs[1].clone());
                    e.wait_for_bind();
                    println!("t2: send m3 to t1");
                    e.send_to(&addrs[1], m3).unwrap();
                }
            });
        }

        t2.join().unwrap();
        t1.join().unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
#![allow(incomplete_features)]

#[derive(PartialEq, Eq)]
struct Foo(u8);

impl const std::ops::Add for Foo {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        self
    }
}

struct Evaluatable<const N: Foo>;

fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
    bar::<{ std::ops::Add::add(N, N) }>();
}

fn bar<const N: Foo>() {}

fn main() {}
<commit_msg>CI please<commit_after>// check-pass
#![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
#![allow(incomplete_features)]

#[derive(PartialEq, Eq)]
struct Foo(u8);

impl const std::ops::Add for Foo {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        self
    }
}

struct Evaluatable<const N: Foo>;

fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
    bar::<{ std::ops::Add::add(N, N) }>();
}

fn bar<const N: Foo>() {}

fn main() {}
<|endoftext|>