<commit_before>//! Cranelift IR entity references.
//!
//! Instructions in Cranelift IR need to reference other entities in the function. This can be other
//! parts of the function like extended basic blocks or stack slots, or it can be external entities
//! that are declared in the function preamble in the text format.
//!
//! These entity references in instruction operands are not implemented as Rust references both
//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers
//! take up a lot of space, and we want a compact in-memory representation. Instead, entity
//! references are structs wrapping a `u32` index into a table in the `Function` main data
//! structure. There is a separate index type for each entity type, so we don't lose type safety.
//!
//! The `entities` module defines public types for the entity references along with constants
//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but
//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact
//! data structures use the `PackedOption<EntityRef>` representation, while function arguments and
//! return values prefer the more Rust-like `Option<EntityRef>` variant.
//!
//! The entity references all implement the `Display` trait in a way that matches the textual IR
//! format.

use crate::entity::entity_impl;
use core::fmt;
use core::u32;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};

/// An opaque reference to an extended basic block in a function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Ebb(u32);
entity_impl!(Ebb, "ebb");

impl Ebb {
    /// Create a new EBB reference from its number. This corresponds to the `ebbNN` representation.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Ebb(n))
        } else {
            None
        }
    }
}

/// An opaque reference to an SSA value.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Value(u32);
entity_impl!(Value, "v");

impl Value {
    /// Create a value from its number representation.
    /// This is the number in the `vNN` notation.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX / 2 {
            Some(Value(n))
        } else {
            None
        }
    }
}

/// An opaque reference to an instruction in a function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Inst(u32);
entity_impl!(Inst, "inst");

/// An opaque reference to a stack slot.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct StackSlot(u32);
entity_impl!(StackSlot, "ss");

impl StackSlot {
    /// Create a new stack slot reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(StackSlot(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a global value.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct GlobalValue(u32);
entity_impl!(GlobalValue, "gv");

impl GlobalValue {
    /// Create a new global value reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(GlobalValue(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a constant
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Constant(u32);
entity_impl!(Constant, "const");

impl Constant {
    /// Create a const reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Constant(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a jump table.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct JumpTable(u32);
entity_impl!(JumpTable, "jt");

impl JumpTable {
    /// Create a new jump table reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(JumpTable(n))
        } else {
            None
        }
    }
}

/// A reference to an external function.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct FuncRef(u32);
entity_impl!(FuncRef, "fn");

impl FuncRef {
    /// Create a new external function reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(FuncRef(n))
        } else {
            None
        }
    }
}

/// A reference to a function signature.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct SigRef(u32);
entity_impl!(SigRef, "sig");

impl SigRef {
    /// Create a new function signature reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(SigRef(n))
        } else {
            None
        }
    }
}

/// A reference to a heap.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Heap(u32);
entity_impl!(Heap, "heap");

impl Heap {
    /// Create a new heap reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Heap(n))
        } else {
            None
        }
    }
}

/// A reference to a table.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Table(u32);
entity_impl!(Table, "table");

impl Table {
    /// Create a new table reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Table(n))
        } else {
            None
        }
    }
}

/// A reference to any of the entities defined in this module that can appear in CLIF IR.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum AnyEntity {
    /// The whole function.
    Function,
    /// An extended basic block.
    Ebb(Ebb),
    /// An instruction.
    Inst(Inst),
    /// An SSA value.
    Value(Value),
    /// A stack slot.
    StackSlot(StackSlot),
    /// A Global value.
    GlobalValue(GlobalValue),
    /// A jump table.
    JumpTable(JumpTable),
    /// An external function.
    FuncRef(FuncRef),
    /// A function call signature.
    SigRef(SigRef),
    /// A heap.
    Heap(Heap),
    /// A table.
    Table(Table),
}

impl fmt::Display for AnyEntity {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            AnyEntity::Function => write!(f, "function"),
            AnyEntity::Ebb(r) => r.fmt(f),
            AnyEntity::Inst(r) => r.fmt(f),
            AnyEntity::Value(r) => r.fmt(f),
            AnyEntity::StackSlot(r) => r.fmt(f),
            AnyEntity::GlobalValue(r) => r.fmt(f),
            AnyEntity::JumpTable(r) => r.fmt(f),
            AnyEntity::FuncRef(r) => r.fmt(f),
            AnyEntity::SigRef(r) => r.fmt(f),
            AnyEntity::Heap(r) => r.fmt(f),
            AnyEntity::Table(r) => r.fmt(f),
        }
    }
}

impl fmt::Debug for AnyEntity {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self as &dyn fmt::Display).fmt(f)
    }
}

impl From<Ebb> for AnyEntity {
    fn from(r: Ebb) -> Self {
        AnyEntity::Ebb(r)
    }
}

impl From<Inst> for AnyEntity {
    fn from(r: Inst) -> Self {
        AnyEntity::Inst(r)
    }
}

impl From<Value> for AnyEntity {
    fn from(r: Value) -> Self {
        AnyEntity::Value(r)
    }
}

impl From<StackSlot> for AnyEntity {
    fn from(r: StackSlot) -> Self {
        AnyEntity::StackSlot(r)
    }
}

impl From<GlobalValue> for AnyEntity {
    fn from(r: GlobalValue) -> Self {
        AnyEntity::GlobalValue(r)
    }
}

impl From<JumpTable> for AnyEntity {
    fn from(r: JumpTable) -> Self {
        AnyEntity::JumpTable(r)
    }
}

impl From<FuncRef> for AnyEntity {
    fn from(r: FuncRef) -> Self {
        AnyEntity::FuncRef(r)
    }
}

impl From<SigRef> for AnyEntity {
    fn from(r: SigRef) -> Self {
        AnyEntity::SigRef(r)
    }
}

impl From<Heap> for AnyEntity {
    fn from(r: Heap) -> Self {
        AnyEntity::Heap(r)
    }
}

impl From<Table> for AnyEntity {
    fn from(r: Table) -> Self {
        AnyEntity::Table(r)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::u32;
    use std::string::ToString;

    #[test]
    fn value_with_number() {
        assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
        assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");

        assert_eq!(Value::with_number(u32::MAX / 2), None);
        assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
    }

    #[test]
    fn memory() {
        use crate::packed_option::PackedOption;
        use core::mem;
        // This is the whole point of `PackedOption`.
        assert_eq!(
            mem::size_of::<Value>(),
            mem::size_of::<PackedOption<Value>>()
        );
    }

    #[test]
    fn constant_with_number() {
        assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
        assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
    }
}
<commit_msg>Add more documentation for entities, fixes #1038 (#1041)<commit_after>//! Cranelift IR entity references.
//!
//! Instructions in Cranelift IR need to reference other entities in the function. This can be other
//! parts of the function like extended basic blocks or stack slots, or it can be external entities
//! that are declared in the function preamble in the text format.
//!
//! These entity references in instruction operands are not implemented as Rust references both
//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers
//! take up a lot of space, and we want a compact in-memory representation. Instead, entity
//! references are structs wrapping a `u32` index into a table in the `Function` main data
//! structure. There is a separate index type for each entity type, so we don't lose type safety.
//!
//! The `entities` module defines public types for the entity references along with constants
//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but
//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact
//! data structures use the `PackedOption<EntityRef>` representation, while function arguments and
//! return values prefer the more Rust-like `Option<EntityRef>` variant.
//!
//! The entity references all implement the `Display` trait in a way that matches the textual IR
//! format.

use crate::entity::entity_impl;
use core::fmt;
use core::u32;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};

/// An opaque reference to an [extended basic
/// block](https://en.wikipedia.org/wiki/Extended_basic_block) in a
/// [`Function`](super::function::Function).
///
/// You can get an `Ebb` using
/// [`FunctionBuilder::create_ebb`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_ebb)
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Ebb(u32);
entity_impl!(Ebb, "ebb");

impl Ebb {
    /// Create a new EBB reference from its number. This corresponds to the `ebbNN` representation.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Ebb(n))
        } else {
            None
        }
    }
}

/// An opaque reference to an SSA value.
///
/// You can get a constant `Value` from the following
/// [`InstBuilder`](super::InstBuilder) instructions:
///
/// - [`iconst`](super::InstBuilder::iconst) for integer constants
/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
/// - [`bconst`](super::InstBuilder::bconst) for boolean constants
/// - [`vconst`](super::InstBuilder::vconst) for vector constants
/// - [`null`](super::InstBuilder::null) for null reference constants
///
/// Any `InstBuilder` instruction that has an output will also return a `Value`.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Value(u32);
entity_impl!(Value, "v");

impl Value {
    /// Create a value from its number representation.
    /// This is the number in the `vNN` notation.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX / 2 {
            Some(Value(n))
        } else {
            None
        }
    }
}

/// An opaque reference to an instruction in a [`Function`](super::Function).
///
/// Most usage of `Inst` is internal. `Inst`ructions are returned by
/// [`InstBuilder`](super::InstBuilder) instructions that do not return a
/// [`Value`], such as control flow and trap instructions.
///
/// If you look around the API, you can find many inventive uses for `Inst`,
/// such as [annotating specific instructions with a comment][inst_comment]
/// or [performing reflection at compile time](super::DataFlowGraph::analyze_branch)
/// on the type of instruction.
///
/// [inst_comment]: https://github.com/bjorn3/rustc_codegen_cranelift/blob/0f8814fd6da3d436a90549d4bb19b94034f2b19c/src/pretty_clif.rs
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Inst(u32);
entity_impl!(Inst, "inst");

