<commit_before>use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
                        FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;

/// Compute a `ir::FunctionName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::FunctionName {
    ir::FunctionName::new(format!("wasm_0x{:x}", func_index))
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: Vec<Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: Vec<ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FunctionIndex>,
}

impl DummyModuleInfo {
    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: Vec::new(),
            function_bodies: Vec::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,
}

impl DummyEnvironment {
    /// Allocates the data structures with default flags.
    pub fn default() -> Self {
        Self::with_flags(settings::Flags::new(&settings::builder()))
    }

    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_flags(flags),
            trans: FuncTranslator::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The FuncEnvironment implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
        GlobalValue::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        func.create_heap(ir::HeapData {
            base: ir::HeapBase::ReservedReg,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.mod_info.signatures[index].clone())
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData { name, signature })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> ir::Inst {
        pos.ins().call_indirect(sig_ref, callee, call_args)
    }

    fn translate_grow_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }

    fn translate_current_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }
}

impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
    fn get_func_name(&self, func_index: FunctionIndex) -> ir::FunctionName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info.imported_funcs.push((
            String::from(module),
            String::from(field),
        ));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: Vec<FunctionIndex>,
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export(&mut self, func_index: FunctionIndex, name: &'data str) {
        self.info.functions[func_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index].export_names.push(
            String::from(name),
        );
    }

    fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_start_func(&mut self, func_index: FunctionIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    /// Provides the contents of a function body.
    fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
        let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
        let name = get_func_name(function_index);
        let sig = self.get_signature(self.get_func_type(function_index))
            .clone();
        let mut func = ir::Function::with_name_signature(name, sig);
        {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)
                .map_err(|e| String::from(e.description()))?;
        }
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<commit_msg>Clean up a stale comment.<commit_after>use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, SignatureIndex,
                        FunctionIndex, MemoryIndex};
use func_translator::FuncTranslator;
use cretonne::ir::{self, InstBuilder};
use cretonne::ir::types::*;
use cretonne::cursor::FuncCursor;
use cretonne::settings;
use wasmparser;
use std::error::Error;

/// Compute a `ir::FunctionName` for a given wasm function index.
fn get_func_name(func_index: FunctionIndex) -> ir::FunctionName {
    ir::FunctionName::new(format!("wasm_0x{:x}", func_index))
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: Vec<Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: Vec<ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FunctionIndex>,
}

impl DummyModuleInfo {
    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: Vec::new(),
            function_bodies: Vec::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,
}

impl DummyEnvironment {
    /// Allocates the data structures with default flags.
    pub fn default() -> Self {
        Self::with_flags(settings::Flags::new(&settings::builder()))
    }

    /// Allocates the data structures with the given flags.
    pub fn with_flags(flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_flags(flags),
            trans: FuncTranslator::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The FuncEnvironment implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
        GlobalValue::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        func.create_heap(ir::HeapData {
            base: ir::HeapBase::ReservedReg,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.mod_info.signatures[index].clone())
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.mod_info.signatures[sigidx].clone());
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData { name, signature })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> ir::Inst {
        pos.ins().call_indirect(sig_ref, callee, call_args)
    }

    fn translate_grow_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }

    fn translate_current_memory(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> ir::Value {
        pos.ins().iconst(I32, -1)
    }
}

impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
    fn get_func_name(&self, func_index: FunctionIndex) -> ir::FunctionName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info.imported_funcs.push((
            String::from(module),
            String::from(field),
        ));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: Vec<FunctionIndex>,
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export(&mut self, func_index: FunctionIndex, name: &'data str) {
        self.info.functions[func_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index].export_names.push(
            String::from(name),
        );
    }

    fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index].export_names.push(
            String::from(
                name,
            ),
        );
    }

    fn declare_start_func(&mut self, func_index: FunctionIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
        let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
        let name = get_func_name(function_index);
        let sig = self.get_signature(self.get_func_type(function_index))
            .clone();
        let mut func = ir::Function::with_name_signature(name, sig);
        {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)
                .map_err(|e| String::from(e.description()))?;
        }
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Implements single-threaded game tree search.

use basetypes::*;
use bitsets::*;
use chess_move::*;
use tt::*;
use position::Position;

/// Represents a terminated search condition.
pub struct TerminatedSearch;

/// Represents a game tree search.
pub struct Search<'a> {
    tt: &'a TranspositionTable,
    position: Position,
    moves: &'a mut MoveStack,
    moves_starting_ply: usize,
    state_stack: Vec<NodeState>,
    reported_nodes: NodeCount,
    unreported_nodes: NodeCount,
    report_function: &'a mut FnMut(NodeCount) -> bool,
}

impl<'a> Search<'a> {
    /// Creates a new instance.
    ///
    /// `report_function` should be a function that registers the
    /// search progress. It will be called with the number of searched
    /// positions from the beginning of the search to this moment. The
    /// function should return `true` if the search should be
    /// terminated, otherwise it should return `false`.
    pub fn new(root: Position,
               tt: &'a TranspositionTable,
               move_stack: &'a mut MoveStack,
               report_function: &'a mut FnMut(NodeCount) -> bool)
               -> Search<'a> {
        let moves_starting_ply = move_stack.ply();
        Search {
            tt: tt,
            position: root,
            moves: move_stack,
            moves_starting_ply: moves_starting_ply,
            state_stack: Vec::with_capacity(32),
            reported_nodes: 0,
            unreported_nodes: 0,
            report_function: report_function,
        }
    }

