@@ -53,12 +53,13 @@ mod private {
53
53
use core:: marker:: PhantomData ;
54
54
55
55
use super :: types:: { ExtData , Type } ;
56
+ use crate :: iter:: TreeLike as _;
56
57
pub use crate :: miniscript:: context:: ScriptContext ;
57
58
use crate :: miniscript:: types;
59
+ use crate :: prelude:: sync:: Arc ;
58
60
use crate :: { Error , MiniscriptKey , Terminal , MAX_RECURSION_DEPTH } ;
59
61
60
62
/// The top-level miniscript abstract syntax tree (AST).
61
- #[ derive( Clone ) ]
62
63
pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
63
64
/// A node in the AST.
64
65
pub node : Terminal < Pk , Ctx > ,
@@ -69,6 +70,70 @@ mod private {
69
70
/// Context PhantomData. Only accessible inside this crate
70
71
phantom : PhantomData < Ctx > ,
71
72
}
73
+
74
+ impl < Pk : MiniscriptKey , Ctx : ScriptContext > Clone for Miniscript < Pk , Ctx > {
75
+ /// We implement clone as a "deep clone" which reconstructs the entire tree.
76
+ ///
77
+ /// If users just want to clone Arcs they can use Arc::clone themselves.
78
+ /// Note that if a Miniscript was constructed using shared Arcs, the result
79
+ /// of calling `clone` will no longer have shared Arcs. So there is no
80
+ /// pleasing everyone. But for the two common cases:
81
+ ///
82
+ /// * Users don't care about sharing at all, and they can call `Arc::clone`
83
+ /// on an `Arc<Miniscript>`.
84
+ /// * Users want a deep copy which does not share any nodes with the original
85
+ /// (for example, because they have keys that have interior mutability),
86
+ /// and they can call `Miniscript::clone`.
87
+ fn clone ( & self ) -> Self {
88
+ let mut stack = vec ! [ ] ;
89
+ for item in self . post_order_iter ( ) {
90
+ let child_n = |n| Arc :: clone ( & stack[ item. child_indices [ n] ] ) ;
91
+
92
+ let new_term = match item. node . node {
93
+ Terminal :: PkK ( ref p) => Terminal :: PkK ( p. clone ( ) ) ,
94
+ Terminal :: PkH ( ref p) => Terminal :: PkH ( p. clone ( ) ) ,
95
+ Terminal :: RawPkH ( ref p) => Terminal :: RawPkH ( * p) ,
96
+ Terminal :: After ( ref n) => Terminal :: After ( * n) ,
97
+ Terminal :: Older ( ref n) => Terminal :: Older ( * n) ,
98
+ Terminal :: Sha256 ( ref x) => Terminal :: Sha256 ( x. clone ( ) ) ,
99
+ Terminal :: Hash256 ( ref x) => Terminal :: Hash256 ( x. clone ( ) ) ,
100
+ Terminal :: Ripemd160 ( ref x) => Terminal :: Ripemd160 ( x. clone ( ) ) ,
101
+ Terminal :: Hash160 ( ref x) => Terminal :: Hash160 ( x. clone ( ) ) ,
102
+ Terminal :: True => Terminal :: True ,
103
+ Terminal :: False => Terminal :: False ,
104
+ Terminal :: Alt ( ..) => Terminal :: Alt ( child_n ( 0 ) ) ,
105
+ Terminal :: Swap ( ..) => Terminal :: Swap ( child_n ( 0 ) ) ,
106
+ Terminal :: Check ( ..) => Terminal :: Check ( child_n ( 0 ) ) ,
107
+ Terminal :: DupIf ( ..) => Terminal :: DupIf ( child_n ( 0 ) ) ,
108
+ Terminal :: Verify ( ..) => Terminal :: Verify ( child_n ( 0 ) ) ,
109
+ Terminal :: NonZero ( ..) => Terminal :: NonZero ( child_n ( 0 ) ) ,
110
+ Terminal :: ZeroNotEqual ( ..) => Terminal :: ZeroNotEqual ( child_n ( 0 ) ) ,
111
+ Terminal :: AndV ( ..) => Terminal :: AndV ( child_n ( 0 ) , child_n ( 1 ) ) ,
112
+ Terminal :: AndB ( ..) => Terminal :: AndB ( child_n ( 0 ) , child_n ( 1 ) ) ,
113
+ Terminal :: AndOr ( ..) => Terminal :: AndOr ( child_n ( 0 ) , child_n ( 1 ) , child_n ( 2 ) ) ,
114
+ Terminal :: OrB ( ..) => Terminal :: OrB ( child_n ( 0 ) , child_n ( 1 ) ) ,
115
+ Terminal :: OrD ( ..) => Terminal :: OrD ( child_n ( 0 ) , child_n ( 1 ) ) ,
116
+ Terminal :: OrC ( ..) => Terminal :: OrC ( child_n ( 0 ) , child_n ( 1 ) ) ,
117
+ Terminal :: OrI ( ..) => Terminal :: OrI ( child_n ( 0 ) , child_n ( 1 ) ) ,
118
+ Terminal :: Thresh ( ref thresh) => Terminal :: Thresh (
119
+ thresh. map_from_post_order_iter ( & item. child_indices , & stack) ,
120
+ ) ,
121
+ Terminal :: Multi ( ref thresh) => Terminal :: Multi ( thresh. clone ( ) ) ,
122
+ Terminal :: MultiA ( ref thresh) => Terminal :: MultiA ( thresh. clone ( ) ) ,
123
+ } ;
124
+
125
+ stack. push ( Arc :: new ( Miniscript {
126
+ node : new_term,
127
+ ty : item. node . ty ,
128
+ ext : item. node . ext ,
129
+ phantom : PhantomData ,
130
+ } ) ) ;
131
+ }
132
+
133
+ Arc :: try_unwrap ( stack. pop ( ) . unwrap ( ) ) . unwrap ( )
134
+ }
135
+ }
136
+
72
137
impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
73
138
/// The `1` combinator.
74
139
pub const TRUE : Self = Miniscript {
0 commit comments