/// An opaque reference to a stack slot.
///
/// Stack slots represent an address on the
/// [call stack](https://en.wikipedia.org/wiki/Call_stack).
///
/// `StackSlot`s can be created with
/// [`FunctionBuilder::create_stackslot`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_stack_slot).
///
/// `StackSlot`s are most often used with
/// [`stack_addr`](super::InstBuilder::stack_addr),
/// [`stack_load`](super::InstBuilder::stack_load), and
/// [`stack_store`](super::InstBuilder::stack_store).
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct StackSlot(u32);
entity_impl!(StackSlot, "ss");

impl StackSlot {
    /// Create a new stack slot reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(StackSlot(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a global value.
///
/// A `GlobalValue` is a [`Value`](Value) that will be live across the entire
/// function lifetime. It can be preloaded from other global values.
///
/// You can create a `GlobalValue` in the following ways:
///
/// - When compiling to WASM, you can use it to load values from a
/// [`VmContext`](super::GlobalValueData::VMContext) using
/// [`FuncEnvironment::make_global`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_global).
/// - When compiling to native code, you can use it for objects in static memory with
/// [`Module::declare_data_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/struct.Module.html#method.declare_data_in_func).
/// - For any compilation target, it can be registered with
/// [`FunctionBuilder::create_global_value`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_global_value).
///
/// `GlobalValue`s can be retrieved with
/// [`InstBuilder:global_value`](super::InstBuilder::global_value).
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct GlobalValue(u32);
entity_impl!(GlobalValue, "gv");

impl GlobalValue {
    /// Create a new global value reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(GlobalValue(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a constant.
///
/// You can store [`ConstantData`](super::ConstantData) in a
/// [`ConstantPool`](super::ConstantPool) for efficient storage and retrieval.
/// See [`ConstantPool::insert`](super::ConstantPool::insert).
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Constant(u32);
entity_impl!(Constant, "const");

impl Constant {
    /// Create a const reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Constant(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a [jump table](https://en.wikipedia.org/wiki/Branch_table).
///
/// `JumpTable`s are used for indirect branching and are specialized for dense,
/// 0-based jump offsets. If you want a jump table which doesn't start at 0,
/// or is not contiguous, consider using a [`Switch`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.Switch.html) instead.
///
/// `JumpTable` are used with [`br_table`](super::InstBuilder::br_table).
///
/// `JumpTable`s can be created with
/// [`create_jump_table`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_jump_table).
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct JumpTable(u32);
entity_impl!(JumpTable, "jt");

impl JumpTable {
    /// Create a new jump table reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(JumpTable(n))
        } else {
            None
        }
    }
}

/// An opaque reference to another [`Function`](super::Function).
///
/// `FuncRef`s are used for [direct](super::InstBuilder::call) function calls
/// and by [`func_addr`](super::InstBuilder::func_addr) for use in
/// [indirect](super::InstBuilder::call_indirect) function calls.
///
/// `FuncRef`s can be created with
///
/// - [`FunctionBuilder::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
/// for external functions
/// - [`Module::declare_func_in_func`](https://docs.rs/cranelift-module/*/cranelift_module/struct.Module.html#method.declare_func_in_func)
/// for functions declared elsewhere in the same native
/// [`Module`](https://docs.rs/cranelift-module/*/cranelift_module/struct.Module.html)
/// - [`FuncEnvironment::make_direct_func`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_direct_func)
/// for functions declared in the same WebAssembly
/// [`FuncEnvironment`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_direct_func)
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct FuncRef(u32);
entity_impl!(FuncRef, "fn");

impl FuncRef {
    /// Create a new external function reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(FuncRef(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a function [`Signature`](super::Signature).
///
/// `SigRef`s are used to declare a function with
/// [`FunctionBuiler::import_function`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_function)
/// as well as to make an [indirect function call](super::InstBuilder::call_indirect).
///
/// `SigRef`s can be created with
/// [`FunctionBuilder::import_signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.import_signature).
///
/// You can retrieve the [`Signature`](super::Signature) that was used to create a `SigRef` with
/// [`FunctionBuilder::signature`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.signature) or
/// [`func.dfg.signatures`](super::dfg::DataFlowGraph::signatures).
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct SigRef(u32);
entity_impl!(SigRef, "sig");

impl SigRef {
    /// Create a new function signature reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(SigRef(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a [heap](https://en.wikipedia.org/wiki/Memory_management#DYNAMIC).
///
/// Heaps are used to access dynamically allocated memory through
/// [`heap_addr`](super::InstBuilder::heap_addr).
///
/// To create a heap, use [`FunctionBuilder::create_heap`](https://docs.rs/cranelift-frontend/*/cranelift_frontend/struct.FunctionBuilder.html#method.create_heap).
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Heap(u32);
entity_impl!(Heap, "heap");

impl Heap {
    /// Create a new heap reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Heap(n))
        } else {
            None
        }
    }
}

/// An opaque reference to a [WebAssembly
/// table](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#WebAssembly_tables).
///
/// `Table`s are used to store a list of function references.
/// They can be created with [`FuncEnvironment::make_table`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.make_table).
/// They can be used with
/// [`FuncEnvironment::translate_call_indirect`](https://docs.rs/cranelift-wasm/*/cranelift_wasm/trait.FuncEnvironment.html#tymethod.translate_call_indirect).
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Table(u32);
entity_impl!(Table, "table");

impl Table {
    /// Create a new table reference from its number.
    ///
    /// This method is for use by the parser.
    pub fn with_number(n: u32) -> Option<Self> {
        if n < u32::MAX {
            Some(Table(n))
        } else {
            None
        }
    }
}

/// An opaque reference to any of the entities defined in this module that can appear in CLIF IR.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum AnyEntity {
    /// The whole function.
    Function,
    /// An extended basic block.
    Ebb(Ebb),
    /// An instruction.
    Inst(Inst),
    /// An SSA value.
    Value(Value),
    /// A stack slot.
    StackSlot(StackSlot),
    /// A Global value.
    GlobalValue(GlobalValue),
    /// A jump table.
    JumpTable(JumpTable),
    /// An external function.
    FuncRef(FuncRef),
    /// A function call signature.
    SigRef(SigRef),
    /// A heap.
    Heap(Heap),
    /// A table.
    Table(Table),
}

impl fmt::Display for AnyEntity {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            AnyEntity::Function => write!(f, "function"),
            AnyEntity::Ebb(r) => r.fmt(f),
            AnyEntity::Inst(r) => r.fmt(f),
            AnyEntity::Value(r) => r.fmt(f),
            AnyEntity::StackSlot(r) => r.fmt(f),
            AnyEntity::GlobalValue(r) => r.fmt(f),
            AnyEntity::JumpTable(r) => r.fmt(f),
            AnyEntity::FuncRef(r) => r.fmt(f),
            AnyEntity::SigRef(r) => r.fmt(f),
            AnyEntity::Heap(r) => r.fmt(f),
            AnyEntity::Table(r) => r.fmt(f),
        }
    }
}

impl fmt::Debug for AnyEntity {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self as &dyn fmt::Display).fmt(f)
    }
}

impl From<Ebb> for AnyEntity {
    fn from(r: Ebb) -> Self {
        AnyEntity::Ebb(r)
    }
}

impl From<Inst> for AnyEntity {
    fn from(r: Inst) -> Self {
        AnyEntity::Inst(r)
    }
}

impl From<Value> for AnyEntity {
    fn from(r: Value) -> Self {
        AnyEntity::Value(r)
    }
}

impl From<StackSlot> for AnyEntity {
    fn from(r: StackSlot) -> Self {
        AnyEntity::StackSlot(r)
    }
}

impl From<GlobalValue> for AnyEntity {
    fn from(r: GlobalValue) -> Self {
        AnyEntity::GlobalValue(r)
    }
}

impl From<JumpTable> for AnyEntity {
    fn from(r: JumpTable) -> Self {
        AnyEntity::JumpTable(r)
    }
}

impl From<FuncRef> for AnyEntity {
    fn from(r: FuncRef) -> Self {
        AnyEntity::FuncRef(r)
    }
}

impl From<SigRef> for AnyEntity {
    fn from(r: SigRef) -> Self {
        AnyEntity::SigRef(r)
    }
}

impl From<Heap> for AnyEntity {
    fn from(r: Heap) -> Self {
        AnyEntity::Heap(r)
    }
}

