use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
pub use prolangkit_macros::*;
pub struct Id<T: ?Sized>(u32, PhantomData<fn() -> T>);
impl<T: ?Sized> Debug for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Id").field(&self.0).finish()
}
}
impl<T: ?Sized> Clone for Id<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Id<T> {}
impl<T: ?Sized> Hash for Id<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: ?Sized> PartialEq for Id<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: ?Sized> Eq for Id<T> {}
impl<T: ?Sized> PartialOrd for Id<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: ?Sized> Ord for Id<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<T: ?Sized> Id<T> {
pub fn new(index: usize) -> Self {
Self(index.try_into().unwrap(), PhantomData)
}
pub fn index(self) -> usize {
usize::try_from(self.0).unwrap()
}
}
pub struct Arena<T> {
values: Vec<T>,
}
impl<T> Default for Arena<T> {
fn default() -> Self {
Self { values: Default::default() }
}
}
impl<T> Arena<T> {
pub fn get(&self, id: Id<T>) -> &T {
self.values.get(id.index()).unwrap()
}
pub fn get_mut(&mut self, id: Id<T>) -> &mut T {
self.values.get_mut(id.index()).unwrap()
}
pub fn insert(&mut self, value: T) -> Id<T> {
let id = Id::new(self.values.len());
self.values.push(value);
id
}
}
pub struct Mapping<K, V> {
values: HashMap<Id<K>, V>,
}
impl<K, V> Default for Mapping<K, V> {
fn default() -> Self {
Self { values: Default::default() }
}
}
impl<K, V> Mapping<K, V> {
pub fn get(&self, id: Id<K>) -> Option<&V> {
self.values.get(&id)
}
pub fn get_mut(&mut self, id: Id<K>) -> Option<&mut V> {
self.values.get_mut(&id)
}
pub fn insert(&mut self, id: Id<K>, value: V) -> &mut V {
self.values.insert(id, value);
self.values.get_mut(&id).unwrap()
}
}
#[derive(Default)]
pub struct StringStore {
lookup: BTreeMap<String, Id<str>>,
ids: Vec<(usize, usize)>,
strings: String,
}
impl StringStore {
pub fn get(&self, id: Id<str>) -> &str {
let (start, end) = self.ids.get(id.index()).copied().unwrap();
&self.strings[start..end]
}
pub fn get_mut(&mut self, id: Id<str>) -> &mut str {
let (start, end) = self.ids.get(id.index()).copied().unwrap();
&mut self.strings[start..end]
}
pub fn insert(&mut self, value: &str) -> Id<str> {
if let Some(id) = self.lookup.get(value) {
return *id;
}
let start = self.strings.len();
let end = start + value.len();
self.strings.push_str(value);
let id = Id::new(self.ids.len());
self.ids.push((start, end));
self.lookup.insert(value.to_string(), id);
id
}
}