    /// Performs a principal variation search (PVS) and returns a
    /// result.
    ///
    /// The alpha-beta algorithm is a significant enhancement to the
    /// minimax search algorithm that eliminates the need to search
    /// large portions of the game tree applying a branch-and-bound
    /// technique. Remarkably, it does this without any potential of
    /// overlooking a better move. If one already has found a quite
    /// good move and search for alternatives, one refutation is
    /// enough to avoid it. No need to look for even stronger
    /// refutations. The algorithm maintains two values, alpha and
    /// beta. They represent the minimum score that the maximizing
    /// player is assured of and the maximum score that the minimizing
    /// player is assured of respectively. PVS is an enhancement to
    /// the alpha-beta search, based on zero (null) window searches of
    /// none PV-nodes, to prove a move is worse or not than an already
    /// safe score from the principal variation. (The principal
    /// variation (PV) is a sequence of moves that the program
    /// considers best and therefore expects to be played.)
    ///
    /// **Important note**: This method may leave un-restored move
    /// lists in the move stack. Call `reset` if you want the move
    /// stack to be restored to the state it had when the search
    /// instance was created.
    pub fn run(&mut self,
               mut alpha: Value, // lower bound
               beta: Value, // upper bound
               depth: u8)
               -> Result<Value, TerminatedSearch> {
        assert!(alpha < beta);

        let entry = self.node_begin();

        // Check if the TT entry gives the result.
        if entry.depth() >= depth {
            let value = entry.value();
            let bound = entry.bound();
            if value >= beta && bound & BOUND_LOWER != 0 {
                self.node_end();
                return Ok(beta);
            }
            if value <= alpha && bound & BOUND_UPPER != 0 {
                self.node_end();
                return Ok(alpha);
            }
            if bound == BOUND_EXACT {
                self.node_end();
                return Ok(value);
            }
        }

        // Initial guests for the final result.
        let mut bound = BOUND_UPPER;
        let mut best_move = Move::invalid();

        if depth == 0 {
            // On leaf nodes, do quiescence search.
            let (value, nodes) = self.position
                                     .evaluate_quiescence(alpha, beta, Some(entry.eval_value()));
            try!(self.report_progress(nodes));

            // See how good this position is.
            if value >= beta {
                alpha = beta;
                bound = BOUND_LOWER;
            } else if value > alpha {
                alpha = value;
                bound = BOUND_EXACT;
            }

        } else {
            // On non-leaf nodes, try moves.
            let mut no_moves_yet = true;
            while let Some(m) = self.do_move() {
                try!(self.report_progress(1));

                // Make a recursive call.
                let value = if no_moves_yet {
                    // The first move we analyze with a fully open window
                    // (alpha, beta). If this happens to be a good move,
                    // it will probably raise `alpha`.
                    no_moves_yet = false;
                    -try!(self.run(-beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that they
                    // are not better than our current best move. For this
                    // purpose we analyze them with a null window (alpha,
                    // alpha + 1). This is faster than a full window
                    // search. Only if we are certain that the move is
                    // better than our current best move, we do a
                    // full-window search.
                    match -try!(self.run(-alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(self.run(-beta, -alpha, depth - 1)),
                    }
                };
                self.undo_move();

                // See how good this move was.
                if value >= beta {
                    // This move is so good, that the opponent will
                    // probably not allow this line of play to
                    // happen. Therefore we should not lose any more time
                    // on this position.
                    alpha = beta;
                    bound = BOUND_LOWER;
                    best_move = m;
                    break;
                }
                if value > alpha {
                    // We found a new best move.
                    alpha = value;
                    bound = BOUND_EXACT;
                    best_move = m;
                }
            }

            // Check if we are in a final position (no legal moves).
            if no_moves_yet {
                let value = self.position.evaluate_final();
                if value >= beta {
                    alpha = beta;
                    bound = BOUND_LOWER;
                }
                if value > alpha {
                    alpha = value;
                    bound = BOUND_EXACT;
                }
            }
        }

        self.store(alpha, bound, depth, best_move);
        self.node_end();
        Ok(alpha)
    }

    /// Returns the number of searched positions.
    #[inline(always)]
    pub fn node_count(&self) -> NodeCount {
        self.reported_nodes + self.unreported_nodes
    }

    /// Resets the instance to the state it had when it was created.
    #[inline]
    pub fn reset(&mut self) {
        while self.moves.ply() > self.moves_starting_ply {
            self.moves.restore();
        }
        self.state_stack.clear();
        self.reported_nodes = 0;
        self.unreported_nodes = 0;
    }

    // Declares that we are starting to process a new node.
    //
    // Each recursive call to `run` begins with a call to
    // `node_begin`. The returned value is a TT entry telling
    // everything we know about the current position.
    #[inline]
    fn node_begin(&mut self) -> EntryData {
        // Consult the transposition table.
        let entry = if let Some(e) = self.tt.probe(self.position.hash()) {
            e
        } else {
            EntryData::new(0, BOUND_NONE, 0, 0, self.position.evaluate_static())
        };
        self.state_stack.push(NodeState {
            phase: NodePhase::Pristine,
            entry: entry,
            checkers: BB_UNIVERSAL_SET,
        });
        entry
    }

    // Declares that we are done processing the current node.
    //
    // Each recursive call to `run` ends with a call to `node_end`.
    #[inline]
    fn node_end(&mut self) {
        if let NodePhase::Pristine = self.state_stack.last().unwrap().phase {
            // For pristine nodes we have not saved the move list
            // yet, so we should not restore it.
        } else {
            self.moves.restore();
        }
        self.state_stack.pop();
    }

    // TODO: Implement do_null_move() method?

    // Plays the next legal move in the current position and returns
    // it.
    //
    // Each call to `do_move` for the same position will play and
    // return a different move. When all legal moves has been played,
    // `None` will be returned. `do_move` will do whatever it can to
    // play the best moves first, and the worst last. It will also try
    // to be efficient, for example it will generate the list of all
    // pseudo-legal moves at the last possible moment.
    #[inline]
    fn do_move(&mut self) -> Option<Move> {
        let state = self.state_stack.last_mut().unwrap();

        // Try the hash move first.
        if let NodePhase::Pristine = state.phase {
            // We save the move list at the last possible moment,
            // because most of the nodes are leafs.
            self.moves.save();

            // We save the checkers bitboard also, because we will
            // need this information later many times, and we do not
            // want to recalculate it needlessly.
            //
            // TODO: Verify if this is the best place to calculate
            // checkers, especially in relation to trying null moves.
            state.checkers = self.position.board().checkers();

            state.phase = NodePhase::TriedHashMove;
            if state.entry.move16() != 0 {
                if let Some(mut m) = self.position.try_move_digest(state.entry.move16()) {
                    if self.position.do_move(m) {
                        m.set_score(MAX_MOVE_SCORE);
                        return Some(m);
                    }
                }
            }
        }

        // After the hash move, we generate all pseudo-legal
        // moves. But we should not forget to remove the already tried
        // hash move from the list.
        if let NodePhase::TriedHashMove = state.phase {
            // TODO: `generate_moves` needs `_checkers` and `_pinned`
            // to do its work. At this time we already have generated
            // them, so we should use them.
            self.position.board()._checkers.set(state.checkers);

            self.position.generate_moves(self.moves);
            if state.entry.move16() != 0 {
                self.moves.remove_move(state.entry.move16());
            }
            state.phase = NodePhase::GeneratedMoves;
        }

        // Spit out the generated moves.
        while let Some(mut m) = self.moves.remove_best_move() {

            // First, the good captures.
            if let NodePhase::GeneratedMoves = state.phase {
                if m.score() == MAX_MOVE_SCORE {
                    if self.position.evaluate_move(m) >= 0 {
                        if self.position.do_move(m) {
                            return Some(m);
                        }
                        continue;
                    }
                    // This is a bad capture -- push it back to the
                    // move stack.
                    m.set_score(MAX_MOVE_SCORE - 1);
                    self.moves.push(m);
                    continue;
                }
                state.phase = NodePhase::TriedGoodCaptures;
            }

            // Second, the bad captures.
            if let NodePhase::TriedGoodCaptures = state.phase {
                if m.score() == MAX_MOVE_SCORE - 1 {
                    if self.position.do_move(m) {
                        return Some(m);
                    }
                    continue;
                }
                state.phase = NodePhase::TriedBadCaptures;
            }

            // Before trying the quiet moves, we should assign proper
            // move scores to them.
            if let NodePhase::TriedBadCaptures = state.phase {
                // TODO: Assign the moves scores here using the killer
                // move heuristics and the history heuristics.

                // We use the score field (2 bits) to properly order
                // quiet movies. Moves which destination square is
                // more advanced into enemy's territory are tried
                // first. The logic is that those moves are riskier,
                // so if such a move loses material this will be
                // detected early and the search tree will be pruned,
                // but if the move does not lose material, chances are
                // that it is a very good move.
                const SCORE_LOOKUP: [[u32; 8]; 2] = [// white
                                                     [0, 1, 2, 3, 4, 5, 6, 7],
                                                     // black
                                                     [7, 6, 5, 4, 3, 2, 1, 0]];
                for m in self.moves.iter_mut() {
                    let rank = rank(m.dest_square());
                    m.set_score(unsafe {
                        *SCORE_LOOKUP.get_unchecked(self.position.board().to_move())
                                     .get_unchecked(rank)
                    });
                }

                state.phase = NodePhase::SortedQuietMoves;
            }

            // Last, quiet moves.
            if self.position.do_move(m) {
                if state.checkers != 0 {
                    // When in check, we set a high move score to all
                    // moves to avoid search depth reductions.
                    m.set_score(MAX_MOVE_SCORE - 1);
                }
                return Some(m);
            }
        }
        None
    }

    // Takes the last played move back.
    #[inline]
    fn undo_move(&mut self) {
        self.position.undo_move();
    }

    // Stores updated node information in the transposition table.
    #[inline]
    fn store(&mut self, value: Value, bound: BoundType, depth: u8, best_move: Move) {
        let entry = &self.state_stack.last().unwrap().entry;
        self.tt.store(self.position.hash(),
                      EntryData::new(value, bound, depth, best_move.digest(), entry.eval_value()));
    }

    // Reports search progress.
    //
    // From time to time, we should report how many nodes had been
    // searched since the beginning of the search. This also gives an
    // opportunity for the search to be terminated.
    #[inline]
    fn report_progress(&mut self, new_nodes: NodeCount) -> Result<(), TerminatedSearch> {
        self.unreported_nodes += new_nodes;
        if self.unreported_nodes >= super::NODE_COUNT_REPORT_INTERVAL {
            self.reported_nodes += self.unreported_nodes;
            self.unreported_nodes = 0;
            if (*self.report_function)(self.reported_nodes) {
                return Err(TerminatedSearch);
            }
        }
        Ok(())
    }
}

enum NodePhase {
    Pristine,
    TriedHashMove,
    GeneratedMoves,
    TriedGoodCaptures,
    TriedBadCaptures,
    SortedQuietMoves,
}

struct NodeState {
    phase: NodePhase,
    entry: EntryData,
    checkers: u64,
}

#[cfg(test)]
mod tests {
    use super::Search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let tt = TranspositionTable::new();
        let mut moves = MoveStack::new();
        let mut report = |_| false;
        let mut search = Search::new(p, &tt, &mut moves, &mut report);
        let value = search.run(-30000, 30000, 2)
                          .ok()
                          .unwrap();
        assert!(value < -300);
        search.reset();
        let value = search.run(-30000, 30000, 4)
                          .ok()
                          .unwrap();
        assert!(value >= 20000);
    }
}
<commit_msg>move some logic from Search::run() to node_begin()<commit_after>//! Implements single-threaded game tree search.

use basetypes::*;
use bitsets::*;
use chess_move::*;
use tt::*;
use position::Position;

/// Represents a terminated search condition.
pub struct TerminatedSearch;

/// Represents a game tree search.
pub struct Search<'a> {
    tt: &'a TranspositionTable,
    position: Position,
    moves: &'a mut MoveStack,
    moves_starting_ply: usize,
    state_stack: Vec<NodeState>,
    reported_nodes: NodeCount,
    unreported_nodes: NodeCount,
    report_function: &'a mut FnMut(NodeCount) -> bool,
}

impl<'a> Search<'a> {
    /// Creates a new instance.
    ///
    /// `report_function` should be a function that registers the
    /// search progress. It will be called with the number of searched
    /// positions from the beginning of the search to this moment. The
    /// function should return `true` if the search should be
    /// terminated, otherwise it should return `false`.
    pub fn new(root: Position,
               tt: &'a TranspositionTable,
               move_stack: &'a mut MoveStack,
               report_function: &'a mut FnMut(NodeCount) -> bool)
               -> Search<'a> {
        let moves_starting_ply = move_stack.ply();
        Search {
            tt: tt,
            position: root,
            moves: move_stack,
            moves_starting_ply: moves_starting_ply,
            state_stack: Vec::with_capacity(32),
            reported_nodes: 0,
            unreported_nodes: 0,
            report_function: report_function,
        }
    }

