Almost Alpha

Massive improvements across the board.

One day I'll adopt incremental commits.
This commit is contained in:
2024-02-23 23:59:24 +00:00
parent c279301583
commit ed0d64d52e
147 changed files with 4121 additions and 4203 deletions

View File

@@ -1,45 +1,123 @@
//! Various datatypes that all represent namespaced names.
use std::borrow::Borrow;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::iter::Cloned;
use std::num::NonZeroUsize;
use std::ops::Index;
use std::vec;
use std::ops::{Deref, Index};
use std::path::Path;
use std::{fmt, slice, vec};
use intern_all::{i, Tok};
use itertools::Itertools;
use trait_set::trait_set;
use crate::utils::boxed_iter::BoxedIter;
trait_set! {
/// Traits that all name iterators should implement
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
}
/// A borrowed name fragment which can be empty. See [VPath] for the owned
/// variant.
pub struct PathSlice<'a>(pub &'a [Tok<String>]);
impl<'a> PathSlice<'a> {
#[derive(Hash, PartialEq, Eq)]
#[repr(transparent)]
pub struct PathSlice([Tok<String>]);
impl PathSlice {
/// Create a new [PathSlice]
pub fn new(slice: &[Tok<String>]) -> &PathSlice {
// SAFETY: This is ok because PathSlice is #[repr(transparent)]
unsafe { &*(slice as *const [Tok<String>] as *const PathSlice) }
}
/// Convert to an owned name fragment
pub fn to_vpath(&self) -> VPath { VPath(self.0.to_vec()) }
/// Iterate over the tokens
pub fn iter(&self) -> impl NameIter + '_ { self.into_iter() }
/// Iterate over the segments
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
Box::new(self.0.iter().map(|s| s.as_str()))
}
}
impl<'a> Debug for PathSlice<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "VName({self})")
/// Find the longest shared prefix of this name and another sequence
pub fn coprefix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count()]
}
/// Find the longest shared suffix of this name and another sequence
pub fn cosuffix<'a>(&'a self, other: &PathSlice) -> &'a PathSlice {
&self[0..self.iter().zip(other.iter()).take_while(|(l, r)| l == r).count()]
}
/// Remove another
pub fn strip_prefix<'a>(&'a self, other: &PathSlice) -> Option<&'a PathSlice> {
let shared = self.coprefix(other).len();
(shared == other.len()).then_some(PathSlice::new(&self[shared..]))
}
/// 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 }
/// Obtain a reference to the held slice. With all indexing traits shadowed,
/// this is better done explicitly
pub fn as_slice(&self) -> &[Tok<String>] { self }
/// Global empty path slice
pub fn empty() -> &'static Self { PathSlice::new(&[]) }
}
impl<'a> Display for PathSlice<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Debug for PathSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
}
impl fmt::Display for PathSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
impl<'a> Borrow<[Tok<String>]> for PathSlice<'a> {
fn borrow(&self) -> &[Tok<String>] { self.0 }
impl Borrow<[Tok<String>]> for PathSlice {
fn borrow(&self) -> &[Tok<String>] { &self.0 }
}
impl<'a> IntoIterator for &'a PathSlice {
type IntoIter = Cloned<slice::Iter<'a, Tok<String>>>;
type Item = Tok<String>;
fn into_iter(self) -> Self::IntoIter { self.0.iter().cloned() }
}
impl<'a, T> Index<T> for PathSlice<'a>
where [Tok<String>]: Index<T>
{
type Output = <[Tok<String>] as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.0[index] }
mod idx_impls {
use std::ops;
use intern_all::Tok;
use super::PathSlice;
impl ops::Index<usize> for PathSlice {
type Output = Tok<String>;
fn index(&self, index: usize) -> &Self::Output { &self.0[index] }
}
macro_rules! impl_range_index_for_pathslice {
($range:ty) => {
impl ops::Index<$range> for PathSlice {
type Output = Self;
fn index(&self, index: $range) -> &Self::Output { Self::new(&self.0[index]) }
}
};
}
impl_range_index_for_pathslice!(ops::RangeFull);
impl_range_index_for_pathslice!(ops::RangeFrom<usize>);
impl_range_index_for_pathslice!(ops::RangeTo<usize>);
impl_range_index_for_pathslice!(ops::Range<usize>);
impl_range_index_for_pathslice!(ops::RangeInclusive<usize>);
impl_range_index_for_pathslice!(ops::RangeToInclusive<usize>);
}
impl Deref for PathSlice {
type Target = [Tok<String>];
fn deref(&self) -> &Self::Target { &self.0 }
}
impl Borrow<PathSlice> for [Tok<String>] {
fn borrow(&self) -> &PathSlice { PathSlice::new(self) }
}
impl<const N: usize> Borrow<PathSlice> for [Tok<String>; N] {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
}
impl Borrow<PathSlice> for Vec<Tok<String>> {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self[..]) }
}
/// A token path which may be empty. [VName] is the non-empty,
@@ -51,6 +129,11 @@ impl VPath {
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> 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 {
Self(items.into_iter().chain(self.0).collect())
@@ -71,22 +154,30 @@ impl VPath {
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 as_prefix_of(self, name: Tok<String>) -> VName {
pub fn name_with_prefix(self, name: Tok<String>) -> 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 as_suffix_of(self, name: Tok<String>) -> VName {
pub fn name_with_suffix(self, name: Tok<String>) -> VName {
VName([name].into_iter().chain(self).collect())
}
}
impl Debug for VPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "VName({self})")
/// 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(i)).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(_) => None,
}
}
}
impl Display for VPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Debug for VPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
}
impl fmt::Display for VPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
@@ -103,13 +194,20 @@ impl IntoIterator for VPath {
impl Borrow<[Tok<String>]> for VPath {
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
}
impl Borrow<PathSlice> for VPath {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
}
impl Deref for VPath {
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
}
impl<T> Index<T> for VPath
where Vec<Tok<String>>: Index<T>
where PathSlice: Index<T>
{
type Output = <Vec<Tok<String>> as Index<T>>::Output;
type Output = <PathSlice as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.0[index] }
fn index(&self, index: T) -> &Self::Output { &Borrow::<PathSlice>::borrow(self)[index] }
}
/// A mutable representation of a namespaced identifier of at least one segment.
@@ -123,9 +221,7 @@ pub struct VName(Vec<Tok<String>>);
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 = Tok<String>>) -> Result<Self, EmptyNameError> {
let data: Vec<_> = items.into_iter().collect();
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
}
@@ -138,20 +234,8 @@ impl VName {
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(i(&self.0)) }
/// like Slice's split_first, but non-optional and tokens are cheap to clone
pub fn split_first(&self) -> (Tok<String>, &[Tok<String>]) {
let (h, t) = self.0.split_first().expect("VName can never be empty");
(h.clone(), t)
}
/// like Slice's split_last, but non-optional and tokens are cheap to clone
pub fn split_last(&self) -> (Tok<String>, &[Tok<String>]) {
let (f, b) = self.0.split_last().expect("VName can never be empty");
(f.clone(), b)
}
/// 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<Tok<String>> { 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 {
@@ -163,33 +247,15 @@ 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))
}
/// Read a name from a string literal which can be known not to be empty
pub fn literal(s: &'static str) -> Self {
Self::parse(s).expect("name literal should not be empty")
}
/// Find the longest shared prefix of this name and another sequence
pub fn coprefix(&self, other: &[Tok<String>]) -> &[Tok<String>] {
&self.0
[0..self.0.iter().zip(other.iter()).take_while(|(l, r)| l == r).count()]
}
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s)) }
/// Obtain an iterator over the segments of the name
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ {
self.0.iter().cloned()
}
/// Convert to [PathSlice]
pub fn as_path_slice(&self) -> PathSlice { PathSlice(&self[..]) }
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ { self.0.iter().cloned() }
}
impl Debug for VName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "VName({self})")
}
impl fmt::Debug for VName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
}
impl Display for VName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for VName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
@@ -199,15 +265,22 @@ impl IntoIterator for VName {
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
impl<T> Index<T> for VName
where Vec<Tok<String>>: Index<T>
where PathSlice: Index<T>
{
type Output = <Vec<Tok<String>> as Index<T>>::Output;
type Output = <PathSlice as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &self.0[index] }
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<PathSlice> for VName {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
}
impl Deref for VName {
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
}
/// Error produced when a non-empty name [VName] or [Sym] is constructed with an
/// empty sequence
@@ -230,23 +303,12 @@ 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 fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
let items = v.into_iter().collect::<Vec<_>>();
Self::from_tok(i(&items))
}
/// Read a `::` separated namespaced name.
pub fn parse(s: &str) -> Result<Self, EmptyNameError> {
Ok(Sym(i(&VName::parse(s)?.into_vec())))
}
/// Parse a string and panic if it's not empty
pub fn literal(s: &'static str) -> Self {
Self::parse(s).expect("name literal should not be empty")
}
pub fn parse(s: &str) -> Result<Self, EmptyNameError> { Ok(Sym(i(&VName::parse(s)?.into_vec()))) }
/// 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> {
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
@@ -255,80 +317,160 @@ impl Sym {
pub fn tok(&self) -> Tok<Vec<Tok<String>>> { self.0.clone() }
/// Get a number unique to this name suitable for arbitrary ordering.
pub fn id(&self) -> NonZeroUsize { self.0.id() }
/// Get an iterator over the tokens in this name
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ {
self.0.iter().cloned()
}
/// Like Slice's split_last, except this slice is never empty
pub fn split_last(&self) -> (Tok<String>, PathSlice) {
let (foot, torso) = self.0.split_last().expect("Sym never empty");
(foot.clone(), PathSlice(torso))
}
/// Like Slice's split_first, except this slice is never empty
pub fn split_first(&self) -> (Tok<String>, PathSlice) {
let (head, tail) = self.0.split_first().expect("Sym never empty");
(head.clone(), PathSlice(tail))
}
/// Extern the sym for editing
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
/// Convert to [PathSlice]
pub fn as_path_slice(&self) -> PathSlice { PathSlice(&self[..]) }
}
impl Debug for Sym {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Sym({self})")
}
impl fmt::Debug for Sym {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sym({self})") }
}
impl Display for Sym {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for Sym {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.str_iter().join("::"))
}
}
impl<T> Index<T> for Sym
where Vec<Tok<String>>: Index<T>
where PathSlice: Index<T>
{
type Output = <Vec<Tok<String>> as Index<T>>::Output;
type Output = <PathSlice as Index<T>>::Output;
fn index(&self, index: T) -> &Self::Output { &(&*self.0)[index] }
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
}
impl Borrow<[Tok<String>]> for Sym {
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
}
impl Borrow<PathSlice> for Sym {
fn borrow(&self) -> &PathSlice { PathSlice::new(&self.0[..]) }
}
impl Deref for Sym {
type Target = PathSlice;
fn deref(&self) -> &Self::Target { self.borrow() }
}
/// An abstraction over tokenized vs non-tokenized names so that they can be
/// 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 + Debug + Display {
pub trait NameLike:
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<PathSlice>
{
/// Convert into held slice
fn as_slice(&self) -> &[Tok<String>] { Borrow::<PathSlice>::borrow(self) }
/// Get iterator over tokens
fn iter(&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())
}
/// Fully resolve the name for printing
#[must_use]
fn to_strv(&self) -> Vec<String> {
self.str_iter().map(str::to_owned).collect()
}
fn to_strv(&self) -> Vec<String> { self.iter().map(|s| s.to_string()).collect() }
/// Format the name as an approximate filename
fn as_src_path(&self) -> String {
format!("{}.orc", self.str_iter().join("/"))
}
fn as_src_path(&self) -> String { format!("{}.orc", self.iter().join("/")) }
/// Return the number of segments in the name
fn len(&self) -> NonZeroUsize {
NonZeroUsize::try_from(self.str_iter().count())
.expect("NameLike never empty")
NonZeroUsize::try_from(self.iter().count()).expect("NameLike never empty")
}
/// Fully resolve the name for printing
fn str_iter(&self) -> BoxedIter<'_, &str>;
/// Like slice's `split_first` except we know that it always returns Some
fn split_first(&self) -> (Tok<String>, &PathSlice) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), PathSlice::new(torso))
}
/// Like slice's `split_last` except we know that it always returns Some
fn split_last(&self) -> (Tok<String>, &PathSlice) {
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
(foot.clone(), PathSlice::new(torso))
}
/// Get the first element
fn first(&self) -> Tok<String> { self.split_first().0 }
/// Get the last element
fn last(&self) -> Tok<String> { self.split_last().0 }
}
impl NameLike for Sym {
fn str_iter(&self) -> BoxedIter<'_, &str> {
Box::new(self.0.iter().map(|s| s.as_str()))
impl NameLike for Sym {}
impl NameLike for VName {}
/// Create a [Sym] literal.
///
/// Both the name and its components will be cached in a thread-local static so
/// that subsequent executions of the expression only incur an Arc-clone for
/// cloning the token.
#[macro_export]
macro_rules! sym {
($seg1:tt $( :: $seg:tt)*) => {
$crate::name::Sym::from_tok(intern_all::i!([intern_all::Tok<String>]: &[
intern_all::i!(str: stringify!($seg1))
$( , intern_all::i!(str: stringify!($seg)) )*
][..])).unwrap()
};
}
/// Create a [VName] literal.
///
/// The components are interned much like in [sym].
#[macro_export]
macro_rules! vname {
($seg1:tt $( :: $seg:tt)*) => {
$crate::name::VName::new([
intern_all::i!(str: stringify!($seg1))
$( , intern_all::i!(str: stringify!($seg)) )*
]).unwrap()
};
}
/// Create a [VPath] literal.
///
/// The components are interned much like in [sym].
#[macro_export]
macro_rules! vpath {
($seg1:tt $( :: $seg:tt)+) => {
$crate::name::VPath(vec![
intern_all::i!(str: stringify!($seg1))
$( , intern_all::i!(str: stringify!($seg)) )+
])
};
() => {
$crate::name::VPath(vec![])
}
}
impl NameLike for VName {
fn str_iter(&self) -> BoxedIter<'_, &str> {
Box::new(self.0.iter().map(|s| s.as_str()))
/// Create a &[PathSlice] literal.
///
/// The components are interned much like in [sym]
#[macro_export]
macro_rules! path_slice {
($seg1:tt $( :: $seg:tt)+) => {
$crate::name::PathSlice::new(&[
intern_all::i!(str: stringify!($seg1))
$( , intern_all::i!(str: stringify!($seg)) )+
])
};
() => {
$crate::name::PathSlice::new(&[])
}
}
#[cfg(test)]
mod test {
use std::borrow::Borrow;
use intern_all::{i, Tok};
use super::{PathSlice, Sym, VName};
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();
}
#[test]
fn literals() {
assert_eq!(sym!(foo::bar::baz), Sym::new([i("foo"), i("bar"), i("baz")]).unwrap());
assert_eq!(vname!(foo::bar::baz), VName::new([i("foo"), i("bar"), i("baz")]).unwrap());
assert_eq!(vpath!(foo::bar::baz), VPath::new([i("foo"), i("bar"), i("baz")]));
assert_eq!(path_slice!(foo::bar::baz), PathSlice::new(&[i("foo"), i("bar"), i("baz")]));
}
}