forked from Orchid/orchid
orchid-base moved to async
This commit is contained in:
@@ -8,6 +8,7 @@ use std::ops::{Bound, Deref, Index, RangeBounds};
|
||||
use std::path::Path;
|
||||
use std::{fmt, slice, vec};
|
||||
|
||||
use futures::future::{OptionFuture, join_all};
|
||||
use itertools::Itertools;
|
||||
use trait_set::trait_set;
|
||||
|
||||
@@ -173,8 +174,8 @@ impl VPath {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Partition the string by `::` namespace separators
|
||||
pub fn parse(s: &str) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { s.split("::").map(intern).collect() })
|
||||
pub async fn parse(s: &str) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(intern)).await })
|
||||
}
|
||||
/// Walk over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
@@ -194,12 +195,14 @@ impl VPath {
|
||||
}
|
||||
|
||||
/// Convert a fs path to a vpath
|
||||
pub fn from_path(path: &Path) -> Option<(Self, bool)> {
|
||||
let to_vpath =
|
||||
|p: &Path| p.iter().map(|c| c.to_str().map(intern)).collect::<Option<_>>().map(VPath);
|
||||
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(intern)))).await;
|
||||
tok_opt_v.into_iter().collect::<Option<_>>().map(VPath)
|
||||
}
|
||||
match path.extension().map(|s| s.to_str()) {
|
||||
Some(Some("orc")) => Some((to_vpath(&path.with_extension(""))?, true)),
|
||||
None => Some((to_vpath(path)?, false)),
|
||||
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension("")).await?, true)),
|
||||
None => Some((to_vpath(path).await?, false)),
|
||||
Some(_) => None,
|
||||
}
|
||||
}
|
||||
@@ -256,8 +259,8 @@ impl VName {
|
||||
let data: Vec<_> = items.into_iter().collect();
|
||||
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
||||
}
|
||||
pub fn deintern(items: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
|
||||
Self::new(items.into_iter().map(Tok::from_api))
|
||||
pub async fn deintern(name: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
|
||||
Self::new(join_all(name.into_iter().map(Tok::from_api)).await)
|
||||
}
|
||||
/// Unwrap the enclosed vector
|
||||
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
|
||||
@@ -267,7 +270,7 @@ impl VName {
|
||||
/// must never be empty.
|
||||
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
|
||||
/// Intern the name and return a [Sym]
|
||||
pub fn to_sym(&self) -> Sym { Sym(intern(&self.0[..])) }
|
||||
pub async fn to_sym(&self) -> Sym { Sym(intern(&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() }
|
||||
/// Prepend the segments to this name
|
||||
@@ -281,8 +284,8 @@ impl VName {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Read a `::` separated namespaced name
|
||||
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s)) }
|
||||
pub fn literal(s: &'static str) -> Self { Self::parse(s).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() }
|
||||
}
|
||||
@@ -338,13 +341,13 @@ pub struct Sym(Tok<Vec<Tok<String>>>);
|
||||
impl Sym {
|
||||
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
|
||||
/// represent this invariant
|
||||
pub fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
pub async fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
let items = v.into_iter().collect_vec();
|
||||
Self::from_tok(intern(&items[..]))
|
||||
Self::from_tok(intern(&items[..]).await)
|
||||
}
|
||||
/// Read a `::` separated namespaced name.
|
||||
pub fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(intern(&VName::parse(s)?.into_vec()[..])))
|
||||
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(intern(&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> {
|
||||
@@ -356,8 +359,8 @@ impl Sym {
|
||||
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
|
||||
/// Extern the sym for editing
|
||||
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
||||
pub fn from_api(marker: api::TStrv) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker)).expect("Empty sequence found for serialized Sym")
|
||||
pub async fn from_api(marker: api::TStrv) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker).await).expect("Empty sequence found for serialized Sym")
|
||||
}
|
||||
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
|
||||
}
|
||||
@@ -437,10 +440,13 @@ impl NameLike for VName {}
|
||||
#[macro_export]
|
||||
macro_rules! sym {
|
||||
($seg1:tt $( :: $seg:tt)*) => { async {
|
||||
$crate::name::Sym::from_tok($crate::intern!([$crate::interner::Tok<String>]: &[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
])).unwrap()
|
||||
$crate::name::Sym::from_tok(
|
||||
$crate::intern!([$crate::interner::Tok<String>]: &[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
])
|
||||
.await
|
||||
).unwrap()
|
||||
}
|
||||
};
|
||||
(@NAME $seg:tt) => {}
|
||||
@@ -451,12 +457,12 @@ macro_rules! sym {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vname {
|
||||
($seg1:tt $( :: $seg:tt)*) => {
|
||||
($seg1:tt $( :: $seg:tt)*) => { async {
|
||||
$crate::name::VName::new([
|
||||
$crate::intern!(str: stringify!($seg1))
|
||||
$( , $crate::intern!(str: stringify!($seg)) )*
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
]).unwrap()
|
||||
};
|
||||
} };
|
||||
}
|
||||
|
||||
/// Create a [VPath] literal.
|
||||
@@ -464,12 +470,12 @@ macro_rules! vname {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vpath {
|
||||
($seg1:tt $( :: $seg:tt)+) => {
|
||||
($seg1:tt $( :: $seg:tt)+) => { async {
|
||||
$crate::name::VPath(vec![
|
||||
$crate::intern!(str: stringify!($seg1))
|
||||
$( , $crate::intern!(str: stringify!($seg)) )+
|
||||
])
|
||||
};
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )+
|
||||
])
|
||||
} };
|
||||
() => {
|
||||
$crate::name::VPath(vec![])
|
||||
}
|
||||
@@ -479,15 +485,39 @@ macro_rules! vpath {
|
||||
///
|
||||
/// The components are interned much like in [sym]
|
||||
#[macro_export]
|
||||
macro_rules! path_slice {
|
||||
($seg1:tt $( :: $seg:tt)+) => {
|
||||
$crate::name::PathSlice::new(&[
|
||||
$crate::intern!(str: stringify!($seg1))
|
||||
$( , $crate::intern!(str: stringify!($seg)) )+
|
||||
])
|
||||
};
|
||||
() => {
|
||||
$crate::name::PathSlice::new(&[])
|
||||
macro_rules! with_path_slice {
|
||||
(@UNIT $tt:tt) => { () };
|
||||
($seg1:tt $( :: $seg:tt)* in $expr:expr) => { {
|
||||
use std::future::Future;
|
||||
use std::ops::Deref as _;
|
||||
use std::pin::Pin;
|
||||
|
||||
const fn count_helper<const N: usize>(_: [(); N]) -> usize { N }
|
||||
|
||||
type Output = [Tok<String>; const {
|
||||
count_helper([() $(, $crate::with_path_slice!(@UNIT $seg))*])
|
||||
}];
|
||||
type InternFuture = Pin<Box<dyn Future<Output = Output>>>;
|
||||
thread_local! {
|
||||
static VALUE: Pin<std::rc::Rc<async_once_cell::Lazy<Output, InternFuture>>> =
|
||||
std::rc::Rc::pin(async_once_cell::Lazy::new(Box::pin(async {
|
||||
[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )+
|
||||
]
|
||||
})));
|
||||
}
|
||||
VALUE.with(|v| $crate::clone!(v; async move {
|
||||
let expr = $expr;
|
||||
let result = v.as_ref().await;
|
||||
let ps: &PathSlice = $crate::name::PathSlice::new(&result.deref()[..]);
|
||||
(expr)(ps).await
|
||||
}))
|
||||
|
||||
} };
|
||||
($expr:expr) => {
|
||||
let expr = $expr;
|
||||
(expr)($crate::name::PathSlice::new(&[]))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,33 +525,45 @@ macro_rules! path_slice {
|
||||
mod test {
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use test_executors::spin_on;
|
||||
|
||||
use super::{PathSlice, Sym, VName};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::name::VPath;
|
||||
|
||||
#[test]
|
||||
fn recur() {
|
||||
let myname = vname!(foo::bar);
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _borrowed_pathslice: &PathSlice = myname.borrow();
|
||||
let _deref_pathslice: &PathSlice = &myname;
|
||||
let _as_slice_out: &[Tok<String>] = myname.as_slice();
|
||||
spin_on(async {
|
||||
let myname = vname!(foo::bar).await;
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _borrowed_pathslice: &PathSlice = myname.borrow();
|
||||
let _deref_pathslice: &PathSlice = &myname;
|
||||
let _as_slice_out: &[Tok<String>] = myname.as_slice();
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn literals() {
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz),
|
||||
Sym::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz),
|
||||
VName::new([intern("foo"), intern("bar"), intern("baz")]).unwrap()
|
||||
);
|
||||
assert_eq!(vpath!(foo::bar::baz), VPath::new([intern("foo"), intern("bar"), intern("baz")]));
|
||||
assert_eq!(
|
||||
path_slice!(foo::bar::baz),
|
||||
PathSlice::new(&[intern("foo"), intern("bar"), intern("baz")])
|
||||
);
|
||||
spin_on(async {
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz).await,
|
||||
Sym::new([intern("foo").await, intern("bar").await, intern("baz").await]).await.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz).await,
|
||||
VName::new([intern("foo").await, intern("bar").await, intern("baz").await]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vpath!(foo::bar::baz).await,
|
||||
VPath::new([intern("foo").await, intern("bar").await, intern("baz").await])
|
||||
);
|
||||
with_path_slice!(foo::bar::baz in |val| async move {
|
||||
assert_eq!(
|
||||
val,
|
||||
PathSlice::new(&[intern("foo").await, intern("bar").await, intern("baz").await])
|
||||
);
|
||||
})
|
||||
.await
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user