    /// Performs a principal variation search (PVS) and returns a
    /// result.
    ///
    /// The alpha-beta algorithm is a significant enhancement to the
    /// minimax search algorithm that eliminates the need to search
    /// large portions of the game tree applying a branch-and-bound
    /// technique. Remarkably, it does this without any potential of
    /// overlooking a better move. If one already has found a quite
    /// good move and search for alternatives, one refutation is
    /// enough to avoid it. No need to look for even stronger
    /// refutations. The algorithm maintains two values, alpha and
    /// beta. They represent the minimum score that the maximizing
    /// player is assured of and the maximum score that the minimizing
    /// player is assured of respectively. PVS is an enhancement to
    /// the alpha-beta search, based on zero (null) window searches of
    /// none PV-nodes, to prove a move is worse or not than an already
    /// safe score from the principal variation. (The principal
    /// variation (PV) is a sequence of moves that the program
    /// considers best and therefore expects to be played.)
    ///
    /// **Important note**: This method may leave un-restored move
    /// lists in the move stack. Call `reset` if you want the move
    /// stack to be restored to the state it had when the search
    /// instance was created.
    pub fn run(&mut self,
               mut alpha: Value, // lower bound
               beta: Value, // upper bound
               depth: u8)
               -> Result<Value, TerminatedSearch> {
        assert!(alpha < beta);

        if let Some(value) = self.node_begin(alpha, beta, depth) {
            // We already have the position's value.
            alpha = value;

        } else {
            // Initial guests for the final result.
            let mut bound = BOUND_UPPER;
            let mut best_move = Move::invalid();

            // On non-leaf nodes, try moves.
            let mut no_moves_yet = true;
            while let Some(m) = self.do_move() {
                try!(self.report_progress(1));

                // Make a recursive call.
                let value = if no_moves_yet {
                    // The first move we analyze with a fully open window
                    // (alpha, beta). If this happens to be a good move,
                    // it will probably raise `alpha`.
                    no_moves_yet = false;
                    -try!(self.run(-beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that they
                    // are not better than our current best move. For this
                    // purpose we analyze them with a null window (alpha,
                    // alpha + 1). This is faster than a full window
                    // search. Only if we are certain that the move is
                    // better than our current best move, we do a
                    // full-window search.
                    match -try!(self.run(-alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(self.run(-beta, -alpha, depth - 1)),
                    }
                };
                self.undo_move();

                // See how good this move was.
                if value >= beta {
                    // This move is so good, that the opponent will
                    // probably not allow this line of play to
                    // happen. Therefore we should not lose any more time
                    // on this position.
                    alpha = beta;
                    bound = BOUND_LOWER;
                    best_move = m;
                    break;
                }
                if value > alpha {
                    // We found a new best move.
                    alpha = value;
                    bound = BOUND_EXACT;
                    best_move = m;
                }
            }

            // Check if we are in a final position (no legal moves).
            if no_moves_yet {
                let value = self.position.evaluate_final();
                if value >= beta {
                    alpha = beta;
                    bound = BOUND_LOWER;
                }
                if value > alpha {
                    alpha = value;
                    bound = BOUND_EXACT;
                }
            }

            // Store the result to the TT.
            self.store(alpha, bound, depth, best_move);
        }

        self.node_end();
        Ok(alpha)
    }

    /// Returns the number of searched positions.
    #[inline(always)]
    pub fn node_count(&self) -> NodeCount {
        self.reported_nodes + self.unreported_nodes
    }

    /// Resets the instance to the state it had when it was created.
    #[inline]
    pub fn reset(&mut self) {
        while self.moves.ply() > self.moves_starting_ply {
            self.moves.restore();
        }
        self.state_stack.clear();
        self.reported_nodes = 0;
        self.unreported_nodes = 0;
    }

    // Declares that we are starting to process a new node.
    //
    // Each recursive call to `run` begins with a call to
    // `node_begin`. The returned value (if not `None`) is the value
    // assigned to the node (taken from the TT or, on leaf nodes --
    // calculated by performing quiescence search).
    #[inline]
    fn node_begin(&mut self, alpha: Value, beta: Value, depth: u8) -> Option<Value> {
        // Consult the transposition table.
        let entry = if let Some(e) = self.tt.probe(self.position.hash()) {
            e
        } else {
            EntryData::new(0, BOUND_NONE, 0, 0, self.position.evaluate_static())
        };
        self.state_stack.push(NodeState {
            phase: NodePhase::Pristine,
            entry: entry,
            checkers: BB_UNIVERSAL_SET,
        });

        // Check if the TT entry gives the result.
        if entry.depth() >= depth {
            let value = entry.value();
            let bound = entry.bound();
            if value >= beta && bound & BOUND_LOWER != 0 {
                return Some(beta);
            }
            if value <= alpha && bound & BOUND_UPPER != 0 {
                return Some(alpha);
            }
            if bound == BOUND_EXACT {
                return Some(value);
            };
        };

        // On leaf nodes, do quiescence search.
        if depth == 0 {
            let eval_value = entry.eval_value();
            let (mut value, nodes) = self.position
                                         .evaluate_quiescence(alpha, beta, Some(eval_value));
            self.report_progress(nodes).ok();
            let bound = if value >= beta {
                value = beta;
                BOUND_LOWER
            } else if value <= alpha {
                value = alpha;
                BOUND_UPPER
            } else {
                BOUND_EXACT
            };
            self.tt.store(self.position.hash(),
                          EntryData::new(value, bound, 0, 0, eval_value));
            return Some(value);
        }

        None
    }

    // Declares that we are done processing the current node.
    //
    // Each recursive call to `run` ends with a call to `node_end`.
    #[inline]
    fn node_end(&mut self) {
        if let NodePhase::Pristine = self.state_stack.last().unwrap().phase {
            // For pristine nodes we have not saved the move list
            // yet, so we should not restore it.
        } else {
            self.moves.restore();
        }
        self.state_stack.pop();
    }

    // TODO: Implement do_null_move() method?

    // Plays the next legal move in the current position and returns
    // it.
    //
    // Each call to `do_move` for the same position will play and
    // return a different move. When all legal moves has been played,
    // `None` will be returned. `do_move` will do whatever it can to
    // play the best moves first, and the worst last. It will also try
    // to be efficient, for example it will generate the list of all
    // pseudo-legal moves at the last possible moment.
    #[inline]
    fn do_move(&mut self) -> Option<Move> {
        let state = self.state_stack.last_mut().unwrap();

        // Try the hash move first.
        if let NodePhase::Pristine = state.phase {
            // We save the move list at the last possible moment,
            // because most of the nodes are leafs.
            self.moves.save();

            // We save the checkers bitboard also, because we will
            // need this information later many times, and we do not
            // want to recalculate it needlessly.
            //
            // TODO: Verify if this is the best place to calculate
            // checkers, especially in relation to trying null moves.
            state.checkers = self.position.board().checkers();

            state.phase = NodePhase::TriedHashMove;
            if state.entry.move16() != 0 {
                if let Some(mut m) = self.position.try_move_digest(state.entry.move16()) {
                    if self.position.do_move(m) {
                        m.set_score(MAX_MOVE_SCORE);
                        return Some(m);
                    }
                }
            }
        }

        // After the hash move, we generate all pseudo-legal
        // moves. But we should not forget to remove the already tried
        // hash move from the list.
        if let NodePhase::TriedHashMove = state.phase {
            // TODO: `generate_moves` needs `_checkers` and `_pinned`
            // to do its work. At this time we already have generated
            // them, so we should use them.
            self.position.board()._checkers.set(state.checkers);

            self.position.generate_moves(self.moves);
            if state.entry.move16() != 0 {
                self.moves.remove_move(state.entry.move16());
            }
            state.phase = NodePhase::GeneratedMoves;
        }

        // Spit out the generated moves.
        while let Some(mut m) = self.moves.remove_best_move() {

            // First, the good captures.
            if let NodePhase::GeneratedMoves = state.phase {
                if m.score() == MAX_MOVE_SCORE {
                    if self.position.evaluate_move(m) >= 0 {
                        if self.position.do_move(m) {
                            return Some(m);
                        }
                        continue;
                    }
                    // This is a bad capture -- push it back to the
                    // move stack.
                    m.set_score(MAX_MOVE_SCORE - 1);
                    self.moves.push(m);
                    continue;
                }
                state.phase = NodePhase::TriedGoodCaptures;
            }

            // Second, the bad captures.
            if let NodePhase::TriedGoodCaptures = state.phase {
                if m.score() == MAX_MOVE_SCORE - 1 {
                    if self.position.do_move(m) {
                        return Some(m);
                    }
                    continue;
                }
                state.phase = NodePhase::TriedBadCaptures;
            }

            // Before trying the quiet moves, we should assign proper
            // move scores to them.
            if let NodePhase::TriedBadCaptures = state.phase {
                // TODO: Assign the moves scores here using the killer
                // move heuristics and the history heuristics.

                // We use the score field (2 bits) to properly order
                // quiet movies. Moves which destination square is
                // more advanced into enemy's territory are tried
                // first. The logic is that those moves are riskier,
                // so if such a move loses material this will be
                // detected early and the search tree will be pruned,
                // but if the move does not lose material, chances are
                // that it is a very good move.
                const SCORE_LOOKUP: [[u32; 8]; 2] = [// white
                                                     [0, 1, 2, 3, 4, 5, 6, 7],
                                                     // black
                                                     [7, 6, 5, 4, 3, 2, 1, 0]];
                for m in self.moves.iter_mut() {
                    let rank = rank(m.dest_square());
                    m.set_score(unsafe {
                        *SCORE_LOOKUP.get_unchecked(self.position.board().to_move())
                                     .get_unchecked(rank)
                    });
                }

                state.phase = NodePhase::SortedQuietMoves;
            }

            // Last, quiet moves.
            if self.position.do_move(m) {
                if state.checkers != 0 {
                    // When in check, we set a high move score to all
                    // moves to avoid search depth reductions.
                    m.set_score(MAX_MOVE_SCORE - 1);
                }
                return Some(m);
            }
        }
        None
    }

    // Takes the last played move back.
    #[inline]
    fn undo_move(&mut self) {
        self.position.undo_move();
    }

    // Stores updated node information in the transposition table.
    #[inline]
    fn store(&mut self, value: Value, bound: BoundType, depth: u8, best_move: Move) {
        let entry = &self.state_stack.last().unwrap().entry;
        self.tt.store(self.position.hash(),
                      EntryData::new(value, bound, depth, best_move.digest(), entry.eval_value()));
    }

    // Reports search progress.
    //
    // From time to time, we should report how many nodes had been
    // searched since the beginning of the search. This also gives an
    // opportunity for the search to be terminated.
    #[inline]
    fn report_progress(&mut self, new_nodes: NodeCount) -> Result<(), TerminatedSearch> {
        self.unreported_nodes += new_nodes;
        if self.unreported_nodes >= super::NODE_COUNT_REPORT_INTERVAL {
            self.reported_nodes += self.unreported_nodes;
            self.unreported_nodes = 0;
            if (*self.report_function)(self.reported_nodes) {
                return Err(TerminatedSearch);
            }
        }
        Ok(())
    }
}

enum NodePhase {
    Pristine,
    TriedHashMove,
    GeneratedMoves,
    TriedGoodCaptures,
    TriedBadCaptures,
    SortedQuietMoves,
}

struct NodeState {
    phase: NodePhase,
    entry: EntryData,
    checkers: u64,
}

#[cfg(test)]
mod tests {
    use super::Search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let tt = TranspositionTable::new();
        let mut moves = MoveStack::new();
        let mut report = |_| false;
        let mut search = Search::new(p, &tt, &mut moves, &mut report);
        let value = search.run(-30000, 30000, 2)
                          .ok()
                          .unwrap();
        assert!(value < -300);
        search.reset();
        let value = search.run(-30000, 30000, 4)
                          .ok()
                          .unwrap();
        assert!(value >= 20000);
    }
}
<|endoftext|>


<commit_before>use crate::paths::TargetDir;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

pub(crate) fn target_dir(out_dir: &Path) -> TargetDir {
    try_target_dir(out_dir).map_or(TargetDir::Unknown, TargetDir::Path)
}

fn try_target_dir(out_dir: &Path) -> Option<PathBuf> {
    if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") {
        return Some(PathBuf::from(target_dir));
    }

    let cargo = option_env!("CARGO").unwrap_or("cargo");
    let output = Command::new(cargo)
        .current_dir(out_dir)
        .arg("metadata")
        .arg("--no-deps")
        .arg("--format-version=1")
        .output()
        .ok()?;

    // Cargo only outputs utf8 encoded JSON.
    let mut metadata = str::from_utf8(&output.stdout).ok()?;

    let key_pattern = "\"target_directory\":";
    let key_index = metadata.rfind(key_pattern)?;
    metadata = &metadata[key_index + key_pattern.len()..];
    let open_quote_index = metadata.find('"')?;
    metadata = &metadata[open_quote_index + 1..];
    let close_quote_index = metadata.find('"')?;
    let string = &metadata[..close_quote_index];
    let target_directory = string.replace("\\\\", "\\");
    Some(PathBuf::from(target_directory))
}
<commit_msg>Skip trying to call `cargo metadata` if CARGO_TARGET_DIR is relative<commit_after>use crate::paths::TargetDir;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

pub(crate) fn target_dir(out_dir: &Path) -> TargetDir {
    try_target_dir(out_dir).map_or(TargetDir::Unknown, TargetDir::Path)
}

fn try_target_dir(out_dir: &Path) -> Option<PathBuf> {
    if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") {
        let target_dir = PathBuf::from(target_dir);
        if target_dir.is_absolute() {
            return Some(target_dir);
        } else {
            return None;
        };
    }