impl From<Table> for AnyEntity {
    fn from(r: Table) -> Self {
        AnyEntity::Table(r)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::u32;
    use std::string::ToString;

    #[test]
    fn value_with_number() {
        assert_eq!(Value::with_number(0).unwrap().to_string(), "v0");
        assert_eq!(Value::with_number(1).unwrap().to_string(), "v1");

        assert_eq!(Value::with_number(u32::MAX / 2), None);
        assert!(Value::with_number(u32::MAX / 2 - 1).is_some());
    }

    #[test]
    fn memory() {
        use crate::packed_option::PackedOption;
        use core::mem;
        // This is the whole point of `PackedOption`.
        assert_eq!(
            mem::size_of::<Value>(),
            mem::size_of::<PackedOption<Value>>()
        );
    }

    #[test]
    fn constant_with_number() {
        assert_eq!(Constant::with_number(0).unwrap().to_string(), "const0");
        assert_eq!(Constant::with_number(1).unwrap().to_string(), "const1");
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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 std::ptr;
use std::mem;

use libc;

use glib_ffi;
use gobject_ffi;
use gst_ffi;

use glib;
use glib::translate::*;
use gst;
use gst::prelude::*;

use object::*;
use anyimpl::*;

pub trait ElementImpl<T: ElementBase>
    : ObjectImpl<T> + AnyImpl + Send + Sync + 'static {
    fn change_state(&self, element: &T, transition: gst::StateChange) -> gst::StateChangeReturn {
        element.parent_change_state(transition)
    }

    fn request_new_pad(
        &self,
        _element: &T,
        _templ: &gst::PadTemplate,
        _name: Option<String>,
        _caps: Option<&gst::CapsRef>,
    ) -> Option<gst::Pad> {
        None
    }

    fn release_pad(&self, _element: &T, _pad: &gst::Pad) {}

    fn send_event(&self, element: &T, event: gst::Event) -> bool {
        element.parent_send_event(event)
    }

    fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
        element.parent_query(query)
    }

    fn set_context(&self, element: &T, context: &gst::Context) {
        element.parent_set_context(context)
    }
}

any_impl!(ElementBase, ElementImpl);

pub unsafe trait ElementBase: IsA<gst::Element> + ObjectType {
    fn parent_change_state(&self, transition: gst::StateChange) -> gst::StateChangeReturn {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .change_state
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, transition.to_glib()))
                })
                .unwrap_or(gst::StateChangeReturn::Success)
        }
    }

    fn parent_send_event(&self, event: gst::Event) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .send_event
                .map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .query
                .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_set_context(&self, context: &gst::Context) {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .set_context
                .map(|f| f(self.to_glib_none().0, context.to_glib_none().0))
                .unwrap_or(())
        }
    }
}

pub unsafe trait ElementClassExt<T: ElementBase>
where
    T::ImplType: ElementImpl<T>,
{
    fn add_pad_template(&mut self, pad_template: gst::PadTemplate) {
        unsafe {
            gst_ffi::gst_element_class_add_pad_template(
                self as *const Self as *mut gst_ffi::GstElementClass,
                pad_template.to_glib_full(),
            );
        }
    }

    fn set_metadata(
        &mut self,
        long_name: &str,
        classification: &str,
        description: &str,
        author: &str,
    ) {
        unsafe {
            gst_ffi::gst_element_class_set_metadata(
                self as *const Self as *mut gst_ffi::GstElementClass,
                long_name.to_glib_none().0,
                classification.to_glib_none().0,
                description.to_glib_none().0,
                author.to_glib_none().0,
            );
        }
    }

    fn override_vfuncs(&mut self, _: &ClassInitToken) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gst_ffi::GstElementClass);
            klass.change_state = Some(element_change_state::<T>);
            klass.request_new_pad = Some(element_request_new_pad::<T>);
            klass.release_pad = Some(element_release_pad::<T>);
            klass.send_event = Some(element_send_event::<T>);
            klass.query = Some(element_query::<T>);
            klass.set_context = Some(element_set_context::<T>);
        }
    }
}

glib_wrapper! {
    pub struct Element(Object<InstanceStruct<Element>>): [gst::Element => gst_ffi::GstElement,
                                                          gst::Object => gst_ffi::GstObject];

    match fn {
        get_type => || get_type::<Element>(),
    }
}

unsafe impl<T: IsA<gst::Element> + ObjectType> ElementBase for T {}
pub type ElementClass = ClassStruct<Element>;

// FIXME: Boilerplate
unsafe impl ElementClassExt<Element> for ElementClass {}

#[macro_export]
macro_rules! box_element_impl(
    ($name:ident) => {
        box_object_impl!($name);

        impl<T: ElementBase> ElementImpl<T> for Box<$name<T>> {
            fn change_state(
                &self,
                element: &T,
                transition: gst::StateChange,
            ) -> gst::StateChangeReturn {
                let imp: &$name<T> = self.as_ref();
                imp.change_state(element, transition)
            }

            fn request_new_pad(&self, element: &T, templ: &gst::PadTemplate, name: Option<String>, caps: Option<&gst::CapsRef>) -> Option<gst::Pad> {
                let imp: &$name<T> = self.as_ref();
                imp.request_new_pad(element, templ, name, caps)
            }

            fn release_pad(&self, element: &T, pad: &gst::Pad) {
                let imp: &$name<T> = self.as_ref();
                imp.release_pad(element, pad)
            }

            fn send_event(&self, element: &T, event: gst::Event) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.send_event(element, event)
            }

            fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                ElementImpl::query(imp, element, query)
            }

            fn set_context(&self, element: &T, context: &gst::Context) {
                let imp: &$name<T> = self.as_ref();
                imp.set_context(element, context)
            }
        }
    };
);

box_element_impl!(ElementImpl);

impl ObjectType for Element {
    const NAME: &'static str = "RsElement";
    type GlibType = gst_ffi::GstElement;
    type GlibClassType = gst_ffi::GstElementClass;
    type ImplType = Box<ElementImpl<Self>>;

    fn glib_type() -> glib::Type {
        unsafe { from_glib(gst_ffi::gst_element_get_type()) }
    }

    fn class_init(token: &ClassInitToken, klass: &mut ElementClass) {
        klass.override_vfuncs(token);
    }

    object_type_fns!();
}

unsafe extern "C" fn element_change_state<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    transition: gst_ffi::GstStateChange,
) -> gst_ffi::GstStateChangeReturn
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, gst::StateChangeReturn::Failure, {
        imp.change_state(&wrap, from_glib(transition))
    }).to_glib()
}

unsafe extern "C" fn element_request_new_pad<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    templ: *mut gst_ffi::GstPadTemplate,
    name: *const libc::c_char,
    caps: *const gst_ffi::GstCaps,
) -> *mut gst_ffi::GstPad
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let caps = if caps.is_null() {
        None
    } else {
        Some(gst::CapsRef::from_ptr(caps))
    };

    panic_to_error!(&wrap, &element.panicked, None, {
        imp.request_new_pad(&wrap, &from_glib_borrow(templ), from_glib_none(name), caps)
    }).to_glib_full()
}

unsafe extern "C" fn element_release_pad<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    pad: *mut gst_ffi::GstPad,
) where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, (), {
        imp.release_pad(&wrap, &from_glib_borrow(pad))
    })
}

unsafe extern "C" fn element_send_event<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    event: *mut gst_ffi::GstEvent,
) -> glib_ffi::gboolean
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.send_event(&wrap, from_glib_full(event))
    }).to_glib()
}

unsafe extern "C" fn element_query<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    query: *mut gst_ffi::GstQuery,
) -> glib_ffi::gboolean
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let query = gst::QueryRef::from_mut_ptr(query);

    panic_to_error!(&wrap, &element.panicked, false, { imp.query(&wrap, query) }).to_glib()
}

unsafe extern "C" fn element_set_context<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    context: *mut gst_ffi::GstContext,
) where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, (), {
        imp.set_context(&wrap, &from_glib_borrow(context))
    })
}
<commit_msg>Element::request_new_pad() is (transfer none) in the return value<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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 std::ptr;
use std::mem;

use libc;

use glib_ffi;
use gobject_ffi;
use gst_ffi;

use glib;
use glib::translate::*;
use gst;
use gst::prelude::*;

use object::*;
use anyimpl::*;

pub trait ElementImpl<T: ElementBase>
    : ObjectImpl<T> + AnyImpl + Send + Sync + 'static {
    fn change_state(&self, element: &T, transition: gst::StateChange) -> gst::StateChangeReturn {
        element.parent_change_state(transition)
    }

    fn request_new_pad(
        &self,
        _element: &T,
        _templ: &gst::PadTemplate,
        _name: Option<String>,
        _caps: Option<&gst::CapsRef>,
    ) -> Option<gst::Pad> {
        None
    }

    fn release_pad(&self, _element: &T, _pad: &gst::Pad) {}

    fn send_event(&self, element: &T, event: gst::Event) -> bool {
        element.parent_send_event(event)
    }

    fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
        element.parent_query(query)
    }

    fn set_context(&self, element: &T, context: &gst::Context) {
        element.parent_set_context(context)
    }
}

any_impl!(ElementBase, ElementImpl);

pub unsafe trait ElementBase: IsA<gst::Element> + ObjectType {
    fn parent_change_state(&self, transition: gst::StateChange) -> gst::StateChangeReturn {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .change_state
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, transition.to_glib()))
                })
                .unwrap_or(gst::StateChangeReturn::Success)
        }
    }

    fn parent_send_event(&self, event: gst::Event) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .send_event
                .map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .query
                .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_set_context(&self, context: &gst::Context) {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
            (*parent_klass)
                .set_context
                .map(|f| f(self.to_glib_none().0, context.to_glib_none().0))
                .unwrap_or(())
        }
    }
}

