pub struct Engine { /* private fields */ }
Expand description

Start here! An execution engine. Contains information about things like globals, registered types, etc.

Implementations

Creates a new engine using the default core library.

Although Engine::with_debug_options and likewise Engine::with_corelib can panic if the core library is much too big, the official core library is not big enough to cause this.

Examples
use mica::Engine;

let mut engine = Engine::new();

Creates a new engine with an alternative core library.

Panics

Constructing the engine can panic if the core library defines too many globals, functions, methods, or the like. See Engine::with_debug_options for more remarks.

Examples
use mica::Engine;

let mut engine = Engine::with_corelib(mica::corelib::Lib);

Creates a new engine with specific debug options.

Engine::new and Engine::with_corelib create engines with Default debug options, and should generally be preferred unless you’re debugging the language’s internals.

Panics

Constructing the engine can panic if the core library defines too many globals, functions, methods, or the like. In reality this is only really a problem if you let users control the amount of methods registered by your core library (which you should never, ever do.)

Examples
use mica::{Engine, DebugOptions};

// Create a loud engine that prints a bunch of debugging information to stdout.
let mut engine = Engine::with_debug_options(mica::corelib::Lib, DebugOptions {
    dump_ast: true,
    dump_bytecode: true,
});

Compiles a script without executing it.

The filename is used for reporting compilation errors and in stack traces.

Examples
use mica::Engine;

let mut engine = Engine::new();
let script = engine.compile("example.mi", "2 + 2")?;

Compiles and starts executing a script in a fiber.

This can be used as a shorthand if you don’t intend to reuse the compiled Script.

Examples
use mica::Engine;

let mut engine = Engine::new();
let mut fiber = engine.start("example.mi", "2 + 2")?;

Calls a function with the given arguments.

The function is called in a new fiber, and execution is trampolined until the fiber finishes executing.

Examples
use mica::{Engine, Value};

let mut engine = Engine::new();
let f: Value = engine.start("example.mi", r#" (func (x) = x + 2) "#)?.trampoline()?;
let result: f64 = engine.call(f, [Value::new(1.0)])?;
assert_eq!(result, 3.0);

Returns the unique ID of a method with a given name and arity.

Note that there can only exist about 65 thousand unique method signatures. This is usually not a problem as method names often repeat between types. Also note that unlike functions, a method can only accept up to 255 arguments. Which, to be quite frankly honest, should be enough for anyone.

Examples
use mica::Engine;

let mut engine = Engine::new();

// Two identical calls to method_id always return the same ID.
let m_to_string_1 = engine.method_id(("to_string", 0))?;
let m_to_string_2 = engine.method_id(("to_string", 0))?;
let m_pi = engine.method_id(("pi", 0))?;
assert_eq!(m_to_string_1, m_to_string_2);
assert_ne!(m_to_string_1, m_pi);

Calls a method on a receiver with the given arguments.

Note that if you’re calling a method often, it’s cheaper to precompute the method signature into a MethodId by using the method_id function, compared to passing a (name, arity) pair every single time.

Examples
use mica::{Engine, Value};

let mut engine = Engine::new();
let example = engine
    .start(
        "dog.mi",
        r#" struct Example impl
                func new() constructor = nil
            end "#
    )?
    .trampoline()?;
let instance: Value = engine.call_method(example, ("new", 0), [])?;
assert!(matches!(instance, Value::Struct(..)));

Creates a new value that is potentially user data.

User data values need to retrieve type information from the engine upon their creation, which prevents them from being created by Value::new which does not possess the same information.

Also of note is that because the type information is retrieved during creation, so the type must be registered inside the engine by then; otherwise you’ll get an opaque user data value.

This needn’t be used for user data returned from functions added into the VM, because the engine automatically does the full conversion under the hood.

Examples
use mica::{Engine, TypeBuilder, UserData, Value};

struct Cell {
    value: Value,
}

impl UserData for Cell {}

let mut engine = Engine::new();
engine.add_type(
    TypeBuilder::<Cell>::new("Cell")
        .add_static("new", |value| Cell { value })
        .add_function("value", |cell: &Cell| cell.value.clone()),
)?;

// The following will not work, because `Value::new` does not have access to
// Mica type information:
// let cell = Value::new(Cell { value: Value::new(1.0) });

// The following though, will:
let cell = engine.create_value(Cell { value: Value::new(1.0) });
engine.set("one", cell)?;

let okay: Result<Value, _> = engine
    .start("okay.mi", "assert(one.value == 1)")?
    .trampoline();
assert!(okay.is_ok());

Returns the unique global ID for the global with the given name, or an error if there are too many globals in scope.

The maximum amount of globals is about 16 million, so you shouldn’t worry too much about hitting that limit unless you’re stress-testing the VM or accepting untrusted input as globals.

Examples
use mica::Engine;

let mut engine = Engine::new();

// Two identical calls to global_id always return the same ID.
let g_print_1 = engine.global_id("print")?;
let g_print_2 = engine.global_id("print")?;
let g_debug = engine.global_id("debug")?;
assert_eq!(g_print_1, g_print_2);
assert_ne!(g_print_1, g_debug);

Sets a global variable that’ll be available to scripts executed by the engine.

The id parameter can be either an &str or a prefetched global_id.

Examples
use mica::{Engine, Value};

let mut engine = Engine::new();
engine.set("x", 1.0_f64);
let _: Value = engine
    .start("assertion.mi", "assert(x == 1)")?
    .trampoline()?;

Returns the value of a global variable, or nil if it’s not set.

The id parameter can be either an &str or a prefetched global_id.

Examples
use mica::{Engine, Value};

let mut engine = Engine::new();
let _: Value = engine
    .start("assertion.mi", "x = 1")?
    .trampoline()?;
let x: f64 = engine.get("x")?;
assert_eq!(x, 1.0);

Declares a “raw” function in the global scope. Raw functions do not perform any type checks by default and accept a variable number of arguments.

You should generally prefer add_function instead of this.

Note that this cannot accept GlobalIds, because a name is required to create the function and global IDs have their name erased.

parameter_count should reflect the parameter count of the function. Pass None if the function accepts a variable number of arguments. Note that because this function omits type checks you may receive a different amount of arguments than specified.

Examples
use mica::{Engine, Value};
use mica::ll::{bytecode::FunctionKind, value::RawValue};

let mut engine = Engine::new();
engine.add_raw_function(
    "a_raw_understanding",
    0,
    FunctionKind::Foreign(Box::new(|env, gc, arguments| {
        Ok(RawValue::from(1.0))
    })),
);
let _: Value = engine
    .start("assertion.mi", "assert(a_raw_understanding() == 1.0)")?
    .trampoline()?;

Declares a function in the global scope.

Examples
use mica::Engine;

let mut engine = Engine::new();
engine.add_function("add", |x: f64, y: f64| x + y);
let x: f64 = engine
    .start("example.mi", "add(1, 2)")?
    .trampoline()?;
assert_eq!(x, 3.0);

Declares a type in the global scope.

Examples

See TypeBuilder<T> for examples.

Starts building a new trait.

Examples

See TraitBuilder for examples.

Trait Implementations

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.