    let cargo = option_env!("CARGO").unwrap_or("cargo");
    let output = Command::new(cargo)
        .current_dir(out_dir)
        .arg("metadata")
        .arg("--no-deps")
        .arg("--format-version=1")
        .output()
        .ok()?;

    // Cargo only outputs utf8 encoded JSON.
    let mut metadata = str::from_utf8(&output.stdout).ok()?;

    let key_pattern = "\"target_directory\":";
    let key_index = metadata.rfind(key_pattern)?;
    metadata = &metadata[key_index + key_pattern.len()..];
    let open_quote_index = metadata.find('"')?;
    metadata = &metadata[open_quote_index + 1..];
    let close_quote_index = metadata.find('"')?;
    let string = &metadata[..close_quote_index];
    let target_directory = string.replace("\\\\", "\\");
    Some(PathBuf::from(target_directory))
}
<|endoftext|>


<commit_before>extern crate euclid;
extern crate image;
extern crate num;
extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate tempdir;
extern crate time;
extern crate vec_map;

mod alg_misc;
mod colors;
pub mod ease;
mod flick;
mod fov;
mod hex;
mod hex_fov;
mod incremental;
mod legend_builder;
mod parser;
mod prefab;
mod rng;
mod search;
mod space;
mod system;
mod text;
mod timing;

pub use alg_misc::{
    bounding_rect, clamp, compact_bits_by_2, lerp, retry_gen, spread_bits_by_2, Deciban,
    GenericError, LerpPath, Noise, WeightedChoice,
};
pub use colors::{
    color, scolor, term_color, to_linear, to_srgb, BaseTermColor, PseudoTermColor, Rgba, SRgba,
    TermColor, Xterm256Color, NAMED_COLORS,
};
pub use flick::Flick;
pub use fov::{Fov, FovValue, PolarPoint};
pub use hex::{hex_disc, hex_neighbors, taxicab_neighbors, Dir12, Dir6, HexDisc, HexGeom};
pub use hex_fov::{AddFakeIsometricCorners, HexFov, HexFovIter, HexPolarPoint};
pub use incremental::{Incremental, IncrementalState};
pub use legend_builder::LegendBuilder;
pub use prefab::{
    DenseTextMap, FromPrefab, IntoPrefab, MinimapSpace, PrefabError, ProjectedImage, TextSpace,
};
pub use rng::{seeded_rng, RandomPermutation, RngExt};
pub use search::{astar_path, Dijkstra, GridNode};
pub use space::{CellSpace, CellVector, Space, Transformation};
pub use system::{app_data_path, save_screenshot, TimeLogItem};
pub use text::{split_line, templatize};
pub use timing::{cycle_anim, single_anim, spike, TimestepLoop};
<commit_msg>Public FLICKS_PER_SECOND<commit_after>extern crate euclid;
extern crate image;
extern crate num;
extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate tempdir;
extern crate time;
extern crate vec_map;

mod alg_misc;
mod colors;
pub mod ease;
mod flick;
mod fov;
mod hex;
mod hex_fov;
mod incremental;
mod legend_builder;
mod parser;
mod prefab;
mod rng;
mod search;
mod space;
mod system;
mod text;
mod timing;

pub use alg_misc::{
    bounding_rect, clamp, compact_bits_by_2, lerp, retry_gen, spread_bits_by_2, Deciban,
    GenericError, LerpPath, Noise, WeightedChoice,
};
pub use colors::{
    color, scolor, term_color, to_linear, to_srgb, BaseTermColor, PseudoTermColor, Rgba, SRgba,
    TermColor, Xterm256Color, NAMED_COLORS,
};
pub use flick::{FLICKS_PER_SECOND, Flick};
pub use fov::{Fov, FovValue, PolarPoint};
pub use hex::{hex_disc, hex_neighbors, taxicab_neighbors, Dir12, Dir6, HexDisc, HexGeom};
pub use hex_fov::{AddFakeIsometricCorners, HexFov, HexFovIter, HexPolarPoint};
pub use incremental::{Incremental, IncrementalState};
pub use legend_builder::LegendBuilder;
pub use prefab::{
    DenseTextMap, FromPrefab, IntoPrefab, MinimapSpace, PrefabError, ProjectedImage, TextSpace,
};
pub use rng::{seeded_rng, RandomPermutation, RngExt};
pub use search::{astar_path, Dijkstra, GridNode};
pub use space::{CellSpace, CellVector, Space, Transformation};
pub use system::{app_data_path, save_screenshot, TimeLogItem};
pub use text::{split_line, templatize};
pub use timing::{cycle_anim, single_anim, spike, TimestepLoop};
<|endoftext|>


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

use libc::c_char;
use libc;

use std::ffi::CString;
use std::mem;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type id = libc::intptr_t;

#[cfg(target_pointer_width = "32")]
pub type NSInteger = libc::c_int;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = libc::c_uint;

#[cfg(target_pointer_width = "64")]
pub type NSInteger = libc::c_long;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = libc::c_ulong;

#[allow(non_upper_case_globals)]
pub const nil: id = 0;
#[allow(non_upper_case_globals)]
pub const Nil: Class = 0 as Class;

pub type BOOL = libc::c_schar;

pub const YES: BOOL = 1;
pub const NO: BOOL = 0;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *const libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
                         types: *const libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *const libc::c_char, value: *mut libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *const libc::c_char, outValue: *mut *mut libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *const libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *const libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL, ...) -> id;
    pub fn objc_msgSend_stret(theReceiver: id, theSelector: SEL, ...);
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *const libc::c_char) -> SEL;
}