pub unsafe trait ElementClassExt<T: ElementBase>
where
    T::ImplType: ElementImpl<T>,
{
    fn add_pad_template(&mut self, pad_template: gst::PadTemplate) {
        unsafe {
            gst_ffi::gst_element_class_add_pad_template(
                self as *const Self as *mut gst_ffi::GstElementClass,
                pad_template.to_glib_full(),
            );
        }
    }

    fn set_metadata(
        &mut self,
        long_name: &str,
        classification: &str,
        description: &str,
        author: &str,
    ) {
        unsafe {
            gst_ffi::gst_element_class_set_metadata(
                self as *const Self as *mut gst_ffi::GstElementClass,
                long_name.to_glib_none().0,
                classification.to_glib_none().0,
                description.to_glib_none().0,
                author.to_glib_none().0,
            );
        }
    }

    fn override_vfuncs(&mut self, _: &ClassInitToken) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gst_ffi::GstElementClass);
            klass.change_state = Some(element_change_state::<T>);
            klass.request_new_pad = Some(element_request_new_pad::<T>);
            klass.release_pad = Some(element_release_pad::<T>);
            klass.send_event = Some(element_send_event::<T>);
            klass.query = Some(element_query::<T>);
            klass.set_context = Some(element_set_context::<T>);
        }
    }
}

glib_wrapper! {
    pub struct Element(Object<InstanceStruct<Element>>): [gst::Element => gst_ffi::GstElement,
                                                          gst::Object => gst_ffi::GstObject];

    match fn {
        get_type => || get_type::<Element>(),
    }
}

unsafe impl<T: IsA<gst::Element> + ObjectType> ElementBase for T {}
pub type ElementClass = ClassStruct<Element>;

// FIXME: Boilerplate
unsafe impl ElementClassExt<Element> for ElementClass {}

#[macro_export]
macro_rules! box_element_impl(
    ($name:ident) => {
        box_object_impl!($name);

        impl<T: ElementBase> ElementImpl<T> for Box<$name<T>> {
            fn change_state(
                &self,
                element: &T,
                transition: gst::StateChange,
            ) -> gst::StateChangeReturn {
                let imp: &$name<T> = self.as_ref();
                imp.change_state(element, transition)
            }

            fn request_new_pad(&self, element: &T, templ: &gst::PadTemplate, name: Option<String>, caps: Option<&gst::CapsRef>) -> Option<gst::Pad> {
                let imp: &$name<T> = self.as_ref();
                imp.request_new_pad(element, templ, name, caps)
            }

            fn release_pad(&self, element: &T, pad: &gst::Pad) {
                let imp: &$name<T> = self.as_ref();
                imp.release_pad(element, pad)
            }

            fn send_event(&self, element: &T, event: gst::Event) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.send_event(element, event)
            }

            fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                ElementImpl::query(imp, element, query)
            }

            fn set_context(&self, element: &T, context: &gst::Context) {
                let imp: &$name<T> = self.as_ref();
                imp.set_context(element, context)
            }
        }
    };
);

box_element_impl!(ElementImpl);

impl ObjectType for Element {
    const NAME: &'static str = "RsElement";
    type GlibType = gst_ffi::GstElement;
    type GlibClassType = gst_ffi::GstElementClass;
    type ImplType = Box<ElementImpl<Self>>;

    fn glib_type() -> glib::Type {
        unsafe { from_glib(gst_ffi::gst_element_get_type()) }
    }

    fn class_init(token: &ClassInitToken, klass: &mut ElementClass) {
        klass.override_vfuncs(token);
    }

    object_type_fns!();
}

unsafe extern "C" fn element_change_state<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    transition: gst_ffi::GstStateChange,
) -> gst_ffi::GstStateChangeReturn
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, gst::StateChangeReturn::Failure, {
        imp.change_state(&wrap, from_glib(transition))
    }).to_glib()
}

unsafe extern "C" fn element_request_new_pad<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    templ: *mut gst_ffi::GstPadTemplate,
    name: *const libc::c_char,
    caps: *const gst_ffi::GstCaps,
) -> *mut gst_ffi::GstPad
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let caps = if caps.is_null() {
        None
    } else {
        Some(gst::CapsRef::from_ptr(caps))
    };

    // XXX: This is effectively unsafe but the best we can do
    // See https://bugzilla.gnome.org/show_bug.cgi?id=791193
    let pad = panic_to_error!(&wrap, &element.panicked, None, {
        imp.request_new_pad(&wrap, &from_glib_borrow(templ), from_glib_none(name), caps)
    });

    // Ensure that the pad is owned by the element now, if a pad was returned
    if let Some(ref pad) = pad {
        assert_eq!(
            pad.get_parent(),
            Some(gst::Object::from_glib_borrow(
                ptr as *mut gst_ffi::GstObject
            ))
        );
    }

    pad.to_glib_none().0
}

unsafe extern "C" fn element_release_pad<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    pad: *mut gst_ffi::GstPad,
) where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, (), {
        imp.release_pad(&wrap, &from_glib_borrow(pad))
    })
}

unsafe extern "C" fn element_send_event<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    event: *mut gst_ffi::GstEvent,
) -> glib_ffi::gboolean
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.send_event(&wrap, from_glib_full(event))
    }).to_glib()
}

unsafe extern "C" fn element_query<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    query: *mut gst_ffi::GstQuery,
) -> glib_ffi::gboolean
where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let query = gst::QueryRef::from_mut_ptr(query);

    panic_to_error!(&wrap, &element.panicked, false, { imp.query(&wrap, query) }).to_glib()
}

unsafe extern "C" fn element_set_context<T: ElementBase>(
    ptr: *mut gst_ffi::GstElement,
    context: *mut gst_ffi::GstContext,
) where
    T::ImplType: ElementImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, (), {
        imp.set_context(&wrap, &from_glib_borrow(context))
    })
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use anyhow::Result;
use log::debug;

#[cfg(feature = "disassembler")]
use crate::analysis::dis;
use crate::{
    aspace::AddressSpace,
    loader::pe::{
        imports,
        imports::{read_best_thunk_data, IMAGE_THUNK_DATA},
        PE,
    },
    util, RVA, VA,
};
#[cfg(feature = "disassembler")]
use std::collections::HashSet;

