Skip to main content

DefaultHandler

Struct DefaultHandler 

Source
pub struct DefaultHandler {
    pub sink: Box<dyn IoSink>,
    pub read_root: Option<PathBuf>,
    pub budget_remaining: Arc<AtomicU64>,
    pub budget_ceiling: Option<u64>,
    pub program: Option<Arc<Program>>,
    pub chat_registry: Option<Arc<ChatRegistry>>,
    pub mcp_clients: McpClientCache,
    pub streams: Arc<Mutex<StreamRegistry>>,
    pub next_stream_id: Arc<AtomicU64>,
    pub requested_exit: Arc<AtomicI64>,
    pub program_args: Vec<String>,
    pub approval_sink: Box<dyn ApprovalSink>,
    /* private fields */
}

Fields§

§sink: Box<dyn IoSink>§read_root: Option<PathBuf>

Optional read root for io.read — when set, io.read("p") resolves to read_root.join(p). Lets tests run without touching the real fs.

§budget_remaining: Arc<AtomicU64>

Per-run budget pool (#225). Arc<AtomicU64> so parallel branches share one counter without locking. Initialized to the policy ceiling at handler construction; each call to a function with declared [budget(N)] deducts N atomically via note_call_budget. Cloning the handler is intentional for net.serve / chat handlers — they share the same pool.

§budget_ceiling: Option<u64>

The original ceiling that budget_remaining started at, kept for diagnostics so a BudgetExceeded error can report (used, ceiling) rather than just “exceeded by N”.

§program: Option<Arc<Program>>

Shared reference to the program, needed by net.serve so the handler can spin up fresh VMs to dispatch incoming requests. None if the handler was constructed without a program.

§chat_registry: Option<Arc<ChatRegistry>>

Chat registry; populated by net.serve_ws’s per-message dispatch so chat.broadcast / chat.send work from inside a handler invocation.

§mcp_clients: McpClientCache

LRU cache of agent.call_mcp clients keyed by the command-line string (#197). Avoids spawn-per-call cost when an agent invokes the same MCP server in tight loops. Capped — when the cache is full, the least-recently-used entry is dropped (its subprocess is reaped on Drop).

§streams: Arc<Mutex<StreamRegistry>>

Stream registry for agent.cloud_stream / stream.next / stream.collect (#305 slice 3). Keyed by an opaque handle id; values are the producer iterators. Wrapped in Arc<Mutex<…>> so par_map workers can share the same stream pool (when slice-2’s per-worker handler split chains the registry through).

§next_stream_id: Arc<AtomicU64>

Monotonic counter for handing out fresh stream handle ids.

§requested_exit: Arc<AtomicI64>

The status std.process.exit asked to terminate with (#754).

Arc-shared for the same reason budget_remaining is: a par_map worker gets a cloned handler, and an exit called from a worker has to reach the VM that will actually return. Held per-handler instead, an exit inside parallel work would be dropped on the floor — the failure mode being that a program signalling failure silently exits 0.

NO_EXIT means “not requested”. The first writer wins, so a racing second exit cannot overwrite the status the program already stopped with.

§program_args: Vec<String>

Arguments passed after -- in lex run <file> -- [args...]. Returned by io.argv() so Lex main functions can read CLI flags.

§approval_sink: Box<dyn ApprovalSink>

Host boundary for approval.request. Defaults to NullApprovalSink (always refuses) so a handler must opt in via with_approval_sink before [approval] calls can succeed.

Implementations§

Source§

impl DefaultHandler

Source

pub fn new(policy: Policy) -> Self

Source

pub fn with_approval_sink(self, sink: Box<dyn ApprovalSink>) -> Self

Source

pub fn active_arena(&self) -> Option<&Arena>

Read-only access to the currently-active request arena, if any. None outside a request scope. The follow-on slice that routes Value allocations consults this from the VM path; today it has no callers in tree but is exercised in tests.

Source

pub fn arena_stack_depth(&self) -> usize

Test-only: depth of the arena stack. Lets tests confirm the net.serve_fn request loop pushes/pops symmetrically.

Source

pub fn with_program(self, program: Arc<Program>) -> Self

Source

pub fn with_chat_registry(self, registry: Arc<ChatRegistry>) -> Self

Source

pub fn with_sink(self, sink: Box<dyn IoSink>) -> Self

Source

pub fn with_read_root(self, root: PathBuf) -> Self

Source

pub fn with_program_args(self, args: Vec<String>) -> Self

Trait Implementations§

Source§

impl EffectHandler for DefaultHandler

Source§

fn enter_request_scope(&mut self) -> u64

Push a fresh per-request arena onto the stack (#463 scaffolding). Returns the scope id; pair with exit_request_scope(id) to drop it.

Source§

fn exit_request_scope(&mut self, scope_id: u64)

Drop the arena associated with scope_id. Mismatched pairs (exit called with a scope id we don’t recognize, or out-of- order exit) are tolerated as no-ops rather than panicking — runtime layer should pair them strictly but a stray exit shouldn’t crash a live server.

Source§

fn note_call_budget(&mut self, cost: u64) -> Result<(), String>

Per-call budget enforcement (#225). VM calls this before invoking any function whose signature declares [budget(N)]. The cost N is deducted atomically from the shared pool; returning Err aborts the call before any frame is pushed.

Source§

fn take_exit(&mut self) -> Option<i32>

list.par_map worker-handler factory (#305 slice 2).

Builds a fresh DefaultHandler per worker that shares the budget pool with the parent (Arc<AtomicU64>) so a parallel batch can’t escape the run-wide budget ceiling. Other state is intentionally split per-worker:

  • sink: a StdoutSink per worker. Tests that capture output via a SharedSink wrapped in Arc<Mutex<…>> see each worker as a fresh handler. Print interleaving on stdout is acceptable; tests that need ordered capture run workloads serially anyway.
  • mcp_clients: a fresh per-worker LRU cache. The parent’s subprocess handles can’t be shared across threads without mutex-serialising every MCP call, which would defeat the parallelism. Cache hit rate is sub-optimal across the first call per worker; warmed caches still amortise within a worker.
  • chat_registry: cloned Arc<ChatRegistry> so all workers route into the same chat dispatch layer.
  • program: cloned Arc<Program> so net.serve (if a worker invokes it) sees the same compiled program.
Source§

fn dispatch( &mut self, kind: &str, op: &str, args: Vec<Value>, ) -> Result<Value, String>

Source§

fn spawn_for_worker(&self) -> Option<Box<dyn EffectHandler + Send>>

list.par_map worker-handler factory (#305 slice 2). Read more

Auto Trait Implementations§

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> PlanCallbackArgs for T

Source§

impl<T> PlanCallbackOut for T

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more