/// Returns an Objective-C message send function that returns a type `T`.
pub unsafe fn msg_send<T>() -> extern fn(theReceiver: id, theSelector: SEL, ...) -> T {
    mem::transmute(objc_msgSend)
}

pub unsafe fn msg_send_stret<T>() -> extern fn(theReceiver: id, theSelector: SEL, ...) -> T {
    mem::transmute(objc_msgSend_stret)
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    let name_c_str = CString::from_slice(name.as_bytes());
    unsafe {
        objc_getClass(name_c_str.as_ptr())
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    let name_c_str = CString::from_slice(name.as_bytes());
    unsafe {
        sel_registerName(name_c_str.as_ptr())
    }
}

#[cfg(test)]
mod test {
    use libc;
    use std::ffi::CString;
    use super::*;

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp: id = msg_send()(class("NSApplication"), selector("sharedApplication"));
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let ns_object = class("NSObject");
        let name_c_str = CString::from_slice("MyObject".as_bytes());
        let my_object = unsafe {
            objc_allocateClassPair(ns_object, name_c_str.as_ptr(), 0 as libc::size_t)
        };

        let doSomething = selector("doSomething");
        let types_c_str = CString::from_slice("@@:".as_bytes());
        unsafe {
            let _ = class_addMethod(my_object, doSomething, MyObject_doSomething,
                                    types_c_str.as_ptr());

            objc_registerClassPair(my_object);

            let mut obj: id = msg_send()(my_object, selector("alloc"));
            obj = msg_send()(obj, selector("init"));
            let _: () = msg_send()(obj, selector("doSomething"));
        }
    }
}
<commit_msg>Flushed out the entirety of the Objective-C runtime. Added some extra documentation.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc;
use std::ffi;
use std::mem;

