Skip to main content

Engine

Struct Engine 

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

The persistent embedding entry point. Holds the table of registered host functions and compiles scripts into reusable Programs.

This is the library analogue of the one-shot [crate::candela_run]: it does not run a script and hand back stdout, it keeps compiler + VM state resident so the host can call into the script repeatedly.

Implementations§

Source§

impl Engine

Source

pub fn new() -> Self

Source

pub fn with_lib_dir(self, dir: impl Into<PathBuf>) -> Self

Points library imports at dir instead of the directory the toolchain installed.

dir is the one that holds std/, so import "std/string"; reads dir/std/string.cdl. A host that ships the standard library inside its own application directory names it here, and the scripts it compiles find it wherever the application was installed.

let engine = candela::Engine::new().with_lib_dir("/opt/myapp/libs");
Source

pub fn with_cfg(self, cfg: Cfg) -> Self

Sets the flags @cfg(...) attributes test in the scripts this engine compiles.

Code under a @cfg whose condition is false is dropped before names resolve, so it may import a module or call a function that does not exist here. A flag the configuration does not enable is false.

let engine = candela::Engine::new().with_cfg(candela::Cfg::from_iter(["web"]));
Source

pub fn with_import_root(self, name: &str, dir: impl Into<PathBuf>) -> Self

Makes dir the root of the package a script imports as name.

The package is entered through the file its candela.toml names as entry, or src/main.cdl when the manifest names none or there is no manifest. import "shapes"; then reads that file, and import "shapes/circle"; reads circle.cdl from the entry’s directory. dir is searched for native libraries too, so a package that ships a shared library under its root binds a dylib import with no further setup.

let engine = candela::Engine::new().with_import_root("shapes", "/cache/shapes/1.2.3");
Source

pub fn register_host_fn<Marker, F>(&mut self, namespace: &str, name: &str, f: F)
where F: IntoHostFn<Marker>,

Registers a typed host function under namespace::name.

The closure may take any combination of i64/i32, f64, bool, String (or a single &str) arguments and return one of those or (). The declared types are checked against the script’s host block when Engine::compile runs; a mismatch is a clean Diagnostic, never a panic.

A closure that can fail returns Result<T, HostError> instead of T, and the error is raised at the call site in the script:

use candela::HostError;

let mut engine = candela::Engine::new();
engine.register_host_fn("fs", "read", |path: &str| {
    std::fs::read_to_string(path).map_err(HostError::new)
});

The type checked against the declaration is the T inside the Result, so both spellings bind to the same host signature.

Source

pub fn register_host_fn_typed<F>( &mut self, namespace: &str, name: &str, arg_types: Vec<HostType>, ret_type: HostType, f: F, )
where F: Fn(&[Value]) -> Result<Value, HostError> + 'static,

Registers a host function whose signature is given as data rather than derived from a Rust closure’s types.

The closure takes the arguments as a &[Value] slice, and arg_types / ret_type say what the script may pass and expect. The binding is checked against the host block exactly as Engine::register_host_fn is, so a declaration that disagrees is a Diagnostic at Engine::compile time, and the declaration must not use ....

use candela::{HostType, Value};

let mut engine = candela::Engine::new();
engine.register_host_fn_typed(
    "gpio",
    "read",
    vec![HostType::Int],
    HostType::Int,
    |args: &[Value]| Ok(Value::Int(args[0].as_i64().unwrap_or(0))),
);

Use it when the signature is only known at run time: a plugin table, a generated binding, anything with no Rust signature to read the types from.

Source

pub fn register_host_fn_variadic<F>( &mut self, namespace: &str, name: &str, f: F, )
where F: Fn(&[Value]) -> Result<Value, HostError> + 'static,

Registers a variadic host function under namespace::name.

Unlike Engine::register_host_fn, the closure receives every argument as a &[Value] slice of any length and returns a single Value (or a HostError to raise in the script), so arguments of mixed / dynamically-typed shape can cross the boundary without a fixed Rust signature. The host block must declare the function with a ... argument list:

host "app" {
    log(...);
}

No arity or per-argument type checking is performed at the call site; the closure interprets the slice it is handed. A non-variadic declaration bound to a variadic closure (or vice versa) is a clean Diagnostic at Engine::compile time.

Source

pub fn register_macro<F>(&mut self, name: &str, expander: F)
where F: Fn(&str) -> Result<String, MacroError> + 'static,

Registers the expander for name!( ... ) invocations in the scripts this engine compiles.

The expander receives the raw text between the parentheses, which candela does not interpret, and returns candela source for one expression that is parsed in its place. A MacroError it returns instead becomes a compile error at the macro, at the byte offset into the region the error names.

use candela::macros::MacroError;

let mut engine = candela::Engine::new();
engine.register_macro("rows", |body: &str| {
    Ok::<String, MacroError>(body.lines().count().to_string())
});
Source

pub const fn allow_unknown_macros(&mut self, allow: bool)

Sets what a macro with no registered expander does: fail the compile naming it (the default), or, when allow is true, compile as null.

Tooling that reads scripts written for a host it is not part of turns this on, so the host’s macros do not read as errors.

Source

pub fn check( &self, src: &str, filename: &str, ) -> Result<Vec<Diagnostic>, Diagnostic>

Type-checks src the way Engine::compile does, without producing a program, and returns the warnings the compile raised.

Every function whose parameters are all annotated is checked at those types, and a function a host would call with a bare parameter is checked with it typed any, as compile does. What this leaves out is everything a check does not need: a dylib block binds the signatures it declares without opening its library, so a script whose C library a build step has not produced yet still checks; host blocks are not matched against registered closures; main is not required and nothing runs.

§Errors

Returns the Diagnostic of the first error: a parse or type error, a body that does not compile at its declared parameter types, or a dylib signature naming a type C cannot represent.

Source

pub fn compile(&self, src: &str, filename: &str) -> Result<Program, Diagnostic>

Compiles src into a reusable Program, binding every host function it declares to the matching registered closure.

Every function in src whose parameters are all annotated is compiled at those declared types, whether or not anything calls it, so an error in the body of a function main never calls comes back from here rather than from the first Program::call. A function with a bare parameter that nothing in the script calls is checked with that parameter typed any, and warned about; the warnings come back on Program::warnings. A function an import brought in stays lazy.

main is executed once here (module instantiation), so any top-level setup runs before the host makes its first Program::call. The entry-point check runs first, so a broken body is reported before any top-level side effect.

§Errors

Returns a Diagnostic if the script fails to parse/type-check, if the body of an annotated function does not compile at its declared parameter types, if the script declares no main, if a declared host function has no registered closure, if a registered closure’s arity/types disagree with the host block, or if running main raises a runtime error.

Trait Implementations§

Source§

impl Default for Engine

Source§

fn default() -> Engine

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Engine

§

impl !Send for Engine

§

impl !Sync for Engine

§

impl !UnwindSafe for Engine

§

impl Freeze for Engine

§

impl Unpin for Engine

§

impl UnsafeUnpin for Engine

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

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

§

impl<T> Paint for T
where T: ?Sized,

§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling [Attribute] value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi [Quirk] value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1:

renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the [Condition] value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new [Painted] with a default [Style]. Read more
§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.