mers/mers_lib/src/data/mod.rs

388 lines
12 KiB
Rust
Raw Normal View History

2023-07-28 00:33:15 +02:00
use std::{
any::Any,
fmt::{Debug, Display},
2023-08-14 17:17:08 +02:00
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
2023-07-28 00:33:15 +02:00
};
pub mod bool;
pub mod float;
pub mod function;
pub mod int;
pub mod reference;
pub mod string;
pub mod tuple;
pub mod defs;
2023-08-14 17:17:08 +02:00
pub trait MersData: Any + Debug + Display + Send + Sync {
2023-07-28 00:33:15 +02:00
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
None
}
/// By default, uses `iterable` to get an iterator and `nth` to retrieve the nth element.
/// Should have a custom implementation for better performance on most types
fn get(&self, i: usize) -> Option<Data> {
self.iterable()?.nth(i)
}
2023-08-14 17:17:08 +02:00
/// If self and other are different types (`other.as_any().downcast_ref::<Self>().is_none()`),
/// this *must* return false.
fn is_eq(&self, other: &dyn MersData) -> bool;
2023-07-28 00:33:15 +02:00
fn clone(&self) -> Box<dyn MersData>;
2023-08-14 17:17:08 +02:00
fn as_type(&self) -> Type;
2023-07-28 00:33:15 +02:00
fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>;
}
2023-08-14 17:17:08 +02:00
pub trait MersType: Any + Debug + Display + Send + Sync {
2023-07-28 00:33:15 +02:00
/// If Some(T), calling `iterable` on the MersData this MersType belongs to
/// Should return Some(I), where I is an Iterator which only returns items of type T.
fn iterable(&self) -> Option<Type> {
None
}
/// If Some(T), calling `get` on data of this type may return T, but it might also return None.
/// By default, this returns the same thing as `iterable`, since this is also the default implementation for `MersData::get`.
fn get(&self) -> Option<Type> {
self.iterable()
}
/// If self and other are different types (`other.as_any().downcast_ref::<Self>().is_none()`),
/// this *must* return false.
fn is_same_type_as(&self, other: &dyn MersType) -> bool;
/// This doesn't handle the case where target is Type (is_included_in handles it)
fn is_included_in_single(&self, target: &dyn MersType) -> bool;
fn is_included_in(&self, target: &dyn MersType) -> bool {
if let Some(target) = target.as_any().downcast_ref::<Type>() {
target
.types
.iter()
.any(|t| self.is_included_in_single(t.as_ref()))
} else {
self.is_included_in_single(target)
}
}
/// Returns all types that can result from the use of this type.
/// Usually, this is just `acc.add(Arc::new(self.clone()))`
/// but if there exists one or more inner types, this becomes interesting:
/// Using `(int/string)` will end up being either `(int)` or `(string)`,
/// so this function should add `(int)` and `(string)`.
/// Since `(int/string)` can't exist at runtime, we don't need to list `self`.
/// note also: `subtypes` has to be called recursively, i.e. you would have to call `.substring` on `int` and `string`.
fn subtypes(&self, acc: &mut Type);
/// like `subtypes`, but returns the accumulator
fn subtypes_type(&self) -> Type {
let mut acc = Type::empty();
self.subtypes(&mut acc);
acc
}
2023-07-28 00:33:15 +02:00
fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>;
2023-08-14 17:17:08 +02:00
fn is_reference_to(&self) -> Option<&Type> {
None
}
2023-07-28 00:33:15 +02:00
}
#[derive(Debug)]
pub struct Data {
2023-08-14 17:17:08 +02:00
is_mut: bool,
counts: Arc<(AtomicUsize, AtomicUsize)>,
2023-07-28 00:33:15 +02:00
pub data: Arc<RwLock<Box<dyn MersData>>>,
}
impl Data {
pub fn new<T: MersData>(data: T) -> Self {
2023-08-14 17:17:08 +02:00
Self::new_boxed(Box::new(data), true)
2023-07-28 00:33:15 +02:00
}
2023-08-14 17:17:08 +02:00
pub fn new_boxed(data: Box<dyn MersData>, is_mut: bool) -> Self {
2023-07-28 00:33:15 +02:00
Self {
2023-08-14 17:17:08 +02:00
is_mut,
counts: Arc::new((
AtomicUsize::new(if is_mut { 0 } else { 1 }),
AtomicUsize::new(if is_mut { 1 } else { 0 }),
)),
2023-07-28 00:33:15 +02:00
data: Arc::new(RwLock::new(data)),
}
}
pub fn empty_tuple() -> Self {
Self::new(tuple::Tuple(vec![]))
}
pub fn one_tuple(v: Self) -> Self {
Self::new(tuple::Tuple(vec![v]))
}
2023-08-14 17:17:08 +02:00
/// Returns true if self is `()`.
pub fn is_zero_tuple(&self) -> bool {
if let Some(tuple) = self
.get()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>()
{
tuple.0.is_empty()
} else {
false
}
}
/// Returns `Some(d)` if and only if self is `(d)`.
pub fn one_tuple_content(&self) -> Option<Data> {
if let Some(data) = self
.get()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>()
.filter(|v| v.len() == 1)
.and_then(|v| v.get(0))
{
Some(data.clone())
} else {
None
}
}
2023-07-28 00:33:15 +02:00
pub fn get(&self) -> RwLockReadGuard<Box<dyn MersData>> {
2023-08-14 17:17:08 +02:00
#[cfg(debug_assertions)]
eprintln!("[mers:data:cow] get");
2023-07-28 00:33:15 +02:00
self.data.read().unwrap()
}
2023-08-14 17:17:08 +02:00
pub fn get_mut_unchecked(&self) -> RwLockWriteGuard<Box<dyn MersData>> {
2023-07-28 00:33:15 +02:00
self.data.write().unwrap()
}
2023-08-14 17:17:08 +02:00
pub fn try_get_mut(&self) -> Option<RwLockWriteGuard<Box<dyn MersData>>> {
if self.is_mut && self.counts.0.load(std::sync::atomic::Ordering::Relaxed) == 0 {
Some(self.get_mut_unchecked())
} else {
None
}
}
/// like try_get_mut, but instead of returning `None` this function `get()`s the data and clones it.
/// When cloning data, this transforms `self` into a `Data` with `is_mut: true`, hence the `&mut self` parameter.
pub fn get_mut(&mut self) -> RwLockWriteGuard<Box<dyn MersData>> {
if self.try_get_mut().is_none() {
#[cfg(debug_assertions)]
eprintln!(
"[mers:data:cow] cloning! get_mut called on {}",
if !self.is_mut {
"non-mut value"
} else {
"value with immut references"
}
);
let val = self.get().clone();
*self = Self::new_boxed(val, true);
}
self.get_mut_unchecked()
}
pub fn mkref(&self) -> Self {
if self.is_mut {
self.counts
.1
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Self {
is_mut: true,
counts: Arc::clone(&self.counts),
data: Arc::clone(&self.data),
}
} else {
#[cfg(debug_assertions)]
eprintln!("[mers:data:cow] cloning! mkref called on immutable data");
Self::new_boxed(self.data.read().unwrap().clone(), true)
}
}
2023-07-28 00:33:15 +02:00
}
impl Clone for Data {
fn clone(&self) -> Self {
2023-08-14 17:17:08 +02:00
self.counts
.0
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2023-07-28 00:33:15 +02:00
Self {
2023-08-14 17:17:08 +02:00
is_mut: false,
counts: Arc::clone(&self.counts),
2023-07-28 00:33:15 +02:00
data: Arc::clone(&self.data),
}
}
}
2023-08-14 17:17:08 +02:00
impl Drop for Data {
fn drop(&mut self) {
if self.is_mut {
&self.counts.1
} else {
&self.counts.0
}
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
}
}
impl PartialEq for Data {
fn eq(&self, other: &Self) -> bool {
self.get().is_eq(other.get().as_ref())
}
}
2023-07-28 00:33:15 +02:00
#[derive(Clone, Debug)]
pub struct Type {
// TODO: Maybe make sure this is always sorted by (recursive?!?) TypeId,
// that way is_same_type_as can work more efficiently (cuz good code but also branch prediction)
2023-08-14 17:17:08 +02:00
pub types: Vec<Arc<dyn MersType>>,
2023-07-28 00:33:15 +02:00
}
impl Type {
pub fn new<T: MersType>(t: T) -> Self {
Self {
types: vec![Arc::new(t)],
}
}
pub fn newm(types: Vec<Arc<dyn MersType>>) -> Self {
Self { types }
}
2023-08-14 17:17:08 +02:00
pub fn empty() -> Self {
Self { types: vec![] }
}
2023-07-28 00:33:15 +02:00
pub fn empty_tuple() -> Self {
Self::new(tuple::TupleT(vec![]))
}
2023-08-14 17:17:08 +02:00
/// Returns true if self is `()`.
pub fn is_zero_tuple(&self) -> bool {
let mut o = false;
for t in &self.types {
o = true;
if let Some(tuple) = t.as_any().downcast_ref::<crate::data::tuple::TupleT>() {
if !tuple.0.is_empty() {
return false;
}
} else {
return false;
}
}
o
}
/// Returns `Some(d)` if and only if self is `(d)`.
pub fn one_tuple_content(&self) -> Option<Type> {
let mut o = Self::empty();
for t in &self.types {
if let Some(t) = t
.as_any()
.downcast_ref::<crate::data::tuple::TupleT>()
.filter(|v| v.0.len() == 1)
.and_then(|v| v.0.get(0))
{
o.add(Arc::new(t.clone()));
} else {
return None;
}
}
Some(o)
}
2023-10-27 17:09:48 +02:00
/// Returns `Some(d)` if self is `()/(d)`
pub fn one_tuple_possible_content(&self) -> Option<Type> {
let mut o = Self::empty();
let mut nothing = true;
for t in &self.types {
if let Some(t) = t
.as_any()
.downcast_ref::<crate::data::tuple::TupleT>()
.filter(|v| v.0.len() == 1)
.and_then(|v| v.0.get(0))
{
nothing = false;
o.add(Arc::new(t.clone()));
}
}
if nothing {
None
} else {
Some(o)
}
}
2023-08-14 17:17:08 +02:00
pub fn add(&mut self, new: Arc<dyn MersType>) {
let n = new.as_any();
if let Some(s) = n.downcast_ref::<Self>() {
for t in &s.types {
self.add(Arc::clone(t));
}
} else {
2023-10-19 18:46:15 +02:00
if !self.types.iter().any(|t| new.is_included_in(t.as_ref())) {
self.types.push(new);
}
2023-08-14 17:17:08 +02:00
}
}
pub fn dereference(&self) -> Option<Self> {
let mut o = Self::empty();
for t in &self.types {
if let Some(t) = t.is_reference_to() {
o.add(Arc::new(t.clone()));
} else {
return None;
}
}
Some(o)
2023-07-28 00:33:15 +02:00
}
}
// PROBLEM:
// [int, int]/[int, string]/[string, int]/[string, string]
// is the same type as [int/string, int/string],
// but [int, int]/[int, string]/[string int] isn't.
// somehow, we need to merge these into the simplest form (same outer type, inner types differ)
// before we can implement `Type`
// idea: pick all the ones with the same first type: [int, int]/[int, string] and [string, int]/[string, string]
// then repeat with the second type if possible (here not, but for longer tuples, probably?)
// merge the last existing type in all the collections until we reach the first type again or the last types aren't equal anymore (how to check????)
impl MersType for Type {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
2023-10-27 19:19:29 +02:00
// TODO! improve
self.is_included_in(other) && other.is_included_in(self)
2023-07-28 00:33:15 +02:00
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
2023-08-14 17:17:08 +02:00
self.types.iter().all(|t| t.is_included_in_single(target))
2023-07-28 00:33:15 +02:00
}
fn subtypes(&self, acc: &mut Type) {
for t in &self.types {
t.subtypes(acc);
}
}
2023-07-28 00:33:15 +02:00
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
2023-08-14 17:17:08 +02:00
fn iterable(&self) -> Option<Type> {
let mut o = Self::empty();
for t in self.types.iter() {
if let Some(t) = t.iterable() {
o.add(Arc::new(t));
} else {
return None;
}
}
Some(o)
}
fn get(&self) -> Option<Type> {
let mut o = Self::empty();
for t in self.types.iter() {
if let Some(t) = t.get() {
o.add(Arc::new(t));
} else {
return None;
}
}
Some(o)
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.types.is_empty() {
write!(f, "<unreachable>")
} else {
if self.types.len() > 1 {
write!(f, "{{")?;
}
write!(f, "{}", self.types[0])?;
for t in self.types.iter().skip(1) {
write!(f, "/{t}")?;
}
if self.types.len() > 1 {
write!(f, "}}")?;
}
Ok(())
}
}
2023-07-28 00:33:15 +02:00
}