partway towards commands

I got very confused and started mucking about with "spawn" when in fact all I needed was the "inline" extension type in orcx that allows the interpreter to expose custom constants.
This commit is contained in:
2026-03-13 16:48:42 +01:00
parent cdcca694c5
commit 09cfcb1839
146 changed files with 3582 additions and 2822 deletions

View File

@@ -10,22 +10,27 @@ use task_local::task_local;
use crate::api;
/// Implementation-specific backing object for an interned string.
pub trait IStrHandle: AsRef<str> {
fn rc(&self) -> Rc<String>;
}
/// Implementation-specific backing object for an interned sequence of interned
/// strings.
pub trait IStrvHandle: AsRef<[IStr]> {
fn rc(&self) -> Rc<Vec<IStr>>;
}
/// Interned string created with [is] or [es]
#[derive(Clone)]
pub struct IStr(pub api::TStr, pub Rc<dyn IStrHandle>);
impl IStr {
/// Obtain a unique ID for this interned data.
/// Obtain a unique ID for this interned data
///
/// NOTICE: the ID is guaranteed to be the same for any interned instance of
/// the same value only as long as at least one instance exists. If a value is
/// no longer interned, the interner is free to forget about it.
/// no longer interned, the interner is free to forget about it
pub fn to_api(&self) -> api::TStr { self.0 }
/// Owned reference to a shared instance of the interned string
pub fn rc(&self) -> Rc<String> { self.1.rc() }
}
impl Deref for IStr {
@@ -45,15 +50,18 @@ impl Display for IStr {
impl Debug for IStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "IStr({self}") }
}
/// Interned string sequence
#[derive(Clone)]
pub struct IStrv(pub api::TStrv, pub Rc<dyn IStrvHandle>);
impl IStrv {
/// Obtain a unique ID for this interned data.
/// Obtain a unique ID for this interned data
///
/// NOTICE: the ID is guaranteed to be the same for any interned instance of
/// the same value only as long as at least one instance exists. If a value is
/// no longer interned, the interner is free to forget about it.
/// no longer interned, the interner is free to forget about it
pub fn to_api(&self) -> api::TStrv { self.0 }
/// Owned reference to a shared instance of the interned sequence
pub fn rc(&self) -> Rc<Vec<IStr>> { self.1.rc() }
}
impl Deref for IStrv {
@@ -84,10 +92,23 @@ impl Debug for IStrv {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "IStrv({self})") }
}
/// Injectable interner interface
///
/// [Self::is] and [Self::iv] return an existing ID if any [IStrHandle] or
/// [IStrvHandle] for the same value is still live, and any ID currently not
/// used with the same type otherwise
///
/// [Self::es] and [Self::ev] find an existing value by its key if any
/// [IStrHandle] or [IStrvHandle] for the same ID is still live. If all objects
/// are gone the functions may work or panic.
pub trait InternerSrv {
/// Intern a string
fn is<'a>(&'a self, v: &'a str) -> LocalBoxFuture<'a, IStr>;
/// Find an existing string by its key
fn es(&self, t: api::TStr) -> LocalBoxFuture<'_, IStr>;
/// Intern a str vector
fn iv<'a>(&'a self, v: &'a [IStr]) -> LocalBoxFuture<'a, IStrv>;
/// Find an existing str vector by its key
fn ev(&self, t: api::TStrv) -> LocalBoxFuture<'_, IStrv>;
}
@@ -95,6 +116,8 @@ task_local! {
static INTERNER: Rc<dyn InternerSrv>;
}
/// Install a global interner. Within this future, the global [is], [iv], [es]
/// and [ev] functions call the provided [InternerSrv]
pub async fn with_interner<F: Future>(val: Rc<dyn InternerSrv>, fut: F) -> F::Output {
INTERNER.scope(val, fut).await
}
@@ -103,11 +126,28 @@ fn get_interner() -> Rc<dyn InternerSrv> {
INTERNER.try_with(|i| i.clone()).expect("Interner not initialized")
}
/// Intern a `String` (find its ID or assign it a new one)
pub async fn is(v: &str) -> IStr { get_interner().is(v).await }
/// Intern a `Vec<IStr>` (find its ID or assign it a new one)
pub async fn iv(v: &[IStr]) -> IStrv { get_interner().iv(v).await }
/// Find a live [IStr] by its ID
///
/// # Panics
///
/// This function may panic if there are no other references to the [IStr] we're
/// searching for, as the interner is free to forget about unreferenced values
pub async fn es(v: api::TStr) -> IStr { get_interner().es(v).await }
/// Find a live [IStrv] by its ID
///
/// # Panics
///
/// This function may panic if there are no other references to the [IStrv]
/// we're searching for, as the interner is free to forget about unreferenced
/// values
pub async fn ev(v: api::TStrv) -> IStrv { get_interner().ev(v).await }
/// Basic engine for an interner that supports recovering if a token is not
/// found locally.
pub mod local_interner {
use std::borrow::Borrow;
use std::cell::RefCell;
@@ -144,6 +184,7 @@ pub mod local_interner {
fn new_interned(token: Self::Token, handle: Rc<Handle<Self>>) -> Self::Interned;
}
/// String-specific values for [InternableCard]
#[derive(Default, Debug)]
pub struct StrBranch;
impl InternableCard for StrBranch {
@@ -154,6 +195,7 @@ pub mod local_interner {
fn new_interned(t: Self::Token, h: Rc<Handle<Self>>) -> Self::Interned { IStr(t, h) }
}
/// Vector-specific values for [InternableCard]
#[derive(Default, Debug)]
pub struct StrvBranch;
impl InternableCard for StrvBranch {
@@ -208,8 +250,8 @@ pub mod local_interner {
/// Information retained about an interned token indexed both by key and
/// value.
struct Rec<B: InternableCard> {
/// This reference is weak, but the [Drop] handler of [Handle] removes all
/// [Rec]s from the interner so it is guaranteed to be live.
/// This reference is weak, but the [Drop] handler of [Handle] removes the
/// [Rec] from the interner so it is guaranteed to be live.
handle: Weak<Handle<B>>,
/// Keys for indexing from either table
data: Data<B>,