oxidd_core/util/
substitution.rs1use std::marker::PhantomData;
2use std::sync::atomic;
3use std::sync::atomic::AtomicU64;
4
5use crate::VarNo;
6
7pub fn new_substitution_id() -> u32 {
9 static ID: AtomicU64 = AtomicU64::new(0);
10 let id = ID.fetch_add(1, atomic::Ordering::Relaxed);
11 if id > u32::MAX as u64 {
12 panic!(
13 "Too many `Substitution` structs\n\
14 \n\
15 To allow caching across multiple results, we assign each \
16 substitution a unique 32 bit integer. Now, so many substitutions \
17 have been created that we cannot guarantee uniqueness anymore."
18 );
19 }
20
21 id as u32
22}
23
24pub trait Substitution {
33 type Replacement;
35
36 fn id(&self) -> u32;
43
44 fn pairs(&self) -> impl ExactSizeIterator<Item = (VarNo, Self::Replacement)>;
46
47 #[inline]
55 fn map<V, R, F>(&self, f: F) -> MapSubst<'_, Self, F>
56 where
57 F: Fn((VarNo, Self::Replacement)) -> (V, R),
58 {
59 MapSubst { inner: self, f }
60 }
61}
62
63impl<T: Substitution> Substitution for &T {
64 type Replacement = T::Replacement;
65
66 #[inline]
67 fn id(&self) -> u32 {
68 (*self).id()
69 }
70 #[inline]
71 fn pairs(&self) -> impl ExactSizeIterator<Item = (VarNo, Self::Replacement)> {
72 (*self).pairs()
73 }
74}
75
76#[derive(Debug)]
81pub struct Subst<F, VS = Vec<VarNo>, RS = Vec<F>> {
82 id: u32,
83 vars: VS,
84 replacements: RS,
85 phantom: PhantomData<fn(&F)>,
86}
87
88impl<F, VS: Copy, RS: Copy> Copy for Subst<F, VS, RS> {}
89impl<F, VS: Clone, RS: Clone> Clone for Subst<F, VS, RS> {
90 fn clone(&self) -> Self {
91 Self {
92 id: self.id,
93 vars: self.vars.clone(),
94 replacements: self.replacements.clone(),
95 phantom: PhantomData,
96 }
97 }
98}
99
100impl<'a, F, VS: AsRef<[VarNo]>, RS: AsRef<[F]>> Substitution for &'a Subst<F, VS, RS> {
101 type Replacement = &'a F;
102
103 #[inline]
104 fn id(&self) -> u32 {
105 self.id
106 }
107
108 #[inline]
109 fn pairs(&self) -> impl ExactSizeIterator<Item = (VarNo, Self::Replacement)> {
110 self.vars
111 .as_ref()
112 .iter()
113 .copied()
114 .zip(self.replacements.as_ref())
115 }
116}
117
118impl<F, VS: AsRef<[VarNo]>, RS: AsRef<[F]>> Subst<F, VS, RS> {
119 #[track_caller]
128 pub fn new(vars: VS, replacements: RS) -> Self {
129 assert_eq!(
130 vars.as_ref().len(),
131 replacements.as_ref().len(),
132 "`vars` and `replacements` must have the same length"
133 );
134
135 Self {
136 id: new_substitution_id(),
137 vars,
138 replacements,
139 phantom: PhantomData,
140 }
141 }
142}
143
144#[derive(Clone, Copy, Debug)]
147pub struct MapSubst<'a, S: ?Sized, F> {
148 inner: &'a S,
149 f: F,
150}
151
152impl<R, S: Substitution + ?Sized, F: Fn((VarNo, S::Replacement)) -> (VarNo, R)> Substitution
153 for MapSubst<'_, S, F>
154{
155 type Replacement = R;
156
157 #[inline]
158 fn id(&self) -> u32 {
159 self.inner.id()
160 }
161
162 #[inline]
163 fn pairs(&self) -> impl ExactSizeIterator<Item = (VarNo, Self::Replacement)> {
164 self.inner.pairs().map(&self.f)
165 }
166}