forked from Orchid/orchid
Added directfs
Added a very rudimentary file I/O system suitable for experimenting with the language further. A better one will be designed when we have sensible error management.
This commit is contained in:
@@ -5,9 +5,7 @@
|
||||
mod monotype;
|
||||
mod multitype;
|
||||
mod token;
|
||||
// mod traits;
|
||||
|
||||
pub use monotype::TypedInterner;
|
||||
pub use multitype::Interner;
|
||||
pub use token::Tok;
|
||||
// pub use traits::{DisplayBundle, InternedDisplay, InternedInto};
|
||||
|
||||
@@ -15,11 +15,13 @@ pub struct TypedInterner<T: 'static + Eq + Hash + Clone> {
|
||||
}
|
||||
impl<T: Eq + Hash + Clone> TypedInterner<T> {
|
||||
/// Create a fresh interner instance
|
||||
#[must_use]
|
||||
pub fn new() -> Rc<Self> {
|
||||
Rc::new(Self { tokens: RefCell::new(HashMap::new()) })
|
||||
}
|
||||
|
||||
/// Intern an object, returning a token
|
||||
#[must_use]
|
||||
pub fn i<Q: ?Sized + Eq + Hash + ToOwned<Owned = T>>(
|
||||
self: &Rc<Self>,
|
||||
q: &Q,
|
||||
@@ -42,6 +44,7 @@ impl<T: Eq + Hash + Clone> TypedInterner<T> {
|
||||
}
|
||||
|
||||
/// Helper function to compute hashes outside a hashmap
|
||||
#[must_use]
|
||||
fn compute_hash(
|
||||
hash_builder: &impl BuildHasher,
|
||||
key: &(impl Hash + ?Sized),
|
||||
|
||||
@@ -8,7 +8,6 @@ use hashbrown::HashMap;
|
||||
|
||||
use super::monotype::TypedInterner;
|
||||
use super::token::Tok;
|
||||
// use super::InternedDisplay;
|
||||
|
||||
/// A collection of interners based on their type. Allows to intern any object
|
||||
/// that implements [ToOwned]. Objects of the same type are stored together in a
|
||||
@@ -18,9 +17,11 @@ pub struct Interner {
|
||||
}
|
||||
impl Interner {
|
||||
/// Create a new interner
|
||||
#[must_use]
|
||||
pub fn new() -> Self { Self { interners: RefCell::new(HashMap::new()) } }
|
||||
|
||||
/// Intern something
|
||||
#[must_use]
|
||||
pub fn i<Q: ?Sized + Eq + Hash + ToOwned>(&self, q: &Q) -> Tok<Q::Owned>
|
||||
where
|
||||
Q::Owned: 'static + Eq + Hash + Clone + Borrow<Q>,
|
||||
@@ -31,32 +32,10 @@ impl Interner {
|
||||
}
|
||||
|
||||
/// Fully resolve a list of interned things.
|
||||
#[must_use]
|
||||
pub fn extern_all<T: 'static + Eq + Hash + Clone>(s: &[Tok<T>]) -> Vec<T> {
|
||||
s.iter().map(|t| (**t).clone()).collect()
|
||||
}
|
||||
|
||||
// /// A variant of `unwrap` using [InternedDisplay] to circumvent `unwrap`'s
|
||||
// /// dependencyon [Debug]. For clarity, [expect] should be preferred.
|
||||
// pub fn unwrap<T, E: InternedDisplay>(&self, result: Result<T, E>) -> T {
|
||||
// result.unwrap_or_else(|e| {
|
||||
// println!("Unwrapped Error: {}", e.bundle(self));
|
||||
// panic!("Unwrapped an error");
|
||||
// })
|
||||
// }
|
||||
|
||||
// /// A variant of `expect` using [InternedDisplay] to circumvent `expect`'s
|
||||
// /// depeendency on [Debug].
|
||||
// pub fn expect<T, E: InternedDisplay>(
|
||||
// &self,
|
||||
// result: Result<T, E>,
|
||||
// msg: &str,
|
||||
// ) -> T {
|
||||
// result.unwrap_or_else(|e| {
|
||||
// println!("Expectation failed: {msg}");
|
||||
// println!("Error: {}", e.bundle(self));
|
||||
// panic!("Expected an error");
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
impl Default for Interner {
|
||||
@@ -64,6 +43,7 @@ impl Default for Interner {
|
||||
}
|
||||
|
||||
/// Get or create an interner for a given type.
|
||||
#[must_use]
|
||||
fn get_interner<T: 'static + Eq + Hash + Clone>(
|
||||
interners: &mut RefMut<HashMap<TypeId, Rc<dyn Any>>>,
|
||||
) -> Rc<TypedInterner<T>> {
|
||||
|
||||
@@ -18,15 +18,18 @@ pub struct Tok<T: Eq + Hash + Clone + 'static> {
|
||||
}
|
||||
impl<T: Eq + Hash + Clone + 'static> Tok<T> {
|
||||
/// Create a new token. Used exclusively by the interner
|
||||
#[must_use]
|
||||
pub(crate) fn new(data: Rc<T>, interner: Weak<TypedInterner<T>>) -> Self {
|
||||
Self { data, interner }
|
||||
}
|
||||
/// Take the ID number out of a token
|
||||
#[must_use]
|
||||
pub fn id(&self) -> NonZeroUsize {
|
||||
((self.data.as_ref() as *const T as usize).try_into())
|
||||
.expect("Pointer can always be cast to nonzero")
|
||||
}
|
||||
/// Cast into usize
|
||||
#[must_use]
|
||||
pub fn usize(&self) -> usize { self.id().into() }
|
||||
///
|
||||
pub fn assert_comparable(&self, other: &Self) {
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
use core::fmt::{self, Display, Formatter};
|
||||
use core::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::interner::Interner;
|
||||
|
||||
/// A variant of [std::fmt::Display] for objects that contain interned
|
||||
/// strings and therefore can only be stringified in the presence of a
|
||||
/// string interner
|
||||
///
|
||||
/// The functions defined here are suffixed to distinguish them from
|
||||
/// the ones in Display and ToString respectively, because Rust can't
|
||||
/// identify functions based on arity
|
||||
pub trait InternedDisplay {
|
||||
/// formats the value using the given formatter and string interner
|
||||
fn fmt_i(
|
||||
&self,
|
||||
f: &mut std::fmt::Formatter<'_>,
|
||||
i: &Interner,
|
||||
) -> std::fmt::Result;
|
||||
|
||||
/// Converts the value to a string to be displayed
|
||||
fn to_string_i(&self, i: &Interner) -> String {
|
||||
self.bundle(i).to_string()
|
||||
}
|
||||
|
||||
/// Combine with an interner to implement [Display]
|
||||
fn bundle<'a>(&'a self, interner: &'a Interner) -> DisplayBundle<'a, Self> {
|
||||
DisplayBundle { interner, data: self }
|
||||
}
|
||||
}
|
||||
|
||||
// Special loophole for Rc<dyn ProjectError>
|
||||
impl<T: ?Sized> InternedDisplay for Rc<T>
|
||||
where
|
||||
T: InternedDisplay,
|
||||
{
|
||||
fn fmt_i(&self, f: &mut Formatter<'_>, i: &Interner) -> fmt::Result {
|
||||
self.deref().fmt_i(f, i)
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference to an [InternedDisplay] type and an [Interner] tied together
|
||||
/// to implement [Display]
|
||||
pub struct DisplayBundle<'a, T: InternedDisplay + ?Sized> {
|
||||
interner: &'a Interner,
|
||||
data: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T: InternedDisplay + ?Sized> Display for DisplayBundle<'a, T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.data.fmt_i(f, self.interner)
|
||||
}
|
||||
}
|
||||
|
||||
/// Conversions that are possible in the presence of an interner
|
||||
///
|
||||
/// Essentially, this allows to define abstractions over interned and
|
||||
/// non-interned versions of a type and convert between them
|
||||
pub trait InternedInto<U> {
|
||||
/// Execute the conversion
|
||||
fn into_i(self, i: &Interner) -> U;
|
||||
}
|
||||
|
||||
impl<T: Into<U>, U> InternedInto<U> for T {
|
||||
fn into_i(self, _i: &Interner) -> U {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user