#[cfg(feature = "disassembler")]
pub mod call_targets;
pub mod control_flow_guard;
pub mod entrypoints;
pub mod exports;
pub mod patterns;
pub mod pointers;
pub mod runtime_functions;
pub mod safeseh;

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum ImportedSymbol {
    Ordinal(u32),
    Name(smol_str::SmolStr),
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Import {
    /// the address of the First Thunk.
    /// that is, the thing that will be referenced by code.
    pub address: VA,
    pub dll:     smol_str::SmolStr,
    pub symbol:  ImportedSymbol,
}

impl std::fmt::Display for Import {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.symbol {
            ImportedSymbol::Ordinal(ord) => write!(f, "{}!#{}", self.dll, ord),
            ImportedSymbol::Name(name) => write!(f, "{}!{}", self.dll, name),
        }
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Thunk {
    /// the address of the function thunk
    pub address: VA,
    pub import:  Import,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Function {
    Local(VA),
    Thunk(Thunk),
    Import(Import),
}

pub fn get_imports(pe: &PE) -> Result<BTreeMap<VA, Import>> {
    let mut imports: BTreeMap<VA, Import> = Default::default();

    if let Some(import_directory) = imports::get_import_directory(pe)? {
        let base_address = pe.module.address_space.base_address;
        let psize = pe.module.arch.pointer_size();

        for import_descriptor in imports::read_import_descriptors(pe, import_directory) {
            let dll = smol_str::SmolStr::new(pe.module.address_space.relative.read_ascii(import_descriptor.name, 1)?);
            debug!("imports: {}", dll);

            for i in 0.. {
                let oft = base_address + import_descriptor.original_first_thunk + (i * psize) as RVA;
                let ft = base_address + import_descriptor.first_thunk + (i * psize) as RVA;

                if pe.module.read_rva_at_va(ft)? == 0x0 {
                    break;
                }

                let symbol = match read_best_thunk_data(pe, oft, ft)? {
                    IMAGE_THUNK_DATA::Function(name_rva) => {
                        // u16    hint
                        // asciiz name
                        let name = pe.module.address_space.relative.read_ascii(name_rva + 2, 1)?;
                        debug!("imports: {}!{}", dll, name);
                        ImportedSymbol::Name(smol_str::SmolStr::new(name))
                    }
                    IMAGE_THUNK_DATA::Ordinal(ord) => {
                        debug!("imports: {}!#{}", dll, ord);
                        ImportedSymbol::Ordinal(ord)
                    }
                };

                imports.insert(
                    ft,
                    Import {
                        address: ft,
                        dll: dll.clone(),
                        symbol,
                    },
                );
            }
        }
    }

    Ok(imports)
}

#[cfg(feature = "disassembler")]
pub fn find_thunks(pe: &PE, imports: &BTreeMap<VA, Import>, functions: &HashSet<VA>) -> Result<BTreeMap<VA, Thunk>> {
    let mut thunks: BTreeMap<VA, Thunk> = Default::default();
    let decoder = dis::get_disassembler(&pe.module)?;

    for &function in functions.iter() {
        if let Ok(insn_buf) = pe.module.address_space.read_bytes(function, 0x10) {
            if let Ok(Some(insn)) = decoder.decode(&insn_buf) {
                if insn.mnemonic != zydis::Mnemonic::JMP {
                    continue;
                }

                let op = dis::get_first_operand(&insn).expect("JMP has no target");

                if let zydis::OperandType::MEMORY = op.ty {
                    // 32-bit
                    if op.mem.base == zydis::Register::NONE
                        && op.mem.index == zydis::Register::NONE
                        && op.mem.scale == 0
                        && op.mem.disp.has_displacement
                    {
                        // the operand is a deref of a memory address.
                        // for example: JMP [0x0]
                        // this means: read the ptr from 0x0, and then jump to it.

                        if op.mem.disp.displacement < 0 {
                            continue;
                        }
                        let ptr: VA = op.mem.disp.displacement as u64;

                        if let Some(import) = imports.get(&ptr) {
                            let thunk = Thunk {
                                address: function,
                                import:  import.clone(),
                            };
                            debug!("thunk: {:#x} -> {}", thunk.address, thunk.import);
                            thunks.insert(thunk.address, thunk);
                        }
                    } else if op.mem.base == zydis::Register::RIP
                            // only valid on x64
                            && op.mem.index == zydis::Register::NONE
                            && op.mem.scale == 0
                            && op.mem.disp.has_displacement
                    {
                        // this is RIP-relative addressing.
                        // it works like a relative immediate,
                        // that is: dst = *(rva + displacement + instruction len)

                        let ptr =
                            match util::va_add_signed(function + insn.length as u64, op.mem.disp.displacement as i64) {
                                None => continue,
                                Some(ptr) => ptr,
                            };

                        if let Some(import) = imports.get(&ptr) {
                            let thunk = Thunk {
                                address: function,
                                import:  import.clone(),
                            };
                            debug!("thunk: {:#x} -> {}", thunk.address, thunk.import);
                            thunks.insert(thunk.address, thunk);
                        }
                    }
                }
            }
        }
    }

    Ok(thunks)
}

#[cfg(feature = "disassembler")]
pub fn find_functions(pe: &PE) -> Result<Vec<Function>> {
    let imports = get_imports(pe)?;
    debug!("imports: found {} imports", imports.len());

    let mut function_starts: HashSet<VA> = Default::default();
    function_starts.extend(crate::analysis::pe::entrypoints::find_pe_entrypoint(pe)?);
    function_starts.extend(crate::analysis::pe::exports::find_pe_exports(pe)?);
    function_starts.extend(crate::analysis::pe::safeseh::find_pe_safeseh_handlers(pe)?);
    function_starts.extend(crate::analysis::pe::runtime_functions::find_pe_runtime_functions(pe)?);
    function_starts.extend(crate::analysis::pe::control_flow_guard::find_pe_cfguard_functions(pe)?);
    function_starts.extend(crate::analysis::pe::call_targets::find_pe_call_targets(pe)?);
    function_starts.extend(crate::analysis::pe::patterns::find_function_prologues(pe)?);
    function_starts.extend(crate::analysis::pe::pointers::find_pe_nonrelocated_executable_pointers(
        pe,
    )?);

    // TODO: validate that the code looks ok

    let thunks = find_thunks(pe, &imports, &function_starts)?;
    debug!("functions: found {} function candidates", function_starts.len());
    debug!("functions: found {} thunks", thunks.len());

    let function_starts: Vec<_> = function_starts
        .difference(&thunks.keys().cloned().collect())
        .cloned()
        .collect();
    debug!("functions: found {} functions", function_starts.len());

    let mut functions: Vec<Function> = Default::default();
    functions.extend(function_starts.iter().map(|&f| Function::Local(f)));
    functions.extend(thunks.values().cloned().map(Function::Thunk));
    functions.extend(imports.values().cloned().map(Function::Import));
    functions.sort_unstable();

    Ok(functions)
}

#[cfg(feature = "disassembler")]
pub fn find_function_starts(pe: &PE) -> Result<Vec<VA>> {
    Ok(find_functions(pe)?
        .into_iter()
        .filter(|f| matches!(f, Function::Local(_)))
        .map(|f| match f {
            Function::Local(va) => va,
            _ => unreachable!(),
        })
        .collect())
}
<commit_msg>pe: analysis: disable pointer hunting<commit_after>use std::collections::BTreeMap;

use anyhow::Result;
use log::debug;

#[cfg(feature = "disassembler")]
use crate::analysis::dis;
use crate::{
    aspace::AddressSpace,
    loader::pe::{
        imports,
        imports::{read_best_thunk_data, IMAGE_THUNK_DATA},
        PE,
    },
    util, RVA, VA,
};
#[cfg(feature = "disassembler")]
use std::collections::HashSet;

#[cfg(feature = "disassembler")]
pub mod call_targets;
pub mod control_flow_guard;
pub mod entrypoints;
pub mod exports;
pub mod patterns;
pub mod pointers;
pub mod runtime_functions;
pub mod safeseh;

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum ImportedSymbol {
    Ordinal(u32),
    Name(smol_str::SmolStr),
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Import {
    /// the address of the First Thunk.
    /// that is, the thing that will be referenced by code.
    pub address: VA,
    pub dll:     smol_str::SmolStr,
    pub symbol:  ImportedSymbol,
}

impl std::fmt::Display for Import {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.symbol {
            ImportedSymbol::Ordinal(ord) => write!(f, "{}!#{}", self.dll, ord),
            ImportedSymbol::Name(name) => write!(f, "{}!{}", self.dll, name),
        }
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Thunk {
    /// the address of the function thunk
    pub address: VA,
    pub import:  Import,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Function {
    Local(VA),
    Thunk(Thunk),
    Import(Import),
}

pub fn get_imports(pe: &PE) -> Result<BTreeMap<VA, Import>> {
    let mut imports: BTreeMap<VA, Import> = Default::default();

    if let Some(import_directory) = imports::get_import_directory(pe)? {
        let base_address = pe.module.address_space.base_address;
        let psize = pe.module.arch.pointer_size();

        for import_descriptor in imports::read_import_descriptors(pe, import_directory) {
            let dll = smol_str::SmolStr::new(pe.module.address_space.relative.read_ascii(import_descriptor.name, 1)?);
            debug!("imports: {}", dll);

            for i in 0.. {
                let oft = base_address + import_descriptor.original_first_thunk + (i * psize) as RVA;
                let ft = base_address + import_descriptor.first_thunk + (i * psize) as RVA;

                if pe.module.read_rva_at_va(ft)? == 0x0 {
                    break;
                }

                let symbol = match read_best_thunk_data(pe, oft, ft)? {
                    IMAGE_THUNK_DATA::Function(name_rva) => {
                        // u16    hint
                        // asciiz name
                        let name = pe.module.address_space.relative.read_ascii(name_rva + 2, 1)?;
                        debug!("imports: {}!{}", dll, name);
                        ImportedSymbol::Name(smol_str::SmolStr::new(name))
                    }
                    IMAGE_THUNK_DATA::Ordinal(ord) => {
                        debug!("imports: {}!#{}", dll, ord);
                        ImportedSymbol::Ordinal(ord)
                    }
                };

                imports.insert(
                    ft,
                    Import {
                        address: ft,
                        dll: dll.clone(),
                        symbol,
                    },
                );
            }
        }
    }

    Ok(imports)
}

#[cfg(feature = "disassembler")]
pub fn find_thunks(pe: &PE, imports: &BTreeMap<VA, Import>, functions: &HashSet<VA>) -> Result<BTreeMap<VA, Thunk>> {
    let mut thunks: BTreeMap<VA, Thunk> = Default::default();
    let decoder = dis::get_disassembler(&pe.module)?;

    for &function in functions.iter() {
        if let Ok(insn_buf) = pe.module.address_space.read_bytes(function, 0x10) {
            if let Ok(Some(insn)) = decoder.decode(&insn_buf) {
                if insn.mnemonic != zydis::Mnemonic::JMP {
                    continue;
                }

                let op = dis::get_first_operand(&insn).expect("JMP has no target");

                if let zydis::OperandType::MEMORY = op.ty {
                    // 32-bit
                    if op.mem.base == zydis::Register::NONE
                        && op.mem.index == zydis::Register::NONE
                        && op.mem.scale == 0
                        && op.mem.disp.has_displacement
                    {
                        // the operand is a deref of a memory address.
                        // for example: JMP [0x0]
                        // this means: read the ptr from 0x0, and then jump to it.

                        if op.mem.disp.displacement < 0 {
                            continue;
                        }
                        let ptr: VA = op.mem.disp.displacement as u64;

                        if let Some(import) = imports.get(&ptr) {
                            let thunk = Thunk {
                                address: function,
                                import:  import.clone(),
                            };
                            debug!("thunk: {:#x} -> {}", thunk.address, thunk.import);
                            thunks.insert(thunk.address, thunk);
                        }
                    } else if op.mem.base == zydis::Register::RIP
                            // only valid on x64
                            && op.mem.index == zydis::Register::NONE
                            && op.mem.scale == 0
                            && op.mem.disp.has_displacement
                    {
                        // this is RIP-relative addressing.
                        // it works like a relative immediate,
                        // that is: dst = *(rva + displacement + instruction len)

                        let ptr =
                            match util::va_add_signed(function + insn.length as u64, op.mem.disp.displacement as i64) {
                                None => continue,
                                Some(ptr) => ptr,
                            };

                        if let Some(import) = imports.get(&ptr) {
                            let thunk = Thunk {
                                address: function,
                                import:  import.clone(),
                            };
                            debug!("thunk: {:#x} -> {}", thunk.address, thunk.import);
                            thunks.insert(thunk.address, thunk);
                        }
                    }
                }
            }
        }
    }

    Ok(thunks)
}

#[cfg(feature = "disassembler")]
pub fn find_functions(pe: &PE) -> Result<Vec<Function>> {
    let imports = get_imports(pe)?;
    debug!("imports: found {} imports", imports.len());

    let mut function_starts: HashSet<VA> = Default::default();
    function_starts.extend(crate::analysis::pe::entrypoints::find_pe_entrypoint(pe)?);
    function_starts.extend(crate::analysis::pe::exports::find_pe_exports(pe)?);
    function_starts.extend(crate::analysis::pe::safeseh::find_pe_safeseh_handlers(pe)?);
    function_starts.extend(crate::analysis::pe::runtime_functions::find_pe_runtime_functions(pe)?);
    function_starts.extend(crate::analysis::pe::control_flow_guard::find_pe_cfguard_functions(pe)?);
    function_starts.extend(crate::analysis::pe::call_targets::find_pe_call_targets(pe)?);
    function_starts.extend(crate::analysis::pe::patterns::find_function_prologues(pe)?);
    /*
    function_starts.extend(crate::analysis::pe::pointers::find_pe_nonrelocated_executable_pointers(
        pe,
    )?);
    */

    // TODO: validate that the code looks ok

    let thunks = find_thunks(pe, &imports, &function_starts)?;
    debug!("functions: found {} function candidates", function_starts.len());
    debug!("functions: found {} thunks", thunks.len());

    let function_starts: Vec<_> = function_starts
        .difference(&thunks.keys().cloned().collect())
        .cloned()
        .collect();
    debug!("functions: found {} functions", function_starts.len());

    let mut functions: Vec<Function> = Default::default();
    functions.extend(function_starts.iter().map(|&f| Function::Local(f)));
    functions.extend(thunks.values().cloned().map(Function::Thunk));
    functions.extend(imports.values().cloned().map(Function::Import));
    functions.sort_unstable();

    Ok(functions)
}

#[cfg(feature = "disassembler")]
pub fn find_function_starts(pe: &PE) -> Result<Vec<VA>> {
    Ok(find_functions(pe)?
        .into_iter()
        .filter(|f| matches!(f, Function::Local(_)))
        .map(|f| match f {
            Function::Local(va) => va,
            _ => unreachable!(),
        })
        .collect())
}
<|endoftext|>


<commit_before>// pub fn find_kth_number(n: i32, k: i32) -> i32 {
//     let mut count = k;
//     for l in 1.. {
//         count -= 1;
//         if count == 0 {
//             return l;
//         }

//         let result = inner_rec(l, n, &mut count);
//         if result != 0 {
//             return result;
//         };
//     }
//     0
// }

// fn inner_rec(head: i32, k: i32, count: &mut i32) -> i32 {
//     if head * 10 < n {
//         0
//     }
//     0
// }

pub fn find_kth_number(n: i32, k: i32) -> i32 {
    let mut count = k;
    return test_inner_rec(1 as u64, &(n as u64), &mut count);
}

fn test_inner_rec(head: u64, n: &u64, count: &mut i32) -> i32 {
    if head > *n {
        return 0;
    }
    //print!("{:?} ", head);
    *count -= 1;

    if *count == 0 {
        return head as i32;
    }

    let re = test_inner_rec(head * 10, n, count);
    if re != 0 {
        return re;
    } else {
        if head % 10 == 9 {
            return 0;
        }
        return test_inner_rec(head + 1, n, count);
    }
}

fn main() {
    let testcase0 = 13;
    let k = 2;
    //dbg!(test_inner_rec(1, &testcase0, &mut k));
    //dbg!(find_kth_number(testcase0, k)); // => 10

    let testcase1 = 100;
    let k = 90;
    //dbg!(find_kth_number(testcase1, k)); // => 9

    let testcase1 = 681692778;
    let k = 351251360;
    //dbg!(find_kth_number(testcase1, k)); // => 416126219

    let testcase1 = 957747794;
    let k = 424238336;
    dbg!(find_kth_number(testcase1, k)); // => 416126219
}
<commit_msg>optimise failed, copy other guys solution<commit_after>pub fn find_kth_number_old(n: i32, k: i32) -> i32 {
    let mut count = k as u64;
    return test_inner_rec(1 as u64, &(n as u64), &mut count) as i32;
}

// this version not fast enough, but it works.
fn test_inner_rec(head: u64, n: &u64, count: &mut u64) -> u64 {
    if head > *n {
        return 0;
    }

    //print!("{:?} ", head);
    *count -= 1;

    if *count == 0 {
        return head;
    }

    let re = test_inner_rec(head * 10, n, count);
    if re != 0 {
        return re;
    } else {
        if head % 10 == 9 {
            return 0;
        }
        return test_inner_rec(head + 1, n, count);
    }
}

///////////////////////////////////////

pub fn find_kth_number(n: i32, k: i32) -> i32 {
    let mut curr = 1;

    let mut kk = (k - 1) as u64;
    while kk > 0 {
        let steps = cal_steps(n, curr, curr + 1);
        //println!("{}", steps);
        if steps <= kk {
            curr += 1;
            kk -= steps;
        } else {
            curr *= 10;
            kk -= 1;
        }
    }

    return curr as i32;
}

fn cal_steps(n: i32, n1: u64, n2: u64) -> u64 {
    use std::cmp;

    let mut steps = 0;
    let nn = n as u64;
    let (mut n11, mut n22) = (n1, n2);
    while n11 <= nn {
        steps += cmp::min(nn + 1, n22) - n11;
        n11 *= 10;
        n22 *= 10;
    }
    return steps;
}

fn main() {
    let testcase0 = 13;
    let k = 2;
    //dbg!(find_kth_number(testcase0, k)); // => 10

    let testcase1 = 100;
    let k = 90;
    //dbg!(find_kth_number(testcase1, k)); // => 9

    let testcase1 = 681692778;
    let k = 351251360;
    dbg!(find_kth_number(testcase1, k)); // => 416126219

    let testcase1 = 957747794;
    let k = 424238336;
    dbg!(find_kth_number(testcase1, k)); // => 481814499

    let testcase2 = 10000;
    let mut k = 10000;
    dbg!(find_kth_number(testcase2, k)); // => 9999
}
<|endoftext|>


<commit_before>//! Input for the parser -- a sequence of tokens.
//!
//! As of now, parser doesn't have access to the *text* of the tokens, and makes
//! decisions based solely on their classification.

use crate::SyntaxKind;

#[allow(non_camel_case_types)]
type bits = u64;

/// Main input to the parser.
///
/// A sequence of tokens represented internally as a struct of arrays.
#[derive(Default)]
pub struct Tokens {
    kind: Vec<SyntaxKind>,
    joint: Vec<bits>,
    contextual_kind: Vec<SyntaxKind>,
}

impl Tokens {
    #[inline]
    pub fn push(&mut self, kind: SyntaxKind) {
        self.push_impl(kind, SyntaxKind::EOF)
    }
    /// Sets jointness for the last token we've pushed.
    ///
    /// This is a separate API rather than an argument to the `push` to make it
    /// convenient both for textual and mbe tokens. With text, you know whether
    /// the *previous* token was joint, with mbe, you know whether the *current*
    /// one is joint. This API allows for styles of usage:
    ///
    /// ```
    /// // In text:
    /// tokens.was_joint(prev_joint);
    /// tokens.push(curr);
    ///
    /// // In MBE:
    /// token.push(curr);
    /// tokens.push(curr_joint)
    /// ```
    #[inline]
    pub fn was_joint(&mut self) {
        self.set_joint(self.len() - 1);
    }
    #[inline]
    pub fn push_ident(&mut self, contextual_kind: SyntaxKind) {
        self.push_impl(SyntaxKind::IDENT, contextual_kind)
    }
    #[inline]
    fn push_impl(&mut self, kind: SyntaxKind, contextual_kind: SyntaxKind) {
        let idx = self.len();
        if idx % (bits::BITS as usize) == 0 {
            self.joint.push(0);
        }
        self.kind.push(kind);
        self.contextual_kind.push(contextual_kind);
    }
    fn set_joint(&mut self, n: usize) {
        let (idx, b_idx) = self.bit_index(n);
        self.joint[idx] |= 1 << b_idx;
    }
    fn bit_index(&self, n: usize) -> (usize, usize) {
        let idx = n / (bits::BITS as usize);
        let b_idx = n % (bits::BITS as usize);
        (idx, b_idx)
    }

    fn len(&self) -> usize {
        self.kind.len()
    }
}

/// pub(crate) impl used by the parser.
impl Tokens {
    pub(crate) fn kind(&self, idx: usize) -> SyntaxKind {
        self.kind.get(idx).copied().unwrap_or(SyntaxKind::EOF)
    }
    pub(crate) fn contextual_kind(&self, idx: usize) -> SyntaxKind {
        self.contextual_kind.get(idx).copied().unwrap_or(SyntaxKind::EOF)
    }
    pub(crate) fn is_joint(&self, n: usize) -> bool {
        let (idx, b_idx) = self.bit_index(n);
        self.joint[idx] & 1 << b_idx != 0
    }
}
<commit_msg>prettyfy<commit_after>//! Input for the parser -- a sequence of tokens.
//!
//! As of now, parser doesn't have access to the *text* of the tokens, and makes
//! decisions based solely on their classification.

use crate::SyntaxKind;

#[allow(non_camel_case_types)]
type bits = u64;

/// Main input to the parser.
///
/// A sequence of tokens represented internally as a struct of arrays.
#[derive(Default)]
pub struct Tokens {
    kind: Vec<SyntaxKind>,
    joint: Vec<bits>,
    contextual_kind: Vec<SyntaxKind>,
}

/// `pub` impl used by callers to create `Tokens`.
impl Tokens {
    #[inline]
    pub fn push(&mut self, kind: SyntaxKind) {
        self.push_impl(kind, SyntaxKind::EOF)
    }
    #[inline]
    pub fn push_ident(&mut self, contextual_kind: SyntaxKind) {
        self.push_impl(SyntaxKind::IDENT, contextual_kind)
    }
    /// Sets jointness for the last token we've pushed.
    ///
    /// This is a separate API rather than an argument to the `push` to make it
    /// convenient both for textual and mbe tokens. With text, you know whether
    /// the *previous* token was joint, with mbe, you know whether the *current*
    /// one is joint. This API allows for styles of usage:
    ///
    /// ```
    /// // In text:
    /// tokens.was_joint(prev_joint);
    /// tokens.push(curr);
    ///
    /// // In MBE:
    /// token.push(curr);
    /// tokens.push(curr_joint)
    /// ```
    #[inline]
    pub fn was_joint(&mut self) {
        let n = self.len() - 1;
        let (idx, b_idx) = self.bit_index(n);
        self.joint[idx] |= 1 << b_idx;
    }
    #[inline]
    fn push_impl(&mut self, kind: SyntaxKind, contextual_kind: SyntaxKind) {
        let idx = self.len();
        if idx % (bits::BITS as usize) == 0 {
            self.joint.push(0);
        }
        self.kind.push(kind);
        self.contextual_kind.push(contextual_kind);
    }
}

/// pub(crate) impl used by the parser to consume `Tokens`.
impl Tokens {
    pub(crate) fn kind(&self, idx: usize) -> SyntaxKind {
        self.kind.get(idx).copied().unwrap_or(SyntaxKind::EOF)
    }
    pub(crate) fn contextual_kind(&self, idx: usize) -> SyntaxKind {
        self.contextual_kind.get(idx).copied().unwrap_or(SyntaxKind::EOF)
    }
    pub(crate) fn is_joint(&self, n: usize) -> bool {
        let (idx, b_idx) = self.bit_index(n);
        self.joint[idx] & 1 << b_idx != 0
    }
}

impl Tokens {
    fn bit_index(&self, n: usize) -> (usize, usize) {
        let idx = n / (bits::BITS as usize);
        let b_idx = n % (bits::BITS as usize);
        (idx, b_idx)
    }
    fn len(&self) -> usize {
        self.kind.len()
    }
}
<|endoftext|>


<commit_before>use super::*;

// explicitly
use super::LogReader;

/// A pointer to a location on disk or an off-log blob.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum DiskPtr {
    /// Points to a value stored in the single-file log.
    Inline(LogId),
    /// Points to a value stored off-log in the blob directory.
    Blob(LogId, BlobPointer),
}

impl DiskPtr {
    pub(crate) fn new_inline(l: LogId) -> DiskPtr {
        DiskPtr::Inline(l)
    }

    pub(crate) fn new_blob(
        lid: LogId,
        ptr: BlobPointer,
    ) -> DiskPtr {
        DiskPtr::Blob(lid, ptr)
    }

    pub(crate) fn is_inline(&self) -> bool {
        match self {
            DiskPtr::Inline(_) => true,
            DiskPtr::Blob(_, _) => false,
        }
    }

    pub(crate) fn is_blob(&self) -> bool {
        match self {
            DiskPtr::Blob(_, _) => true,
            DiskPtr::Inline(_) => false,
        }
    }

    pub(crate) fn inline(&self) -> LogId {
        match self {
            DiskPtr::Inline(l) => *l,
            DiskPtr::Blob(_, _) => {
                panic!("inline called on Blob disk pointer")
            }
        }
    }

    pub(crate) fn blob(&self) -> (LogId, BlobPointer) {
        match self {
            DiskPtr::Blob(lid, ptr) => (*lid, *ptr),
            DiskPtr::Inline(_) => {
                panic!("blob called on Internal disk pointer")
            }
        }
    }

    #[doc(hidden)]
    pub fn lid(&self) -> LogId {
        match self {
            DiskPtr::Blob(lid, _) | DiskPtr::Inline(lid) => *lid,
        }
    }

    pub(crate) fn read(
        &self,
        config: &Config,
    ) -> Result<Vec<u8>, ()> {
        match self {
            DiskPtr::Blob(_lid, ptr) => read_blob(*ptr, &config),
            DiskPtr::Inline(lid) => {
                let mut f = config.file()?;

                f.read_message(*lid, &config).map(|log_read| {
                    log_read
                        .inline()
                        .expect(
                            "call to DiskPtr::read with \
                             an Inline pointer should result \
                             in a valid Inline read. It's \
                             possible the DiskPtr outlived \
                             an outer guard.",
                        ).1
                })
            }
        }
    }
}

impl std::fmt::Display for DiskPtr {
    fn fmt(
        &self,
        f: &mut std::fmt::Formatter<'_>,
    ) -> std::result::Result<(), std::fmt::Error> {
        write!(f, "{:?}", self)
    }
}
<commit_msg>Small cleanup of half-written comment<commit_after>use super::*;

// Explicitly use this so its use is tool-friendly.
use super::LogReader;

/// A pointer to a location on disk or an off-log blob.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum DiskPtr {
    /// Points to a value stored in the single-file log.
    Inline(LogId),
    /// Points to a value stored off-log in the blob directory.
    Blob(LogId, BlobPointer),
}

impl DiskPtr {
    pub(crate) fn new_inline(l: LogId) -> DiskPtr {
        DiskPtr::Inline(l)
    }

    pub(crate) fn new_blob(lid: LogId, ptr: BlobPointer) -> DiskPtr {
        DiskPtr::Blob(lid, ptr)
    }

    pub(crate) fn is_inline(&self) -> bool {
        match self {
            DiskPtr::Inline(_) => true,
            DiskPtr::Blob(_, _) => false,
        }
    }

    pub(crate) fn is_blob(&self) -> bool {
        match self {
            DiskPtr::Blob(_, _) => true,
            DiskPtr::Inline(_) => false,
        }
    }

    pub(crate) fn inline(&self) -> LogId {
        match self {
            DiskPtr::Inline(l) => *l,
            DiskPtr::Blob(_, _) => {
                panic!("inline called on Blob disk pointer")
            }
        }
    }

    pub(crate) fn blob(&self) -> (LogId, BlobPointer) {
        match self {
            DiskPtr::Blob(lid, ptr) => (*lid, *ptr),
            DiskPtr::Inline(_) => {
                panic!("blob called on Internal disk pointer")
            }
        }
    }

    #[doc(hidden)]
    pub fn lid(&self) -> LogId {
        match self {
            DiskPtr::Blob(lid, _) | DiskPtr::Inline(lid) => *lid,
        }
    }

    pub(crate) fn read(
        &self,
        config: &Config,
    ) -> Result<Vec<u8>, ()> {
        match self {
            DiskPtr::Blob(_lid, ptr) => read_blob(*ptr, &config),
            DiskPtr::Inline(lid) => {
                let mut f = config.file()?;

                f.read_message(*lid, &config).map(|log_read| {
                    log_read
                        .inline()
                        .expect(
                            "call to DiskPtr::read with \
                             an Inline pointer should result \
                             in a valid Inline read. It's \
                             possible the DiskPtr outlived \
                             an outer guard.",
                        ).1
                })
            }
        }
    }
}

impl std::fmt::Display for DiskPtr {
    fn fmt(
        &self,
        f: &mut std::fmt::Formatter<'_>,
    ) -> std::result::Result<(), std::fmt::Error> {
        write!(f, "{:?}", self)
    }
}
<|endoftext|>


<commit_before>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// 8, 7 and 6-M are supported via dedicated instructions like DMB. All other arches are supported
// via CP15 instructions. See Section 10.1 of ACLE
mod barrier;

pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// We also include the A profile even though DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // >= v5TE but excludes v7-M
        all(target_feature = "v5te", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
mod dsp;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v5te", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
pub use self::dsp::*;

// Supported arches: 6, 7-M. See Section 10.1 of ACLE (e.g. SSAT)
#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
mod sat;

#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
pub use self::sat::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // v7-A, v7-R
        all(target_feature = "v6", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
mod simd32;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v6", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<commit_msg>acle/dsp: note the difference between LLVM's +dsp and ACLE's __ARM_FEATURE_DSP<commit_after>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! *NOTE*: Section 5.4.7 of ACLE says:
//!
//! - "__ARM_FEATURE_DSP is defined to 1 if the DSP (v5E) instructions are supported and the
//! intrinsics defined in Saturating intrinsics are available."
//!
//! This does *not* match how LLVM uses the '+dsp' feature; this feature is not set for v5te
//! targets so we have to work around this difference.
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// 8, 7 and 6-M are supported via dedicated instructions like DMB. All other arches are supported
// via CP15 instructions. See Section 10.1 of ACLE
mod barrier;

pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// We also include the A profile even though DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
// Here we workaround the difference between LLVM's +dsp and ACLE's __ARM_FEATURE_DSP by gating on
// '+v5te' rather than on '+dsp'
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // >= v5TE but excludes v7-M
        all(target_feature = "v5te", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
mod dsp;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v5te", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
pub use self::dsp::*;

// Supported arches: 6, 7-M. See Section 10.1 of ACLE (e.g. SSAT)
#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
mod sat;

#[cfg(all(
    not(target_arch = "aarch64"),
    target_feature = "v6",
))]
pub use self::sat::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // v7-A, v7-R
        all(target_feature = "v6", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
mod simd32;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v6", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<|endoftext|>


<commit_before>use std::sync::{Mutex, Arc};
use std::result::Result;
use std::error::Error;

use serde_json::*;
use gossyp_base::*;
use gossyp_base::basic::*;

use super::binding_environment::*;
use super::script_interpreter::*;
use super::bind_statement::*;
use super::evaluate_statement::*;
use super::script::*;
use super::bound_script::*;

///
/// Represents a tool that can be used to evaluate scripts and maintains
/// state (useful for evaluation in a REPL environment)
///
#[derive(Clone)]
pub struct StatefulEvalTool {
    binding:    Arc<Mutex<Box<VariableBindingEnvironment>>>,
    execution:  Arc<Mutex<ScriptExecutionEnvironment>>
}

impl StatefulEvalTool {
    pub fn new() -> StatefulEvalTool {
        StatefulEvalTool {
            binding: Arc::new(Mutex::new(BindingEnvironment::new())),
            execution: Arc::new(Mutex::new(ScriptExecutionEnvironment::new()))
        }
    }

    ///
    /// Evaluates an unbound statement using this tool
    ///
    pub fn evaluate_unbound_statement(&self, script: &Script, environment: &Environment) -> Result<Value, Value> {
        self.evaluate_statement(&self.bind_statement(script, environment)?, environment)
    }

    ///
    /// Binds a statement to this tool
    ///
    pub fn bind_statement(&self, script: &Script, environment: &Environment) -> Result<BoundScript, Value> {
        // Merge the stuff in the external environment with the stored environment
        let our_environment             = &mut **self.binding.lock().unwrap();
        let their_environment           = BindingEnvironment::from_environment(environment);
        let mut combined_environment    = BindingEnvironment::combine(our_environment, &*their_environment);

        // Bind to the combined environments
        bind_statement(script, &mut *combined_environment)
    }

    ///
    /// Evaluates a statement in the environment represented by this tool
    ///
    pub fn evaluate_statement(&self, script: &BoundScript, environment: &Environment) -> Result<Value, Value> {
        evaluate_statement(script, environment, &mut *self.execution.lock().unwrap())
    }
}

impl Tool for StatefulEvalTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let script = from_value::<Script>(input);

        match script {
            Ok(script)          => self.evaluate_unbound_statement(&script, environment),
            Err(script_error)   => Err(json![{
                "error":        "JSON input decode failed",
                "description":  script_error.description(),
            }])
        }
    }
}

///
/// Tool function that creates an eval state in an environment
///
pub fn create_evaluator_with_state_tool(eval_name: String, environment: &Environment) -> Result<(), Value> {
    // Fetch the tool defining tool
    let define_tool = environment.get_json_tool(tool_name::DEFINE_TOOL)
        .map(|tool| TypedTool::from(tool))
        .map_err(|retrieve_error| json![{
            "error":        "Cannot define tool",
            "description":  retrieve_error.message()
        }])?;

    // Define an environment containing the stateful tool
    let stateful_env = StaticEnvironment::from_tool("stateful-eval", StatefulEvalTool::new(), &EmptyEnvironment::new());

    // Copy the stateful eval tool to the new environment
    let _define_result: () = define_tool.invoke(DefineToolInput::new(&eval_name, Some("stateful-eval")), &stateful_env)?;

    Ok(())
}

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

    #[test]
    fn can_bind_variable_using_stateful_tool() {
        let eval    = StatefulEvalTool::new();
        let env     = EmptyEnvironment::new();

        // var x = 1
        let assign_x = eval.evaluate_unbound_statement(&Script::Var(ScriptToken::identifier("x"), Expression::Number(ScriptToken::number("1"))), &env);
        assert!(assign_x.is_ok());

        // x
        let val_of_x = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("x"))), &env);
        assert!(val_of_x == Ok(json![ 1 ]));
    }

    #[test]
    fn can_bind_tool_from_passed_in_environment() {
        let eval    = StatefulEvalTool::new();
        let env     = DynamicEnvironment::new();

        env.define("test-tool", Box::new(make_pure_tool(|_: ()| 42)));

        // test-tool
        let val_of_test_tool = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("test-tool"))), &env);
        assert!(val_of_test_tool == Ok(json![ 42 ]));
    }
}
<commit_msg>Fix the ‘create evaluator’ tool so that the names are the right way around<commit_after>use std::sync::{Mutex, Arc};
use std::result::Result;
use std::error::Error;