pub type Category = libc::intptr_t;
pub type Class = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type id = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type Method = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type objc_AssociationPolicy = libc::intptr_t;
#[allow(non_camel_case_types)]
pub type objc_property_t = libc::intptr_t;
pub type Protocol = libc::intptr_t;
pub type SEL = libc::intptr_t;

#[cfg(target_pointer_width = "32")]
pub type NSInteger = libc::c_int;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = libc::c_uint;
#[cfg(target_pointer_width = "32")]
#[allow(non_camel_case_types)]
pub type ptrdiff_t = libc::c_int;

#[cfg(target_pointer_width = "64")]
pub type NSInteger = libc::c_long;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = libc::c_ulong;
#[cfg(target_pointer_width = "64")]
#[allow(non_camel_case_types)]
pub type ptrdiff_t = libc::c_long;

#[allow(non_upper_case_globals)]
pub const nil: id = 0;
#[allow(non_upper_case_globals)]
pub const Nil: Class = 0 as Class;

pub type BOOL = libc::c_schar;
pub const NO: BOOL = 0;
pub const YES: BOOL = 1;

#[allow(non_camel_case_types, missing_copy_implementations)]
#[repr(C)]
pub struct objc_method_description {
    name: SEL,
    types: *mut libc::c_char,
}

#[allow(non_camel_case_types, missing_copy_implementations)]
#[repr(C)]
pub struct objc_property_attribute_t {
    name: *const libc::c_char,
    value: *const libc::c_char,
}

#[allow(non_camel_case_types, missing_copy_implementations)]
#[repr(C)]
pub struct objc_super {
    receiver: id,
    cls: Class,
    super_class: Class,
}

