egglog_core_relations/base_values/
mod.rs1use std::{
4 any::{Any, TypeId},
5 fmt::{self, Debug},
6 hash::Hash,
7};
8
9use crate::numeric_id::{DenseIdMap, NumericId, define_id};
10
11use crate::common::{HashMap, InternTable, Value};
12
13#[cfg(test)]
14mod tests;
15mod unboxed;
16
17define_id!(pub BaseValueId, u32, "an identifier for base value types");
18
19pub trait BaseValue: Clone + Hash + Eq + Any + Debug + Send + Sync {
29 const MAY_UNBOX: bool = false;
30 fn intern(&self, table: &InternTable<Self, Value>) -> Value {
31 table.intern(self)
32 }
33 fn as_any(&self) -> &dyn Any {
34 self
35 }
36 fn try_box(&self) -> Option<Value> {
37 None
38 }
39 fn try_unbox(_val: Value) -> Option<Self> {
40 None
41 }
42}
43
44impl BaseValue for String {}
45impl BaseValue for &'static str {}
46impl BaseValue for num::Rational64 {}
47
48pub struct BaseValuePrinter<'a> {
53 pub base: &'a BaseValues,
54 pub ty: BaseValueId,
55 pub val: Value,
56}
57
58impl Debug for BaseValuePrinter<'_> {
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 self.base.tables[self.ty].print_value(self.val, f)
61 }
62}
63
64#[derive(Clone, Default)]
66pub struct BaseValues {
67 type_ids: HashMap<TypeId, BaseValueId>,
68 tables: DenseIdMap<BaseValueId, Box<dyn DynamicInternTable>>,
69}
70
71impl BaseValues {
72 pub fn register_type<P: BaseValue>(&mut self) -> BaseValueId {
74 let type_id = TypeId::of::<P>();
75 let next_id = BaseValueId::from_usize(self.type_ids.len());
76 let id = *self.type_ids.entry(type_id).or_insert(next_id);
77 self.tables
78 .get_or_insert(id, || Box::<BaseInternTable<P>>::default());
79 id
80 }
81
82 pub fn get_ty<P: BaseValue>(&self) -> BaseValueId {
84 self.type_ids[&TypeId::of::<P>()]
85 }
86
87 pub fn get_ty_by_id(&self, id: TypeId) -> BaseValueId {
89 self.type_ids[&id]
90 }
91
92 pub fn get<P: BaseValue>(&self, p: P) -> Value {
94 if P::MAY_UNBOX {
95 if let Some(v) = p.try_box() {
96 return v;
97 }
98 }
99 let id = self.get_ty::<P>();
100 let table = self.tables[id]
101 .as_any()
102 .downcast_ref::<BaseInternTable<P>>()
103 .unwrap();
104 table.intern(p)
105 }
106
107 pub fn unwrap<P: BaseValue>(&self, v: Value) -> P {
109 if P::MAY_UNBOX {
110 if let Some(p) = P::try_unbox(v) {
111 return p;
112 }
113 }
114 let id = self.get_ty::<P>();
115 let table = self
116 .tables
117 .get(id)
118 .expect("types must be registered before unwrapping")
119 .as_any()
120 .downcast_ref::<BaseInternTable<P>>()
121 .unwrap();
122 table.get(v)
123 }
124}
125
126trait DynamicInternTable: Any + dyn_clone::DynClone + Send + Sync {
127 fn as_any(&self) -> &dyn Any;
128 fn print_value(&self, val: Value, f: &mut fmt::Formatter) -> fmt::Result;
129}
130
131dyn_clone::clone_trait_object!(DynamicInternTable);
133
134#[derive(Clone)]
135struct BaseInternTable<P> {
136 table: InternTable<P, Value>,
137}
138
139impl<P> Default for BaseInternTable<P> {
140 fn default() -> Self {
141 Self {
142 table: InternTable::default(),
143 }
144 }
145}
146
147impl<P: BaseValue> DynamicInternTable for BaseInternTable<P> {
148 fn as_any(&self) -> &dyn Any {
149 self
150 }
151
152 fn print_value(&self, val: Value, f: &mut fmt::Formatter) -> fmt::Result {
153 let p = self.get(val);
154 write!(f, "{p:?}")
155 }
156}
157
158const VAL_OFFSET: u32 = 1 << (std::mem::size_of::<Value>() as u32 * 8 - 1);
159
160impl<P: BaseValue> BaseInternTable<P> {
161 pub fn intern(&self, p: P) -> Value {
162 if P::MAY_UNBOX {
163 p.try_box().unwrap_or_else(|| {
164 Value::new(
168 self.table
169 .intern(&p)
170 .rep()
171 .checked_add(VAL_OFFSET)
172 .expect("interned value overflowed"),
173 )
174 })
175 } else {
176 self.table.intern(&p)
177 }
178 }
179
180 pub fn get(&self, v: Value) -> P {
181 if P::MAY_UNBOX {
182 P::try_unbox(v)
183 .unwrap_or_else(|| self.table.get_cloned(Value::new(v.rep() - VAL_OFFSET)))
184 } else {
185 self.table.get_cloned(v)
186 }
187 }
188}
189
190#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
197pub struct Boxed<T>(pub T);
198
199impl<T> Boxed<T> {
200 pub fn new(value: T) -> Self {
201 Boxed(value)
202 }
203
204 pub fn into_inner(self) -> T {
205 self.0
206 }
207}
208
209impl<T: Debug> Debug for Boxed<T> {
210 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211 write!(f, "{:?}", self.0)
212 }
213}
214
215impl<T: Hash + Eq + Debug + Clone + Send + Sync + 'static> BaseValue for Boxed<T> {}
216
217impl<T> std::ops::Deref for Boxed<T> {
218 type Target = T;
219
220 fn deref(&self) -> &Self::Target {
221 &self.0
222 }
223}
224
225impl<T> std::ops::DerefMut for Boxed<T> {
226 fn deref_mut(&mut self) -> &mut Self::Target {
227 &mut self.0
228 }
229}
230
231impl<T> From<T> for Boxed<T> {
232 fn from(value: T) -> Self {
233 Boxed(value)
234 }
235}
236
237impl<T: Copy> From<&T> for Boxed<T> {
238 fn from(value: &T) -> Self {
239 Boxed(*value)
240 }
241}
242
243impl<T: std::ops::Add<Output = T>> std::ops::Add for Boxed<T> {
244 type Output = Self;
245
246 fn add(self, other: Self) -> Self::Output {
247 Boxed(self.0 + other.0)
248 }
249}
250
251impl<T: std::ops::Sub<Output = T>> std::ops::Sub for Boxed<T> {
252 type Output = Self;
253
254 fn sub(self, other: Self) -> Self::Output {
255 Boxed(self.0 - other.0)
256 }
257}
258
259impl<T: std::ops::Mul<Output = T>> std::ops::Mul for Boxed<T> {
260 type Output = Self;
261
262 fn mul(self, other: Self) -> Self::Output {
263 Boxed(self.0 * other.0)
264 }
265}
266
267impl<T: std::ops::Div<Output = T>> std::ops::Div for Boxed<T> {
268 type Output = Self;
269
270 fn div(self, other: Self) -> Self::Output {
271 Boxed(self.0 / other.0)
272 }
273}
274
275impl<T: std::ops::Rem<Output = T>> std::ops::Rem for Boxed<T> {
276 type Output = Self;
277
278 fn rem(self, other: Self) -> Self::Output {
279 Boxed(self.0 % other.0)
280 }
281}
282
283impl<T: std::ops::Neg<Output = T>> std::ops::Neg for Boxed<T> {
284 type Output = Self;
285
286 fn neg(self) -> Self::Output {
287 Boxed(-self.0)
288 }
289}
290
291impl<T: std::ops::BitAnd<Output = T>> std::ops::BitAnd for Boxed<T> {
292 type Output = Self;
293
294 fn bitand(self, other: Self) -> Self::Output {
295 Boxed(self.0 & other.0)
296 }
297}
298
299impl<T: std::ops::BitOr<Output = T>> std::ops::BitOr for Boxed<T> {
300 type Output = Self;
301
302 fn bitor(self, other: Self) -> Self::Output {
303 Boxed(self.0 | other.0)
304 }
305}
306
307impl<T: std::ops::BitXor<Output = T>> std::ops::BitXor for Boxed<T> {
308 type Output = Self;
309
310 fn bitxor(self, other: Self) -> Self::Output {
311 Boxed(self.0 ^ other.0)
312 }
313}