Skip to main content

NativeFnCaps

Trait NativeFnCaps 

Source
pub trait NativeFnCaps: Send + Sync {
    // Required method
    fn call_relon(
        &self,
        func: &Value,
        args: Vec<Value>,
        range: TokenRange,
    ) -> Result<Value, RuntimeError>;

    // Provided methods
    fn max_value_elements(&self) -> Option<usize> { ... }
    fn next_iter_id(&self) -> u64 { ... }
    fn iter_cursor_fetch_and_inc(
        &self,
        _iter_id: u64,
        _len: usize,
    ) -> Option<usize> { ... }
    fn tick(&self, _n: u64, _range: TokenRange) -> Result<(), RuntimeError> { ... }
}
Expand description

A handle to the evaluator’s internal execution capabilities, allowing native functions to call back into Relon logic (closures).

Lives in relon-eval-api so that any backend implementing crate::Evaluator can mint a NativeFnCaps of its own for the native fns it dispatches. The default impls keep host-supplied RelonFunctions usable in lightweight test contexts where no backend is attached.

Required Methods§

Source

fn call_relon( &self, func: &Value, args: Vec<Value>, range: TokenRange, ) -> Result<Value, RuntimeError>

Provided Methods§

Source

fn max_value_elements(&self) -> Option<usize>

Expose Capabilities::max_value_elements to native functions so collection-building intrinsics (range, future bulk constructors) can pre-flight oversized requests before allocating. Returning None means the host imposes no cap on List / Tuple / Dict element counts.

The evaluator still runs a post-call check_value_size on every List / Tuple / Dict produced by a native fn (catch-all in call_function / try_call_native_method), so an intrinsic that ignores this hint is still bounded — but allocating Vec::with_capacity(end - start) first would OOM the host before the post-call check fires. Intrinsics that build a collection whose size is known up-front from their arguments should consult this and reject early.

Source

fn next_iter_id(&self) -> u64

Mint a fresh Iter cursor id under the originating Context. Used by List.iter() / String.iter() / Dict.iter() (and any future user-side Iterable constructor that wants to participate in Iter.next() cursor tracking) to stamp the _id field of the resulting Iter-branded dict. Returns 0 from the default impl so a non-Context-backed caps (e.g. in unit tests) still produces a sane id; production evaluation overrides this on the per-Context impl.

Source

fn iter_cursor_fetch_and_inc(&self, _iter_id: u64, _len: usize) -> Option<usize>

Atomic read-check-increment of the cursor associated with iter_id. Returns Some(old_cursor) when the cursor was strictly less than len (and the cursor is post-incremented in the same critical section), or None when the cursor has reached len or the id is unknown to this Context.

The “unknown id ⇒ None” branch is the cross-Context isolation policy: an Iter value built in Context A and then handed to Context B looks exhausted from B’s perspective. Implementations should preserve this — silently auto-inserting a fresh cursor for an unknown id would re-introduce ambient state across Context boundaries.

Source

fn tick(&self, _n: u64, _range: TokenRange) -> Result<(), RuntimeError>

Advance the step counter by n and bail with RuntimeError::StepLimitExceeded if the new count would exceed max_steps. Native fns with internal loops (range, list.map / filter / reduce, string.split / replace, dict.merge, …) call this once per inner iteration so a million-element pipeline can’t hide behind a single AST-node step.

Behaviour:

  • max_steps == None → no-op (Ok(())), no allocation, no lock — the default impl below mirrors that for hosts that build a custom NativeFnCaps.
  • max_steps == Some(limit)fetch_add(n) on the same atomic counter the evaluator increments; if the new value crosses the limit, return StepLimitExceeded { limit, range }.

range should pin the call-site span of the intrinsic so the resulting diagnostic points at the same node the AST-level step check would have flagged.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§