Orchid-base uses task-local context.

Everything else is broken at the moment.
This commit is contained in:
2025-12-14 17:17:43 +01:00
parent 8753d4c751
commit 0b2b05d44e
22 changed files with 463 additions and 1082 deletions

View File

@@ -12,65 +12,60 @@ use itertools::Itertools;
use trait_set::trait_set;
use crate::api;
use crate::interner::{InternMarker, Interner, Tok};
use crate::interner::{IStr, IStrv, es, ev, is, iv};
trait_set! {
/// Traits that all name iterators should implement
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
pub trait NameIter = Iterator<Item = IStr> + DoubleEndedIterator + ExactSizeIterator;
}
/// A token path which may be empty. [VName] is the non-empty version
#[derive(Clone, Default, Hash, PartialEq, Eq)]
pub struct VPath(Vec<Tok<String>>);
pub struct VPath(Vec<IStr>);
impl VPath {
/// Collect segments into a vector
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Self {
Self(items.into_iter().collect())
}
pub fn new(items: impl IntoIterator<Item = IStr>) -> Self { Self(items.into_iter().collect()) }
/// Number of path segments
pub fn len(&self) -> usize { self.0.len() }
/// Whether there are any path segments. In other words, whether this is a
/// valid name
pub fn is_empty(&self) -> bool { self.len() == 0 }
/// Prepend some tokens to the path
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
pub fn prefix(self, items: impl IntoIterator<Item = IStr>) -> Self {
Self(items.into_iter().chain(self.0).collect())
}
/// Append some tokens to the path
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
pub fn suffix(self, items: impl IntoIterator<Item = IStr>) -> Self {
Self(self.0.into_iter().chain(items).collect())
}
/// Partition the string by `::` namespace separators
pub async fn parse(s: &str, i: &Interner) -> Self {
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(|s| i.i(s))).await })
pub async fn parse(s: &str) -> Self {
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(is)).await })
}
/// Walk over the segments
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> { Box::new(self.0.iter().map(|s| &**s)) }
/// Try to convert into non-empty version
pub fn into_name(self) -> Result<VName, EmptyNameError> { VName::new(self.0) }
/// Add a token to the path. Since now we know that it can't be empty, turn it
/// into a name.
pub fn name_with_suffix(self, name: Tok<String>) -> VName {
pub fn name_with_suffix(self, name: IStr) -> VName {
VName(self.into_iter().chain([name]).collect())
}
/// Add a token to the beginning of the. Since now we know that it can't be
/// empty, turn it into a name.
pub fn name_with_prefix(self, name: Tok<String>) -> VName {
pub fn name_with_prefix(self, name: IStr) -> VName {
VName([name].into_iter().chain(self).collect())
}
/// Convert a fs path to a vpath
pub async fn from_path(path: &Path, ext: &str, i: &Interner) -> Option<(Self, bool)> {
async fn to_vpath(p: &Path, i: &Interner) -> Option<VPath> {
let tok_opt_v =
join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(|s| i.i(s))))).await;
pub async fn from_path(path: &Path, ext: &str) -> Option<(Self, bool)> {
async fn to_vpath(p: &Path) -> Option<VPath> {
let tok_opt_v = join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(is)))).await;
tok_opt_v.into_iter().collect::<Option<_>>().map(VPath)
}
match path.extension().map(|s| s.to_str()) {
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension(""), i).await?, true)),
None => Some((to_vpath(path, i).await?, false)),
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension("")).await?, true)),
None => Some((to_vpath(path).await?, false)),
Some(_) => None,
}
}
@@ -83,30 +78,28 @@ impl fmt::Display for VPath {
write!(f, "{}", self.str_iter().join("::"))
}
}
impl FromIterator<Tok<String>> for VPath {
fn from_iter<T: IntoIterator<Item = Tok<String>>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
impl FromIterator<IStr> for VPath {
fn from_iter<T: IntoIterator<Item = IStr>>(iter: T) -> Self { Self(iter.into_iter().collect()) }
}
impl IntoIterator for VPath {
type Item = Tok<String>;
type Item = IStr;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
impl Borrow<[Tok<String>]> for VPath {
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
impl Borrow<[IStr]> for VPath {
fn borrow(&self) -> &[IStr] { &self.0[..] }
}
impl Deref for VPath {
type Target = [Tok<String>];
type Target = [IStr];
fn deref(&self) -> &Self::Target { self.borrow() }
}
impl<T> Index<T> for VPath
where [Tok<String>]: Index<T>
where [IStr]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
type Output = <[IStr] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &Borrow::<[Tok<String>]>::borrow(self)[index] }
fn index(&self, index: T) -> &Self::Output { &Borrow::<[IStr]>::borrow(self)[index] }
}
/// A mutable representation of a namespaced identifier of at least one segment.
@@ -116,50 +109,43 @@ where [Tok<String>]: Index<T>
/// See also [Sym] for the immutable representation, and [VPath] for possibly
/// empty values
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct VName(Vec<Tok<String>>);
pub struct VName(Vec<IStr>);
impl VName {
/// Assert that the sequence isn't empty and wrap it in [VName] to represent
/// this invariant
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
pub fn new(items: impl IntoIterator<Item = IStr>) -> Result<Self, EmptyNameError> {
let data: Vec<_> = items.into_iter().collect();
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
}
pub async fn deintern(
name: impl IntoIterator<Item = api::TStr>,
i: &Interner,
) -> Result<Self, EmptyNameError> {
Self::new(join_all(name.into_iter().map(|m| Tok::from_api(m, i))).await)
pub async fn deintern(name: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
Self::new(join_all(name.into_iter().map(es)).await)
}
/// Unwrap the enclosed vector
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
pub fn into_vec(self) -> Vec<IStr> { self.0 }
/// Get a reference to the enclosed vector
pub fn vec(&self) -> &Vec<Tok<String>> { &self.0 }
pub fn vec(&self) -> &Vec<IStr> { &self.0 }
/// Mutable access to the underlying vector. To ensure correct results, this
/// must never be empty.
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
pub fn vec_mut(&mut self) -> &mut Vec<IStr> { &mut self.0 }
/// Intern the name and return a [Sym]
pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.i(&self.0[..]).await) }
pub async fn to_sym(&self) -> Sym { Sym(iv(&self.0[..]).await) }
/// If this name has only one segment, return it
pub fn as_root(&self) -> Option<Tok<String>> { self.0.iter().exactly_one().ok().cloned() }
pub fn as_root(&self) -> Option<IStr> { self.0.iter().exactly_one().ok().cloned() }
/// Prepend the segments to this name
#[must_use = "This is a pure function"]
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
pub fn prefix(self, items: impl IntoIterator<Item = IStr>) -> Self {
Self(items.into_iter().chain(self.0).collect())
}
/// Append the segments to this name
#[must_use = "This is a pure function"]
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
pub fn suffix(self, items: impl IntoIterator<Item = IStr>) -> Self {
Self(self.0.into_iter().chain(items).collect())
}
/// Read a `::` separated namespaced name
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
Self::new(VPath::parse(s, i).await)
}
pub async fn literal(s: &'static str, i: &Interner) -> Self {
Self::parse(s, i).await.expect("empty literal !?")
}
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s).await) }
pub async fn literal(s: &'static str) -> Self { Self::parse(s).await.expect("empty literal !?") }
/// Obtain an iterator over the segments of the name
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ { self.0.iter().cloned() }
pub fn iter(&self) -> impl Iterator<Item = IStr> + '_ { self.0.iter().cloned() }
}
impl fmt::Debug for VName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
@@ -170,22 +156,22 @@ impl fmt::Display for VName {
}
}
impl IntoIterator for VName {
type Item = Tok<String>;
type Item = IStr;
type IntoIter = vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
impl<T> Index<T> for VName
where [Tok<String>]: Index<T>
where [IStr]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
type Output = <[IStr] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for VName {
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
impl Borrow<[IStr]> for VName {
fn borrow(&self) -> &[IStr] { self.0.borrow() }
}
impl Deref for VName {
type Target = [Tok<String>];
type Target = [IStr];
fn deref(&self) -> &Self::Target { self.borrow() }
}
@@ -193,11 +179,9 @@ impl Deref for VName {
/// empty sequence
#[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EmptyNameError;
impl TryFrom<&[Tok<String>]> for VName {
impl TryFrom<&[IStr]> for VName {
type Error = EmptyNameError;
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
Self::new(value.iter().cloned())
}
fn try_from(value: &[IStr]) -> Result<Self, Self::Error> { Self::new(value.iter().cloned()) }
}
/// An interned representation of a namespaced identifier.
@@ -206,37 +190,34 @@ impl TryFrom<&[Tok<String>]> for VName {
///
/// See also [VName]
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct Sym(Tok<Vec<Tok<String>>>);
pub struct Sym(IStrv);
impl Sym {
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
/// represent this invariant
pub async fn new(
v: impl IntoIterator<Item = Tok<String>>,
i: &Interner,
) -> Result<Self, EmptyNameError> {
pub async fn new(v: impl IntoIterator<Item = IStr>) -> Result<Self, EmptyNameError> {
let items = v.into_iter().collect_vec();
Self::from_tok(i.i(&items).await)
Self::from_tok(iv(&items).await)
}
/// Read a `::` separated namespaced name.
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
Ok(Sym(i.i(&VName::parse(s, i).await?.into_vec()).await))
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> {
Ok(Sym(iv(&VName::parse(s).await?.into_vec()).await))
}
/// Assert that a token isn't empty, and wrap it in a [Sym]
pub fn from_tok(t: Tok<Vec<Tok<String>>>) -> Result<Self, EmptyNameError> {
pub fn from_tok(t: IStrv) -> Result<Self, EmptyNameError> {
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
}
/// Grab the interner token
pub fn tok(&self) -> Tok<Vec<Tok<String>>> { self.0.clone() }
pub fn tok(&self) -> IStrv { self.0.clone() }
/// Get a number unique to this name suitable for arbitrary ordering.
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
pub fn id(&self) -> NonZeroU64 { self.0.to_api().0 }
/// Extern the sym for editing
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
pub async fn from_api(marker: api::TStrv, i: &Interner) -> Sym {
Self::from_tok(Tok::from_api(marker, i).await).expect("Empty sequence found for serialized Sym")
pub async fn from_api(marker: api::TStrv) -> Sym {
Self::from_tok(ev(marker).await).expect("Empty sequence found for serialized Sym")
}
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
pub async fn suffix(&self, tokv: impl IntoIterator<Item = Tok<String>>, i: &Interner) -> Sym {
Self::new(self.0.iter().cloned().chain(tokv), i).await.unwrap()
pub async fn suffix(&self, tokv: impl IntoIterator<Item = IStr>) -> Sym {
Self::new(self.0.iter().cloned().chain(tokv)).await.unwrap()
}
}
impl fmt::Debug for Sym {
@@ -248,17 +229,17 @@ impl fmt::Display for Sym {
}
}
impl<T> Index<T> for Sym
where [Tok<String>]: Index<T>
where [IStr]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
type Output = <[IStr] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for Sym {
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
impl Borrow<[IStr]> for Sym {
fn borrow(&self) -> &[IStr] { &self.0[..] }
}
impl Deref for Sym {
type Target = [Tok<String>];
type Target = [IStr];
fn deref(&self) -> &Self::Target { self.borrow() }
}
@@ -266,16 +247,14 @@ impl Deref for Sym {
/// handled together in datastructures. The names can never be empty
#[allow(clippy::len_without_is_empty)] // never empty
pub trait NameLike:
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[Tok<String>]>
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[IStr]>
{
/// Convert into held slice
fn as_slice(&self) -> &[Tok<String>] { Borrow::<[Tok<String>]>::borrow(self) }
fn as_slice(&self) -> &[IStr] { Borrow::<[IStr]>::borrow(self) }
/// Get iterator over tokens
fn segs(&self) -> impl NameIter + '_ { self.as_slice().iter().cloned() }
/// Get iterator over string segments
fn str_iter(&self) -> impl Iterator<Item = &'_ str> + '_ {
self.as_slice().iter().map(|t| t.as_str())
}
fn str_iter(&self) -> impl Iterator<Item = &'_ str> + '_ { self.as_slice().iter().map(|t| &**t) }
/// Fully resolve the name for printing
#[must_use]
fn to_strv(&self) -> Vec<String> { self.segs().map(|s| s.to_string()).collect() }
@@ -286,19 +265,19 @@ pub trait NameLike:
NonZeroUsize::try_from(self.segs().count()).expect("NameLike never empty")
}
/// Like slice's `split_first` except we know that it always returns Some
fn split_first_seg(&self) -> (Tok<String>, &[Tok<String>]) {
fn split_first_seg(&self) -> (IStr, &[IStr]) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), torso)
}
/// Like slice's `split_last` except we know that it always returns Some
fn split_last_seg(&self) -> (Tok<String>, &[Tok<String>]) {
fn split_last_seg(&self) -> (IStr, &[IStr]) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), torso)
}
/// Get the first element
fn first_seg(&self) -> Tok<String> { self.split_first_seg().0 }
fn first_seg(&self) -> IStr { self.split_first_seg().0 }
/// Get the last element
fn last_seg(&self) -> Tok<String> { self.split_last_seg().0 }
fn last_seg(&self) -> IStr { self.split_last_seg().0 }
}
impl NameLike for Sym {}
@@ -311,11 +290,11 @@ impl NameLike for VName {}
/// cloning the token.
#[macro_export]
macro_rules! sym {
($seg1:tt $( :: $seg:tt)* ; $i:expr) => {
($seg1:tt $( :: $seg:tt)*) => {
$crate::name::Sym::from_tok(
$i.i(&[
$i.i(stringify!($seg1)).await
$( , $i.i(stringify!($seg)).await )*
$crate::interner::iv(&[
$crate::interner::is(stringify!($seg1)).await
$( , $crate::interner::is(stringify!($seg)).await )*
])
.await
).unwrap()
@@ -327,10 +306,10 @@ macro_rules! sym {
/// The components are interned much like in [sym].
#[macro_export]
macro_rules! vname {
($seg1:tt $( :: $seg:tt)* ; $i:expr) => {
($seg1:tt $( :: $seg:tt)*) => {
$crate::name::VName::new([
$i.i(stringify!($seg1)).await
$( , $i.i(stringify!($seg)).await )*
$crate::interner::is(stringify!($seg1)).await
$( , $crate::interner::is(stringify!($seg)).await )*
]).unwrap()
};
}
@@ -340,10 +319,10 @@ macro_rules! vname {
/// The components are interned much like in [sym].
#[macro_export]
macro_rules! vpath {
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => {
($seg1:tt $( :: $seg:tt)*) => {
$crate::name::VPath(vec![
$i.i(stringify!($seg1)).await
$( , $i.i(stringify!($seg)).await )+
$crate::interner::is(stringify!($seg1)).await
$( , $crate::interner::is(stringify!($seg)).await )*
])
};
() => {
@@ -352,42 +331,33 @@ macro_rules! vpath {
}
#[cfg(test)]
mod test {
pub mod test {
use std::borrow::Borrow;
use test_executors::spin_on;
use super::{NameLike, Sym, VName};
use crate::interner::{Interner, Tok};
use crate::interner::{IStr, is};
use crate::name::VPath;
#[test]
fn recur() {
spin_on(async {
let i = Interner::new_master();
let myname = vname!(foo::bar; i);
let _borrowed_slice: &[Tok<String>] = myname.borrow();
let _deref_pathslice: &[Tok<String>] = &myname;
let _as_slice_out: &[Tok<String>] = myname.as_slice();
})
pub async fn recur() {
let myname = vname!(foo::bar);
let _borrowed_slice: &[IStr] = myname.borrow();
let _deref_pathslice: &[IStr] = &myname;
let _as_slice_out: &[IStr] = myname.as_slice();
}
#[test]
fn literals() {
spin_on(async {
let i = Interner::new_master();
assert_eq!(
sym!(foo::bar::baz; i),
Sym::new([i.i("foo").await, i.i("bar").await, i.i("baz").await], &i).await.unwrap()
);
assert_eq!(
vname!(foo::bar::baz; i),
VName::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]).unwrap()
);
assert_eq!(
vpath!(foo::bar::baz; i),
VPath::new([i.i("foo").await, i.i("bar").await, i.i("baz").await])
);
})
/// Tests that literals are correctly interned as equal
pub async fn literals() {
assert_eq!(
sym!(foo::bar::baz),
Sym::new([is("foo").await, is("bar").await, is("baz").await]).await.unwrap()
);
assert_eq!(
vname!(foo::bar::baz),
VName::new([is("foo").await, is("bar").await, is("baz").await]).unwrap()
);
assert_eq!(
vpath!(foo::bar::baz),
VPath::new([is("foo").await, is("bar").await, is("baz").await])
);
}
}