#[link(name = "objc")]
extern {
    pub fn class_addProperty(cls: Class,
                             name: *const libc::c_char,
                             attributes: *const objc_property_attribute_t,
                             attributeCount: libc::uint32_t) -> BOOL;
    pub fn class_addProtocol(cls: Class, protocol: *mut Protocol) -> BOOL;
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> BOOL;
    pub fn class_addIvar(cls: Class,
                         name: *const libc::c_char,
                         size: libc::size_t,
                         alignment: libc::uint8_t,
                         types: *const libc::c_char) -> BOOL;
    pub fn class_conformsToProtocol(cls: Class, protocol: *mut Protocol) -> BOOL;
    pub fn class_copyIvarList(cls: Class, outCount: *mut libc::uint32_t) -> *mut Ivar;
    pub fn class_copyMethodList(cls: Class, outCount: *mut libc::uint32_t) -> *mut Method;
    pub fn class_copyPropertyList(cls: Class,
                                  outCount: *mut libc::uint32_t) -> *mut objc_property_t;
    pub fn class_copyProtocolList(cls: Class, outCount: *mut libc::uint32_t) -> *mut *mut Protocol;
    pub fn class_createInstance(cls: Class, extraBytes: libc::size_t) -> id;
    pub fn class_getClassMethod(cls: Class, name: SEL) -> Method;
    pub fn class_getFutureClass(name: *const libc::c_char) -> Class;
    pub fn class_getIvarLayout(cls: Class) -> *const libc::uint8_t;
    pub fn class_getImageName(cls: Class) -> *const libc::c_char;
    pub fn class_getInstanceMethod(cls: Class, name: SEL) -> Method;
    pub fn class_getInstanceSize(cls: Class) -> libc::size_t;
    pub fn class_getInstanceVariable(cls: Class, name: *const libc::c_char) -> Ivar;
    pub fn class_getMethodImplementation(cls: Class, name: SEL) -> IMP;
    pub fn class_getMethodImplementation_stret(cls: Class, name: SEL) -> IMP;
    pub fn class_getName(cls: Class) -> *const libc::c_char;
    pub fn class_getProperty(cls: Class, name: *const libc::c_char) -> objc_property_t;
    pub fn class_getSuperclass(cls: Class) -> Class;
    pub fn class_getVersion(cls: Class) -> libc::int32_t;
    pub fn class_getWeakIvarLayout(cls: Class) -> *const libc::uint8_t;
    pub fn class_isMetaClass(cls: Class) -> BOOL;
    pub fn class_replaceMethod(cls: Class, name: SEL, imp: IMP, types: *const libc::c_char) -> IMP;
    pub fn class_replaceProperty(cls: Class,
                                 name: *const libc::c_char,
                                 attributes: *const objc_property_attribute_t,
                                 attributeCount: libc::uint32_t);
    pub fn class_respondsToSelector(cls: Class, sel: SEL) -> BOOL;
    pub fn class_setFutureClass(cls: Class, name: *const libc::c_char);
    pub fn class_setIvarLayout(cls: Class, layout: *const libc::uint8_t);
    pub fn class_setSuperclass(cls: Class, newSuper: Class);
    pub fn class_setWeakIvarLayout(cls: Class, layout: *const libc::uint8_t);
    pub fn class_setVersion(cls: Class, name: libc::int32_t);
    pub fn imp_getBlock(imp: IMP) -> id;
    pub fn imp_implementationWithBlock(block: id) -> IMP;
    pub fn imp_removeBlock(imp: IMP) -> BOOL;
    pub fn ivar_getName(ivar: Ivar) -> *const libc::c_char;
    pub fn ivar_getOffset(ivar: Ivar) -> ptrdiff_t;
    pub fn ivar_getTypeEncoding(ivar: Ivar) -> *const libc::c_char;
    pub fn method_copyArgumentType(m: Method, index: libc::uint32_t) -> *mut libc::c_char;
    pub fn method_copyReturnType(m: Method) -> *mut libc::c_char;
    pub fn method_getArgumentType(m: Method,
                                  index: libc::uint32_t,
                                  dst: *mut libc::c_char,
                                  dst_len: libc::size_t);
    pub fn method_getDescription(m: Method) -> *mut objc_method_description;
    pub fn method_exchangeImplementations(m1: Method, m2: Method);
    pub fn method_getImplementation(m: Method) -> IMP;
    pub fn method_getName(m: Method) -> SEL;
    pub fn method_getNumberOfArguments(m: Method) -> libc::uint32_t;
    pub fn method_getReturnType(m: Method, dst: *mut libc::c_char, dst_len: libc::size_t);
    pub fn method_getTypeEncoding(m: Method) -> *const libc::c_char;
    pub fn method_invoke(receiver: id, m: Method, ...) -> id;
    pub fn method_invoke_stret(receiver: id, m: Method, ...);
    pub fn method_setImplementation(m: Method, imp: IMP) -> IMP;
    pub fn objc_allocateClassPair(superclass: Class,
                                  name: *const libc::c_char,
                                  extraBytes: libc::size_t) -> Class;
    pub fn objc_allocateProtocol(name: *const libc::c_char) -> *mut Protocol;
    pub fn objc_constructInstance(cls: Class, bytes: *mut libc::c_void) -> id;
    pub fn objc_copyClassList(outCount: *mut libc::uint32_t) -> *mut Class;
    pub fn objc_copyClassNamesForImage(image: *const libc::c_char,
                                       outCount: *mut libc::uint32_t) -> *const *const libc::c_char;
    pub fn objc_copyImageNames(outCount: *mut libc::uint32_t) -> *const *const libc::c_char;
    pub fn objc_copyProtocolList(outCount: *mut libc::uint32_t) -> *mut *mut Protocol;
    pub fn objc_destructInstance(obj: id) -> *mut libc::c_void;
    pub fn objc_disposeClassPair(cls: Class);
    pub fn objc_duplicateClass(original: Class,
                               name: *const libc::c_char,
                               extraBytes: libc::size_t) -> Class;
    pub fn objc_enumerationMutation(obj: id);
    pub fn objc_getAssociatedObject(object: id, key: *const libc::c_void) -> id;
    pub fn objc_getClass(name: *const libc::c_char) -> Class;
    pub fn objc_getClassList(buffer: *mut Class, bufferCount: libc::int32_t) -> libc::int32_t;
    pub fn objc_getMetaClass(name: *const libc::c_char) -> Class;
    pub fn objc_getProtocol(name: *const libc::c_char) -> *mut Protocol;
    pub fn objc_getRequiredClass(name: *const libc::c_char) -> Class;
    pub fn objc_loadWeak(location: *mut id) -> id;
    pub fn objc_storeWeak(location: *mut id, obj: id) -> id;
    pub fn objc_msgSend(target: id, selector: SEL, ...) -> id;
    pub fn objc_msgSend_ftret(target: id, selector: SEL, ...) -> libc::c_double;
    pub fn objc_msgSend_stret(target: id, selector: SEL, ...);
    pub fn objc_msgSendSuper(sup: *mut objc_super, op: SEL, ...) -> id;
    pub fn objc_msgSendSuper_stret(sup: *mut objc_super, op: SEL, ...);
    pub fn objc_registerClassPair(cls: Class);
    pub fn objc_registerProtocol(proto: *mut Protocol);
    pub fn objc_removeAssociatedObjects(object: id);
    pub fn objc_setAssociatedObject(object: id,
                                    key: *const libc::c_void,
                                    value: id,
                                    policy: objc_AssociationPolicy);
    pub fn objc_setEnumerationMutationHandler(handler: extern fn (id));
    pub fn object_copy(obj: id, size: libc::size_t) -> id;
    pub fn object_dispose(obj: id) -> id;
    pub fn object_getClass(obj: id) -> Class;
    pub fn object_getClassName(obj: id) -> *const libc::c_char;
    pub fn object_getIndexedIvars(obj: id) -> *mut libc::c_void;
    pub fn object_getInstanceVariable(obj: id,
                                      name: *const libc::c_char,
                                      outValue: *mut *mut libc::c_void);
    pub fn object_getIvar(obj: id, ivar: Ivar) -> id;
    pub fn object_setClass(obj: id, cls: Class) -> Class;
    pub fn object_setInstanceVariable(obj: id,
                                      name: *const libc::c_char,
                                      value: *mut libc::c_void);
    pub fn object_setIvar(obj: id, ivar: Ivar, value: id);
    pub fn protocol_addMethodDescription(proto: *mut Protocol,
                                         name: SEL,
                                         types: *const libc::c_char,
                                         isRequiredMethod: BOOL,
                                         isInstanceMethod: BOOL);
    pub fn protocol_addProperty(proto: *mut Protocol,
                                name: *const libc::c_char,
                                attributes: *const objc_property_attribute_t,
                                attributeCount: libc::uint32_t,
                                isRequiredMethod: BOOL,
                                isInstanceMethod: BOOL);
    pub fn protocol_addProtocol(proto: *mut Protocol, addition: *mut Protocol);
    pub fn protocol_conformsToProtocol(proto: *mut Protocol, other: *mut Protocol) -> BOOL;
    pub fn protocol_copyMethodDescriptionList(proto: *mut Protocol,
                                              isRequiredMethod: BOOL,
                                              isInstanceMethod: BOOL,
                                              outCount: *mut libc::uint32_t
                                             ) -> *mut objc_method_description;
    pub fn protocol_copyPropertyList(proto: *mut Protocol,
                                     outCount: *mut libc::uint32_t) -> *mut objc_property_t;
    pub fn protocol_copyProtocolList(proto: *mut Protocol,
                                     outCount: *mut libc::uint32_t) -> *mut *mut Protocol;
    pub fn protocol_getMethodDescription(proto: *mut Protocol,
                                         name: SEL,
                                         isRequiredMethod: BOOL,
                                         isInstanceMethod: BOOL) -> objc_method_description;
    pub fn protocol_getProperty(proto: *mut Protocol,
                                name: *const libc::c_char,
                                isRequiredMethod: BOOL,
                                isInstanceMethod: BOOL) -> objc_property_t;
    pub fn protocol_getName(proto: *mut Protocol) -> *const libc::c_char;
    pub fn protocol_isEqual(proto: *mut Protocol, other: *mut Protocol) -> BOOL;
    pub fn property_copyAttributeList(property: objc_property_t,
                                      outCount: *mut libc::uint32_t
                                     ) -> *mut objc_property_attribute_t;
    pub fn property_copyAttributeValue(property: objc_property_t,
                                       attributeName: *const libc::c_char) -> *mut libc::c_char;
    pub fn property_getAttributes(property: objc_property_t) -> *const libc::c_char;
    pub fn property_getName(property: objc_property_t) -> *const libc::c_char;
    pub fn sel_getName(sel: SEL) -> *const libc::c_char;
    pub fn sel_getUid(string: *const libc::c_char) -> SEL;
    pub fn sel_isEqual(lhs: SEL, rhs: SEL) -> BOOL;
    pub fn sel_registerName(name: *const libc::c_char) -> SEL;
}

/// Returns an Objective-C message send function that returns a type `T`.
///
/// # Example
///
/// ```
/// # use cocoa::base::{class, selector, msg_send, nil};
/// assert!(unsafe { msg_send()(class("NSObject"), selector("class")) } != nil);
/// ```
pub unsafe fn msg_send<T>() -> extern fn(target: id, selector: SEL, ...) -> T {
    mem::transmute(objc_msgSend)
}