use serde_json::*;
use gossyp_base::*;
use gossyp_base::basic::*;

use super::binding_environment::*;
use super::script_interpreter::*;
use super::bind_statement::*;
use super::evaluate_statement::*;
use super::script::*;
use super::bound_script::*;

///
/// Represents a tool that can be used to evaluate scripts and maintains
/// state (useful for evaluation in a REPL environment)
///
#[derive(Clone)]
pub struct StatefulEvalTool {
    binding:    Arc<Mutex<Box<VariableBindingEnvironment>>>,
    execution:  Arc<Mutex<ScriptExecutionEnvironment>>
}

impl StatefulEvalTool {
    pub fn new() -> StatefulEvalTool {
        StatefulEvalTool {
            binding: Arc::new(Mutex::new(BindingEnvironment::new())),
            execution: Arc::new(Mutex::new(ScriptExecutionEnvironment::new()))
        }
    }

    ///
    /// Evaluates an unbound statement using this tool
    ///
    pub fn evaluate_unbound_statement(&self, script: &Script, environment: &Environment) -> Result<Value, Value> {
        self.evaluate_statement(&self.bind_statement(script, environment)?, environment)
    }

    ///
    /// Binds a statement to this tool
    ///
    pub fn bind_statement(&self, script: &Script, environment: &Environment) -> Result<BoundScript, Value> {
        // Merge the stuff in the external environment with the stored environment
        let our_environment             = &mut **self.binding.lock().unwrap();
        let their_environment           = BindingEnvironment::from_environment(environment);
        let mut combined_environment    = BindingEnvironment::combine(our_environment, &*their_environment);

        // Bind to the combined environments
        bind_statement(script, &mut *combined_environment)
    }

