simplicity/node/
inner.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use super::{Disconnectable, FailEntropy};
4use crate::dag::Dag;
5use crate::Cmr;
6
7use crate::value::Word;
8use std::fmt;
9use std::sync::Arc;
10
11/// Internal "Simplicity DAG" structure.
12///
13/// This structure is used to indicate the type of a node and provide
14/// pointers or references to its children, if any.
15#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
16pub enum Inner<C, J, X, W> {
17    /// Identity
18    Iden,
19    /// Unit constant
20    Unit,
21    /// Left injection of some child
22    InjL(C),
23    /// Right injection of some child
24    InjR(C),
25    /// Take of some child
26    Take(C),
27    /// Drop of some child
28    Drop(C),
29    /// Composition of a left and right child
30    Comp(C, C),
31    /// Case of a left and right child
32    Case(C, C),
33    /// Left assertion of a left and right child.
34    AssertL(C, Cmr),
35    /// Right assertion of a left and right child.
36    AssertR(Cmr, C),
37    /// Pair of a left and right child
38    Pair(C, C),
39    /// Disconnect of a left and right child
40    Disconnect(C, X),
41    /// Witness data (missing during commitment, inserted during redemption)
42    Witness(W),
43    /// Universal fail
44    Fail(FailEntropy),
45    /// Application jet
46    Jet(J),
47    /// Constant word
48    Word(Word),
49}
50
51impl<C, J: Clone, X, W> Inner<C, J, X, W> {
52    /// Convert a node's combinator data to a different type.
53    pub fn map<D, F: FnMut(C) -> D>(self, mut f: F) -> Inner<D, J, X, W> {
54        match self {
55            Inner::Iden => Inner::Iden,
56            Inner::Unit => Inner::Unit,
57            Inner::InjL(c) => Inner::InjL(f(c)),
58            Inner::InjR(c) => Inner::InjR(f(c)),
59            Inner::Take(c) => Inner::Take(f(c)),
60            Inner::Drop(c) => Inner::Drop(f(c)),
61            Inner::Comp(cl, cr) => Inner::Comp(f(cl), f(cr)),
62            Inner::Case(cl, cr) => Inner::Case(f(cl), f(cr)),
63            Inner::AssertL(c, cmr) => Inner::AssertL(f(c), cmr),
64            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, f(c)),
65            Inner::Pair(cl, cr) => Inner::Pair(f(cl), f(cr)),
66            Inner::Disconnect(cl, cr) => Inner::Disconnect(f(cl), cr),
67            Inner::Witness(w) => Inner::Witness(w),
68            Inner::Fail(entropy) => Inner::Fail(entropy),
69            Inner::Jet(j) => Inner::Jet(j),
70            Inner::Word(w) => Inner::Word(w),
71        }
72    }
73
74    /// Convert a node's combinator data to a different type.
75    pub fn map_result<D, E, F: FnMut(C) -> Result<D, E>>(
76        self,
77        mut f: F,
78    ) -> Result<Inner<D, J, X, W>, E> {
79        Ok(match self {
80            Inner::Iden => Inner::Iden,
81            Inner::Unit => Inner::Unit,
82            Inner::InjL(c) => Inner::InjL(f(c)?),
83            Inner::InjR(c) => Inner::InjR(f(c)?),
84            Inner::Take(c) => Inner::Take(f(c)?),
85            Inner::Drop(c) => Inner::Drop(f(c)?),
86            Inner::Comp(cl, cr) => Inner::Comp(f(cl)?, f(cr)?),
87            Inner::Case(cl, cr) => Inner::Case(f(cl)?, f(cr)?),
88            Inner::AssertL(c, cmr) => Inner::AssertL(f(c)?, cmr),
89            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, f(c)?),
90            Inner::Pair(cl, cr) => Inner::Pair(f(cl)?, f(cr)?),
91            Inner::Disconnect(cl, cr) => Inner::Disconnect(f(cl)?, cr),
92            Inner::Witness(w) => Inner::Witness(w),
93            Inner::Fail(entropy) => Inner::Fail(entropy),
94            Inner::Jet(j) => Inner::Jet(j),
95            Inner::Word(w) => Inner::Word(w),
96        })
97    }
98
99    /// Convert a node's combinator data to a different type, mapping each
100    /// child separately.
101    ///
102    /// Importantly, the child of an `AssertR` node is considered the left
103    /// child, because as a DAG node, this is the sole (left) child, even
104    /// though as a combinator, it is a right child.
105    pub fn map_left_right<D, FL, FR>(self, fl: FL, fr: FR) -> Inner<D, J, X, W>
106    where
107        FL: FnOnce(C) -> D,
108        FR: FnOnce(C) -> D,
109    {
110        match self {
111            Inner::Iden => Inner::Iden,
112            Inner::Unit => Inner::Unit,
113            Inner::InjL(c) => Inner::InjL(fl(c)),
114            Inner::InjR(c) => Inner::InjR(fl(c)),
115            Inner::Take(c) => Inner::Take(fl(c)),
116            Inner::Drop(c) => Inner::Drop(fl(c)),
117            Inner::Comp(cl, cr) => Inner::Comp(fl(cl), fr(cr)),
118            Inner::Case(cl, cr) => Inner::Case(fl(cl), fr(cr)),
119            Inner::AssertL(c, cmr) => Inner::AssertL(fl(c), cmr),
120            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, fl(c)),
121            Inner::Pair(cl, cr) => Inner::Pair(fl(cl), fr(cr)),
122            Inner::Disconnect(cl, cr) => Inner::Disconnect(fl(cl), cr),
123            Inner::Witness(w) => Inner::Witness(w),
124            Inner::Fail(entropy) => Inner::Fail(entropy),
125            Inner::Jet(j) => Inner::Jet(j),
126            Inner::Word(w) => Inner::Word(w),
127        }
128    }
129
130    /// Take references to all contained data.
131    pub fn as_ref(&self) -> Inner<&C, J, &X, &W> {
132        match self {
133            Inner::Iden => Inner::Iden,
134            Inner::Unit => Inner::Unit,
135            Inner::InjL(c) => Inner::InjL(c),
136            Inner::InjR(c) => Inner::InjR(c),
137            Inner::Take(c) => Inner::Take(c),
138            Inner::Drop(c) => Inner::Drop(c),
139            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
140            Inner::Case(cl, cr) => Inner::Case(cl, cr),
141            Inner::AssertL(c, cmr) => Inner::AssertL(c, *cmr),
142            Inner::AssertR(cmr, c) => Inner::AssertR(*cmr, c),
143            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
144            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, cr),
145            Inner::Witness(w) => Inner::Witness(w),
146            Inner::Fail(entropy) => Inner::Fail(*entropy),
147            Inner::Jet(j) => Inner::Jet(j.clone()),
148            Inner::Word(w) => Inner::Word(w.shallow_clone()),
149        }
150    }
151
152    /// Take references to only the disconnect node.
153    pub fn disconnect_as_ref(&self) -> Inner<C, J, &X, W>
154    where
155        J: Copy,
156        C: Copy,
157        W: Copy,
158    {
159        match *self {
160            Inner::Iden => Inner::Iden,
161            Inner::Unit => Inner::Unit,
162            Inner::InjL(c) => Inner::InjL(c),
163            Inner::InjR(c) => Inner::InjR(c),
164            Inner::Take(c) => Inner::Take(c),
165            Inner::Drop(c) => Inner::Drop(c),
166            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
167            Inner::Case(cl, cr) => Inner::Case(cl, cr),
168            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
169            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
170            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
171            Inner::Disconnect(cl, ref cr) => Inner::Disconnect(cl, cr),
172            Inner::Witness(w) => Inner::Witness(w),
173            Inner::Fail(entropy) => Inner::Fail(entropy),
174            Inner::Jet(j) => Inner::Jet(j),
175            Inner::Word(ref w) => Inner::Word(w.shallow_clone()),
176        }
177    }
178
179    pub fn map_disconnect<Y, F: FnOnce(X) -> Y>(self, f: F) -> Inner<C, J, Y, W> {
180        match self {
181            Inner::Iden => Inner::Iden,
182            Inner::Unit => Inner::Unit,
183            Inner::InjL(c) => Inner::InjL(c),
184            Inner::InjR(c) => Inner::InjR(c),
185            Inner::Take(c) => Inner::Take(c),
186            Inner::Drop(c) => Inner::Drop(c),
187            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
188            Inner::Case(cl, cr) => Inner::Case(cl, cr),
189            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
190            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
191            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
192            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, f(cr)),
193            Inner::Witness(w) => Inner::Witness(w),
194            Inner::Fail(entropy) => Inner::Fail(entropy),
195            Inner::Jet(j) => Inner::Jet(j),
196            Inner::Word(w) => Inner::Word(w),
197        }
198    }
199
200    /// Convert a node's witness data to a different type.
201    pub fn map_disconnect_result<Y, E, F: FnOnce(X) -> Result<Y, E>>(
202        self,
203        f: F,
204    ) -> Result<Inner<C, J, Y, W>, E> {
205        Ok(match self {
206            Inner::Iden => Inner::Iden,
207            Inner::Unit => Inner::Unit,
208            Inner::InjL(c) => Inner::InjL(c),
209            Inner::InjR(c) => Inner::InjR(c),
210            Inner::Take(c) => Inner::Take(c),
211            Inner::Drop(c) => Inner::Drop(c),
212            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
213            Inner::Case(cl, cr) => Inner::Case(cl, cr),
214            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
215            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
216            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
217            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, f(cr)?),
218            Inner::Witness(w) => Inner::Witness(w),
219            Inner::Fail(entropy) => Inner::Fail(entropy),
220            Inner::Jet(j) => Inner::Jet(j),
221            Inner::Word(w) => Inner::Word(w),
222        })
223    }
224
225    /// Convert a node's witness data to a different type.
226    pub fn map_witness<V, F: FnOnce(W) -> V>(self, f: F) -> Inner<C, J, X, V> {
227        match self {
228            Inner::Iden => Inner::Iden,
229            Inner::Unit => Inner::Unit,
230            Inner::InjL(c) => Inner::InjL(c),
231            Inner::InjR(c) => Inner::InjR(c),
232            Inner::Take(c) => Inner::Take(c),
233            Inner::Drop(c) => Inner::Drop(c),
234            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
235            Inner::Case(cl, cr) => Inner::Case(cl, cr),
236            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
237            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
238            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
239            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, cr),
240            Inner::Witness(w) => Inner::Witness(f(w)),
241            Inner::Fail(entropy) => Inner::Fail(entropy),
242            Inner::Jet(j) => Inner::Jet(j),
243            Inner::Word(w) => Inner::Word(w),
244        }
245    }
246
247    /// Convert a node's witness data to a different type.
248    pub fn map_witness_result<V, E, F: FnOnce(W) -> Result<V, E>>(
249        self,
250        f: F,
251    ) -> Result<Inner<C, J, X, V>, E> {
252        Ok(match self {
253            Inner::Iden => Inner::Iden,
254            Inner::Unit => Inner::Unit,
255            Inner::InjL(c) => Inner::InjL(c),
256            Inner::InjR(c) => Inner::InjR(c),
257            Inner::Take(c) => Inner::Take(c),
258            Inner::Drop(c) => Inner::Drop(c),
259            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
260            Inner::Case(cl, cr) => Inner::Case(cl, cr),
261            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
262            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
263            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
264            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, cr),
265            Inner::Witness(w) => Inner::Witness(f(w)?),
266            Inner::Fail(entropy) => Inner::Fail(entropy),
267            Inner::Jet(j) => Inner::Jet(j),
268            Inner::Word(w) => Inner::Word(w),
269        })
270    }
271}
272
273impl<C, J, X: Disconnectable<C>, W> Inner<Arc<C>, J, X, W> {
274    /// Collapse the node information to a `Dag`
275    pub fn as_dag(&self) -> Dag<&C> {
276        match self {
277            Inner::Iden
278            | Inner::Unit
279            | Inner::Witness(_)
280            | Inner::Fail(_)
281            | Inner::Jet(_)
282            | Inner::Word(_) => Dag::Nullary,
283            Inner::InjL(c)
284            | Inner::InjR(c)
285            | Inner::Take(c)
286            | Inner::Drop(c)
287            | Inner::AssertL(c, _)
288            | Inner::AssertR(_, c) => Dag::Unary(c),
289            Inner::Comp(cl, cr) | Inner::Case(cl, cr) | Inner::Pair(cl, cr) => Dag::Binary(cl, cr),
290            Inner::Disconnect(cl, cr) => cr.disconnect_dag_ref(cl),
291        }
292    }
293}
294
295impl<C, J, X, W> Inner<Option<C>, J, X, W> {
296    /// Convert an `Inner<Option<C>, J, W>` to an `Option<Inner<C, J, W>>`.
297    pub fn transpose(self) -> Option<Inner<C, J, X, W>> {
298        Some(match self {
299            Inner::Iden => Inner::Iden,
300            Inner::Unit => Inner::Unit,
301            Inner::InjL(c) => Inner::InjL(c?),
302            Inner::InjR(c) => Inner::InjR(c?),
303            Inner::Take(c) => Inner::Take(c?),
304            Inner::Drop(c) => Inner::Drop(c?),
305            Inner::Comp(cl, cr) => Inner::Comp(cl?, cr?),
306            Inner::Case(cl, cr) => Inner::Case(cl?, cr?),
307            Inner::AssertL(c, cmr) => Inner::AssertL(c?, cmr),
308            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c?),
309            Inner::Pair(cl, cr) => Inner::Pair(cl?, cr?),
310            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl?, cr),
311            Inner::Witness(w) => Inner::Witness(w),
312            Inner::Fail(entropy) => Inner::Fail(entropy),
313            Inner::Jet(j) => Inner::Jet(j),
314            Inner::Word(w) => Inner::Word(w),
315        })
316    }
317}
318
319impl<C, J, X, W> Inner<C, J, Option<X>, W> {
320    /// Convert an `Inner<Option<C>, J, W>` to an `Option<Inner<C, J, W>>`.
321    pub fn transpose_disconnect(self) -> Option<Inner<C, J, X, W>> {
322        Some(match self {
323            Inner::Iden => Inner::Iden,
324            Inner::Unit => Inner::Unit,
325            Inner::InjL(c) => Inner::InjL(c),
326            Inner::InjR(c) => Inner::InjR(c),
327            Inner::Take(c) => Inner::Take(c),
328            Inner::Drop(c) => Inner::Drop(c),
329            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
330            Inner::Case(cl, cr) => Inner::Case(cl, cr),
331            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
332            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
333            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
334            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, cr?),
335            Inner::Witness(w) => Inner::Witness(w),
336            Inner::Fail(entropy) => Inner::Fail(entropy),
337            Inner::Jet(j) => Inner::Jet(j),
338            Inner::Word(w) => Inner::Word(w),
339        })
340    }
341}
342
343impl<C, J, X, W> Inner<C, J, X, Option<W>> {
344    /// Convert an `Inner<C, J, Option<W>>` to an `Option<Inner<C, J, W>>`.
345    pub fn transpose_witness(self) -> Option<Inner<C, J, X, W>> {
346        Some(match self {
347            Inner::Iden => Inner::Iden,
348            Inner::Unit => Inner::Unit,
349            Inner::InjL(c) => Inner::InjL(c),
350            Inner::InjR(c) => Inner::InjR(c),
351            Inner::Take(c) => Inner::Take(c),
352            Inner::Drop(c) => Inner::Drop(c),
353            Inner::Comp(cl, cr) => Inner::Comp(cl, cr),
354            Inner::Case(cl, cr) => Inner::Case(cl, cr),
355            Inner::AssertL(c, cmr) => Inner::AssertL(c, cmr),
356            Inner::AssertR(cmr, c) => Inner::AssertR(cmr, c),
357            Inner::Pair(cl, cr) => Inner::Pair(cl, cr),
358            Inner::Disconnect(cl, cr) => Inner::Disconnect(cl, cr),
359            Inner::Witness(w) => Inner::Witness(w?),
360            Inner::Fail(entropy) => Inner::Fail(entropy),
361            Inner::Jet(j) => Inner::Jet(j),
362            Inner::Word(w) => Inner::Word(w),
363        })
364    }
365}
366
367impl<C, J: Clone, X, W: Copy> Inner<C, J, X, &W> {
368    /// Copies witness data.
369    ///
370    /// Useful in conjunction with [`Inner::as_ref`] when you don't want to
371    /// take a reference to witness data.
372    pub fn copy_witness(self) -> Inner<C, J, X, W> {
373        self.map_witness(W::clone)
374    }
375}
376
377impl<C, J: Clone, X: Copy, W> Inner<C, J, &X, W> {
378    /// Copies disconnect data.
379    ///
380    /// Useful in conjunction with [`Inner::as_ref`] when you don't want to
381    /// take a reference to disconnect data.
382    pub fn copy_disconnect(self) -> Inner<C, J, X, W> {
383        self.map_disconnect(X::clone)
384    }
385}
386
387impl<C, J: fmt::Display, X, W> fmt::Display for Inner<C, J, X, W> {
388    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389        match self {
390            Inner::Iden => f.write_str("iden"),
391            Inner::Unit => f.write_str("unit"),
392            Inner::InjL(_) => f.write_str("injl"),
393            Inner::InjR(_) => f.write_str("injr"),
394            Inner::Take(_) => f.write_str("take"),
395            Inner::Drop(_) => f.write_str("drop"),
396            Inner::Comp(_, _) => f.write_str("comp"),
397            Inner::Case(_, _) => f.write_str("case"),
398            Inner::AssertL(_, _) => f.write_str("assertl"),
399            Inner::AssertR(_, _) => f.write_str("assertr"),
400            Inner::Pair(_, _) => f.write_str("pair"),
401            Inner::Disconnect(_, _) => f.write_str("disconnect"),
402            Inner::Witness(..) => f.write_str("witness"),
403            Inner::Fail(..) => f.write_str("fail"),
404            Inner::Jet(jet) => write!(f, "jet({})", jet),
405            Inner::Word(w) => write!(f, "word({})", w),
406        }
407    }
408}