1use crate::dag::{Dag, DagLike, NoSharing};
15use crate::Tmr;
16
17use std::sync::Arc;
18use std::{cmp, fmt, hash};
19
20#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
22pub enum CompleteBound {
23 Unit,
25 Sum(Arc<Final>, Arc<Final>),
27 Product(Arc<Final>, Arc<Final>),
29}
30
31#[derive(Clone)]
34pub struct Final {
35 bound: CompleteBound,
37 bit_width: usize,
39 has_padding: bool,
43 tmr: Tmr,
45}
46
47impl PartialEq for Final {
48 fn eq(&self, other: &Self) -> bool {
49 self.tmr == other.tmr
50 }
51}
52impl Eq for Final {}
53
54impl PartialOrd for Final {
55 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
56 Some(self.cmp(other))
57 }
58}
59impl Ord for Final {
60 fn cmp(&self, other: &Self) -> cmp::Ordering {
61 self.tmr.cmp(&other.tmr)
62 }
63}
64impl hash::Hash for Final {
65 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
66 self.tmr.hash(hasher)
67 }
68}
69
70impl fmt::Debug for Final {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 write!(
73 f,
74 "{{ tmr: {}, bit_width: {}, bound: {} }}",
75 self.tmr, self.bit_width, self
76 )
77 }
78}
79
80impl fmt::Display for Final {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 let mut skipping: Option<Tmr> = None;
83 for data in self.verbose_pre_order_iter::<NoSharing>(None) {
84 if let Some(skip) = skipping {
85 if data.is_complete && data.node.tmr == skip {
86 skipping = None;
87 }
88 continue;
89 } else {
90 if data.node.tmr == Tmr::TWO_TWO_N[0] {
91 f.write_str("2")?;
92 skipping = Some(data.node.tmr);
93 }
94 for (n, tmr) in Tmr::TWO_TWO_N.iter().enumerate().skip(1) {
95 if data.node.tmr == *tmr {
96 write!(f, "2^{}", 1 << n)?;
97 skipping = Some(data.node.tmr);
98 }
99 }
100 }
101 if skipping.is_some() {
102 continue;
103 }
104
105 match (&data.node.bound, data.n_children_yielded) {
106 (CompleteBound::Unit, _) => {
107 f.write_str("1")?;
108 }
109 (CompleteBound::Sum(ref left, _), 0)
111 if matches!(left.bound, CompleteBound::Unit) =>
112 {
113 skipping = Some(Tmr::unit());
114 }
115 (CompleteBound::Sum(ref left, _), 1)
116 if matches!(left.bound, CompleteBound::Unit) => {}
117 (CompleteBound::Sum(ref left, _), 2)
118 if matches!(left.bound, CompleteBound::Unit) =>
119 {
120 f.write_str("?")?;
121 }
122 (CompleteBound::Sum(..), 0) | (CompleteBound::Product(..), 0) => {
124 if data.index > 0 {
125 f.write_str("(")?;
126 }
127 }
128 (CompleteBound::Sum(..), 2) | (CompleteBound::Product(..), 2) => {
129 if data.index > 0 {
130 f.write_str(")")?;
131 }
132 }
133 (CompleteBound::Sum(..), _) => f.write_str(" + ")?,
134 (CompleteBound::Product(..), _) => f.write_str(" × ")?,
135 }
136 }
137 Ok(())
138 }
139}
140
141impl DagLike for &'_ Final {
142 type Node = Final;
143 fn data(&self) -> &Final {
144 self
145 }
146 fn as_dag_node(&self) -> Dag<Self> {
147 match self.bound {
148 CompleteBound::Unit => Dag::Nullary,
149 CompleteBound::Sum(ref left, ref right)
150 | CompleteBound::Product(ref left, ref right) => Dag::Binary(left, right),
151 }
152 }
153}
154
155macro_rules! construct_final_two_two_n {
156 ($name: ident, $n: expr, $text: expr) => {
157 #[doc = "Create the type of"]
158 #[doc = $text]
159 #[doc = "words.\n\nThe type is precomputed and fast to access."]
160 #[inline]
161 pub fn $name() -> Arc<Self> {
162 super::precomputed::nth_power_of_2($n)
163 }
164 };
165}
166
167impl Final {
168 pub fn unit() -> Arc<Self> {
170 Arc::new(Final {
171 bound: CompleteBound::Unit,
172 bit_width: 0,
173 has_padding: false,
174 tmr: Tmr::unit(),
175 })
176 }
177
178 pub fn successor(self: Arc<Self>) -> Arc<Self> {
183 Self::sum(Self::unit(), self)
184 }
185
186 #[inline]
190 pub fn two_two_n(n: usize) -> Result<Arc<Self>, TypeTooLargeError> {
191 let maximum = Tmr::TWO_TWO_N.len();
192 if n < maximum {
193 Ok(super::precomputed::nth_power_of_2(n))
194 } else {
195 Err(TypeTooLargeError {
196 ty: "2^(2^n)",
197 n,
198 maximum,
199 })
200 }
201 }
202
203 #[inline]
207 pub fn two_two_n_fixed<const N: usize>() -> Arc<Self> {
208 struct Hack<const N: usize>;
210 impl<const N: usize> Hack<N> {
211 const IS_IN_RANGE: () = {
212 assert!(N < Tmr::TWO_TWO_N.len());
213 };
214 }
215 let () = Hack::<N>::IS_IN_RANGE;
216
217 super::precomputed::nth_power_of_2(N)
218 }
219
220 #[inline]
230 pub fn buffer8_two_n_plus_one(n: usize) -> Result<Arc<Self>, TypeTooLargeError> {
231 let maximum = Tmr::BUFFER8_TWO_N_PLUS_ONE.len();
232 if n < maximum {
233 Ok(super::precomputed::buffer8_two_n_plus_one(n))
234 } else {
235 Err(TypeTooLargeError {
240 ty: "(TWO^8)^<2^(n+1)",
241 n,
242 maximum,
243 })
244 }
245 }
246
247 pub fn ctx8() -> Arc<Self> {
251 super::precomputed::ctx8()
252 }
253
254 construct_final_two_two_n!(u1, 0, "1-bit");
255 construct_final_two_two_n!(u2, 1, "2-bit");
256 construct_final_two_two_n!(u4, 2, "4-bit");
257 construct_final_two_two_n!(u8, 3, "8-bit");
258 construct_final_two_two_n!(u16, 4, "16-bit");
259 construct_final_two_two_n!(u32, 5, "32-bit");
260 construct_final_two_two_n!(u64, 6, "64-bit");
261 construct_final_two_two_n!(u128, 7, "128-bit");
262 construct_final_two_two_n!(u256, 8, "256-bit");
263 construct_final_two_two_n!(u512, 9, "512-bit");
264
265 pub fn sum(left: Arc<Self>, right: Arc<Self>) -> Arc<Self> {
267 Arc::new(Final {
272 tmr: Tmr::sum(left.tmr, right.tmr),
273 bit_width: cmp::max(left.bit_width, right.bit_width).saturating_add(1),
274 has_padding: left.has_padding || right.has_padding || left.bit_width != right.bit_width,
275 bound: CompleteBound::Sum(left, right),
276 })
277 }
278
279 pub fn product(left: Arc<Self>, right: Arc<Self>) -> Arc<Self> {
281 Arc::new(Final {
283 tmr: Tmr::product(left.tmr, right.tmr),
284 bit_width: left.bit_width.saturating_add(right.bit_width),
285 has_padding: left.has_padding || right.has_padding,
286 bound: CompleteBound::Product(left, right),
287 })
288 }
289
290 pub fn tmr(&self) -> Tmr {
292 self.tmr
293 }
294
295 pub fn bit_width(&self) -> usize {
297 self.bit_width
298 }
299
300 pub fn has_padding(&self) -> bool {
305 self.has_padding
306 }
307
308 pub fn is_empty(&self) -> bool {
311 self.bit_width() == 0
312 }
313
314 pub fn bound(&self) -> &CompleteBound {
316 &self.bound
317 }
318
319 pub fn is_unit(&self) -> bool {
321 self.bound == CompleteBound::Unit
322 }
323
324 pub fn as_sum(&self) -> Option<(&Arc<Self>, &Arc<Self>)> {
326 match &self.bound {
327 CompleteBound::Sum(left, right) => Some((left, right)),
328 _ => None,
329 }
330 }
331
332 pub fn as_product(&self) -> Option<(&Arc<Self>, &Arc<Self>)> {
334 match &self.bound {
335 CompleteBound::Product(left, right) => Some((left, right)),
336 _ => None,
337 }
338 }
339
340 pub fn as_word(&self) -> Option<u8> {
346 (0u8..32).find(|&n| self.tmr == Tmr::TWO_TWO_N[usize::from(n)])
347 }
348
349 pub fn pad_left(&self, other: &Self) -> usize {
351 cmp::max(self.bit_width, other.bit_width) - self.bit_width
352 }
353
354 pub fn pad_right(&self, other: &Self) -> usize {
356 cmp::max(self.bit_width, other.bit_width) - other.bit_width
357 }
358}
359
360#[derive(Clone, PartialEq, Eq, Debug)]
362pub struct TypeTooLargeError {
363 ty: &'static str,
364 n: usize,
365 maximum: usize,
366}
367
368impl fmt::Display for TypeTooLargeError {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 write!(
371 f,
372 "maximum n for {} is {}; got {}",
373 self.ty, self.maximum, self.n
374 )
375 }
376}
377
378impl std::error::Error for TypeTooLargeError {
379 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
380 let Self {
381 ty: _,
382 n: _,
383 maximum: _,
384 } = self;
385 None
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn two_two_n_consistent() {
395 assert_eq!(Final::two_two_n_fixed::<0>(), Final::two_two_n(0).unwrap());
397 assert_eq!(Final::two_two_n_fixed::<1>(), Final::two_two_n(1).unwrap());
398 assert_eq!(Final::two_two_n_fixed::<2>(), Final::two_two_n(2).unwrap());
399 assert_eq!(Final::two_two_n_fixed::<3>(), Final::two_two_n(3).unwrap());
400 assert_eq!(Final::two_two_n_fixed::<4>(), Final::two_two_n(4).unwrap());
401 assert_eq!(Final::two_two_n_fixed::<5>(), Final::two_two_n(5).unwrap());
402 assert_eq!(Final::two_two_n_fixed::<6>(), Final::two_two_n(6).unwrap());
403 assert_eq!(Final::two_two_n_fixed::<7>(), Final::two_two_n(7).unwrap());
404 }
405
406 #[test]
407 fn final_stringify() {
408 let ty1 = Final::two_two_n_fixed::<10>();
409 assert_eq!(ty1.to_string(), "2^1024");
410
411 let sum = Final::sum(Final::two_two_n_fixed::<5>(), Final::two_two_n(10).unwrap());
412 assert_eq!(sum.to_string(), "2^32 + 2^1024");
413
414 let prod = Final::product(
415 Final::two_two_n_fixed::<5>(),
416 Final::two_two_n_fixed::<10>(),
417 );
418 assert_eq!(prod.to_string(), "2^32 × 2^1024");
419
420 let ty1 = Final::two_two_n_fixed::<0>();
421 assert_eq!(ty1.to_string(), "2");
422
423 let ty1 = Final::sum(Final::unit(), Final::two_two_n_fixed::<2>());
424 assert_eq!(ty1.to_string(), "2^4?");
425 }
426}