    ///
    /// Evaluates a statement in the environment represented by this tool
    ///
    pub fn evaluate_statement(&self, script: &BoundScript, environment: &Environment) -> Result<Value, Value> {
        evaluate_statement(script, environment, &mut *self.execution.lock().unwrap())
    }
}

impl Tool for StatefulEvalTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let script = from_value::<Script>(input);

        match script {
            Ok(script)          => self.evaluate_unbound_statement(&script, environment),
            Err(script_error)   => Err(json![{
                "error":        "JSON input decode failed",
                "description":  script_error.description(),
            }])
        }
    }
}

///
/// Tool function that creates an eval state in an environment
///
pub fn create_evaluator_with_state_tool(eval_name: String, environment: &Environment) -> Result<(), Value> {
    // Fetch the tool defining tool
    let define_tool = environment.get_json_tool(tool_name::DEFINE_TOOL)
        .map(|tool| TypedTool::<DefineToolInput, ()>::from(tool))
        .map_err(|retrieve_error| json![{
            "error":        "Cannot define tool",
            "description":  retrieve_error.message()
        }])?;

    // Define an environment containing the stateful tool
    let stateful_env = StaticEnvironment::from_tool("new-evaluator", StatefulEvalTool::new(), &EmptyEnvironment::new());

    // Copy the stateful eval tool to the new environment
    define_tool.invoke(DefineToolInput::new("new-evaluator", Some(&eval_name)), &stateful_env)?;

    Ok(())
}

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

    #[test]
    fn can_bind_variable_using_stateful_tool() {
        let eval    = StatefulEvalTool::new();
        let env     = EmptyEnvironment::new();

        // var x = 1
        let assign_x = eval.evaluate_unbound_statement(&Script::Var(ScriptToken::identifier("x"), Expression::Number(ScriptToken::number("1"))), &env);
        assert!(assign_x.is_ok());

        // x
        let val_of_x = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("x"))), &env);
        assert!(val_of_x == Ok(json![ 1 ]));
    }

    #[test]
    fn can_bind_tool_from_passed_in_environment() {
        let eval    = StatefulEvalTool::new();
        let env     = DynamicEnvironment::new();

        env.define("test-tool", Box::new(make_pure_tool(|_: ()| 42)));

        // test-tool
        let val_of_test_tool = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("test-tool"))), &env);
        assert!(val_of_test_tool == Ok(json![ 42 ]));
    }
}
<|endoftext|>