/// Returns an Objective-C message send function that returns a type `T`, where `T` is a struct
/// with the attribute `#[repr(C)]`.
pub unsafe fn msg_send_stret<T>() -> extern fn(target: id, selector: SEL, ...) -> T {
    mem::transmute(objc_msgSend_stret)
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> Class {
    let name_c_str = ffi::CString::from_slice(name.as_bytes());
    unsafe {
        objc_getClass(name_c_str.as_ptr())
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    let name_c_str = ffi::CString::from_slice(name.as_bytes());
    unsafe {
        sel_registerName(name_c_str.as_ptr())
    }
}

#[cfg(test)]
mod test {
    use libc;
    use std::ffi;
    use super::*;

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp: id = msg_send()(class("NSApplication"), selector("sharedApplication"));
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let ns_object = class("NSObject");
        let name_c_str = ffi::CString::from_slice("MyObject".as_bytes());
        let my_object = unsafe {
            objc_allocateClassPair(ns_object, name_c_str.as_ptr(), 0 as libc::size_t)
        };

        let doSomething = selector("doSomething");
        let types_c_str = ffi::CString::from_slice("@@:".as_bytes());
        unsafe {
            let _ = class_addMethod(my_object, doSomething, MyObject_doSomething,
                                    types_c_str.as_ptr());

            objc_registerClassPair(my_object);

            let mut obj: id = msg_send()(my_object, selector("alloc"));
            obj = msg_send()(obj, selector("init"));
            let _: () = msg_send()(obj, selector("doSomething"));
        }
    }
}
<|endoftext|>


<commit_before>pub trait IteratorCloneEach<'a, E, It> where E: Clone, It: Iterator<&'a E> {
    /**
Creates an iterator which will clone each element of the input iterator.
    */
    fn clone_each(self) -> CloneItems<It>;
}

impl<'a, E, It> IteratorCloneEach<'a, E, It> for It where E: Clone, It: Iterator<&'a E> {
    fn clone_each(self) -> CloneItems<It> {
        CloneItems {
            iter: self,
        }
    }
}

pub struct CloneItems<It> {
    iter: It,
}

impl<'a, E, It> Iterator<E> for CloneItems<It> where E: 'a+Clone, It: Iterator<&'a E> {
    fn next(&mut self) -> Option<E> {
        match self.iter.next() {
            None => None,
            Some(e) => Some(e.clone())
        }
    }
}

#[test]
fn test_clone_each() {
    let it: Vec<int> = vec![1, 2, 3];
    let mut it = it.iter().clone_each();
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), None);
}

pub trait IteratorFoldl<E> {
    fn foldl(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldl<E> for It where It: Iterator<E> {
    fn foldl(mut self, f: |E, E| -> E) -> Option<E> {
        let first = match self.next() {
            None => return None,
            Some(e) => e
        };

        Some(self.fold(first, f))
    }
}

#[test]
fn test_foldl() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("((a, b), c)".into_string()), vs.foldl(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorFoldr<E> {
    fn foldr(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldr<E> for It where It: DoubleEndedIterator<E> {
    fn foldr(mut self, f: |E, E| -> E) -> Option<E> {
        let mut last = match self.next_back() {
            None => return None,
            Some(e) => e
        };

        loop {
            match self.next_back() {
                None => break,
                Some(e) => last = f(e, last)
            }
        }

        Some(last)
    }
}

#[test]
fn test_foldr() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("(a, (b, c))".into_string()), vs.foldr(|a,b| format!("({}, {})", a, b)));
}
<commit_msg>Added docs for foldl and foldr.<commit_after>pub trait IteratorCloneEach<'a, E, It> where E: Clone, It: Iterator<&'a E> {
    /**
Creates an iterator which will clone each element of the input iterator.
    */
    fn clone_each(self) -> CloneItems<It>;
}

impl<'a, E, It> IteratorCloneEach<'a, E, It> for It where E: Clone, It: Iterator<&'a E> {
    fn clone_each(self) -> CloneItems<It> {
        CloneItems {
            iter: self,
        }
    }
}

pub struct CloneItems<It> {
    iter: It,
}

impl<'a, E, It> Iterator<E> for CloneItems<It> where E: 'a+Clone, It: Iterator<&'a E> {
    fn next(&mut self) -> Option<E> {
        match self.iter.next() {
            None => None,
            Some(e) => Some(e.clone())
        }
    }
}

#[test]
fn test_clone_each() {
    let it: Vec<int> = vec![1, 2, 3];
    let mut it = it.iter().clone_each();
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), None);
}

pub trait IteratorFoldl<E> {
    /**
Folds the elements of the iterator together, from left to right, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldl(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldl<E> for It where It: Iterator<E> {
    fn foldl(mut self, f: |E, E| -> E) -> Option<E> {
        let first = match self.next() {
            None => return None,
            Some(e) => e
        };

        Some(self.fold(first, f))
    }
}

#[test]
fn test_foldl() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("((a, b), c)".into_string()), vs.foldl(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorFoldr<E> {
    /**
Folds the elements of the iterator together, from right to left, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldr(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldr<E> for It where It: DoubleEndedIterator<E> {
    fn foldr(mut self, f: |E, E| -> E) -> Option<E> {
        let mut last = match self.next_back() {
            None => return None,
            Some(e) => e
        };

        loop {
            match self.next_back() {
                None => break,
                Some(e) => last = f(e, last)
            }
        }

        Some(last)
    }
}

#[test]
fn test_foldr() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("(a, (b, c))".into_string()), vs.foldr(|a,b| format!("({}, {})", a, b)));
}
<|endoftext|>


<commit_before>use codec::{
    eyre::Result, stencila_schema::Node, utils::vec_string, Codec, CodecTrait, DecodeOptions,
    EncodeOptions,
};
use codec_md::MdCodec;

#[cfg(feature = "decode")]
mod decode;

#[cfg(feature = "encode")]
mod encode;

/// A codec for markdown
pub struct RmdCodec {}

impl CodecTrait for RmdCodec {
    fn spec() -> Codec {
        let md_codec = MdCodec::spec();
        Codec {
            status: "alpha".to_string(),
            formats: vec_string!["rmd"],
            root_types: vec_string!["Article"],
            from_string: cfg!(feature = "decode"),
            from_path: cfg!(feature = "decode"),
            to_string: cfg!(feature = "encode"),
            to_path: cfg!(feature = "encode"),
            unsupported_types: md_codec.unsupported_types,
            unsupported_properties: md_codec.unsupported_properties,
        }
    }

    #[cfg(feature = "decode")]
    fn from_str(str: &str, options: Option<DecodeOptions>) -> Result<Node> {
        decode::decode(str, options)
    }

    #[cfg(feature = "encode")]
    fn to_string(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        encode::encode(node, options)
    }
}
<commit_msg>chore(R Markdown codec): Update spec<commit_after>use codec::{
    eyre::Result, stencila_schema::Node, utils::vec_string, Codec, CodecTrait, DecodeOptions,
    EncodeOptions,
};
use codec_md::MdCodec;

#[cfg(feature = "decode")]
mod decode;

#[cfg(feature = "encode")]
mod encode;

/// A codec for R Markdown
pub struct RmdCodec {}

impl CodecTrait for RmdCodec {
    fn spec() -> Codec {
        let md_codec = MdCodec::spec();
        Codec {
            status: "beta".to_string(),
            formats: vec_string!["rmd"],
            root_types: vec_string!["Article"],
            from_string: cfg!(feature = "decode"),
            from_path: cfg!(feature = "decode"),
            to_string: cfg!(feature = "encode"),
            to_path: cfg!(feature = "encode"),
            unsupported_types: md_codec.unsupported_types,
            unsupported_properties: md_codec.unsupported_properties,
        }
    }

    #[cfg(feature = "decode")]
    fn from_str(str: &str, options: Option<DecodeOptions>) -> Result<Node> {
        decode::decode(str, options)
    }

    #[cfg(feature = "encode")]
    fn to_string(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        encode::encode(node, options)
    }
}
<|endoftext|>