#[cfg(feature = "persistent")] use dogged::DVec; use snapshot_vec as sv; use std::marker::PhantomData; use std::ops::{self, Range}; use undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; use super::{UnifyKey, UnifyValue, VarValue}; #[allow(dead_code)] // rustc BUG #[allow(type_alias_bounds)] type Key = ::Key; /// Largely internal trait implemented by the unification table /// backing store types. The most common such type is `InPlace`, /// which indicates a standard, mutable unification table. pub trait UnificationStoreBase: ops::Index>> { type Key: UnifyKey; type Value: UnifyValue; fn len(&self) -> usize; fn tag() -> &'static str { Self::Key::tag() } } pub trait UnificationStoreMut: UnificationStoreBase { fn reset_unifications(&mut self, value: impl FnMut(u32) -> VarValue); fn push(&mut self, value: VarValue); fn reserve(&mut self, num_new_values: usize); fn update(&mut self, index: usize, op: F) where F: FnOnce(&mut VarValue); } pub trait UnificationStore: UnificationStoreMut { type Snapshot; fn start_snapshot(&mut self) -> Self::Snapshot; fn rollback_to(&mut self, snapshot: Self::Snapshot); fn commit(&mut self, snapshot: Self::Snapshot); fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range; } /// Backing store for an in-place unification table. /// Not typically used directly. #[derive(Clone, Debug)] pub struct InPlace< K: UnifyKey, V: sv::VecLike> = Vec>, L = VecLog>>, > { pub(crate) values: sv::SnapshotVec, V, L>, } // HACK(eddyb) manual impl avoids `Default` bound on `K`. impl> + Default, L: Default> Default for InPlace { fn default() -> Self { InPlace { values: sv::SnapshotVec::new(), } } } impl UnificationStoreBase for InPlace where K: UnifyKey, V: sv::VecLike>, { type Key = K; type Value = K::Value; fn len(&self) -> usize { self.values.len() } } impl UnificationStoreMut for InPlace where K: UnifyKey, V: sv::VecLike>, L: UndoLogs>>, { #[inline] fn reset_unifications(&mut self, mut value: impl FnMut(u32) -> VarValue) { self.values.set_all(|i| value(i as u32)); } #[inline] fn push(&mut self, value: VarValue) { self.values.push(value); } #[inline] fn reserve(&mut self, num_new_values: usize) { self.values.reserve(num_new_values); } #[inline] fn update(&mut self, index: usize, op: F) where F: FnOnce(&mut VarValue), { self.values.update(index, op) } } impl UnificationStore for InPlace where K: UnifyKey, V: sv::VecLike>, L: Snapshots>>, { type Snapshot = sv::Snapshot; #[inline] fn start_snapshot(&mut self) -> Self::Snapshot { self.values.start_snapshot() } #[inline] fn rollback_to(&mut self, snapshot: Self::Snapshot) { self.values.rollback_to(snapshot); } #[inline] fn commit(&mut self, snapshot: Self::Snapshot) { self.values.commit(snapshot); } #[inline] fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range { snapshot.value_count..self.len() } } impl ops::Index for InPlace where V: sv::VecLike>, K: UnifyKey, { type Output = VarValue; fn index(&self, index: usize) -> &VarValue { &self.values[index] } } #[doc(hidden)] #[derive(Copy, Clone, Debug)] pub struct Delegate(PhantomData); impl sv::SnapshotVecDelegate for Delegate { type Value = VarValue; type Undo = (); fn reverse(_: &mut Vec>, _: ()) {} } impl Rollback>> for super::UnificationTableStorage { fn reverse(&mut self, undo: sv::UndoLog>) { self.values.values.reverse(undo); } } #[cfg(feature = "persistent")] #[derive(Clone, Debug)] pub struct Persistent { values: DVec>, } // HACK(eddyb) manual impl avoids `Default` bound on `K`. #[cfg(feature = "persistent")] impl Default for Persistent { fn default() -> Self { Persistent { values: DVec::new(), } } } #[cfg(feature = "persistent")] impl UnificationStoreBase for Persistent { type Key = K; type Value = K::Value; fn len(&self) -> usize { self.values.len() } } #[cfg(feature = "persistent")] impl UnificationStoreMut for Persistent { #[inline] fn reset_unifications(&mut self, mut value: impl FnMut(u32) -> VarValue) { // Without extending dogged, there isn't obviously a more // efficient way to do this. But it's pretty dumb. Maybe // dogged needs a `map`. for i in 0..self.values.len() { self.values[i] = value(i as u32); } } #[inline] fn push(&mut self, value: VarValue) { self.values.push(value); } #[inline] fn reserve(&mut self, _num_new_values: usize) { // not obviously relevant to DVec. } #[inline] fn update(&mut self, index: usize, op: F) where F: FnOnce(&mut VarValue), { let p = &mut self.values[index]; op(p); } } #[cfg(feature = "persistent")] impl UnificationStore for Persistent { type Snapshot = Self; #[inline] fn start_snapshot(&mut self) -> Self::Snapshot { self.clone() } #[inline] fn rollback_to(&mut self, snapshot: Self::Snapshot) { *self = snapshot; } #[inline] fn commit(&mut self, _snapshot: Self::Snapshot) {} #[inline] fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range { snapshot.len()..self.len() } } #[cfg(feature = "persistent")] impl ops::Index for Persistent where K: UnifyKey, { type Output = VarValue; fn index(&self, index: usize) -> &VarValue { &self.values[index] } }