@@ -53,12 +53,13 @@ mod private {
5353 use core:: marker:: PhantomData ;
5454
5555 use super :: types:: { ExtData , Type } ;
56+ use crate :: iter:: TreeLike as _;
5657 pub use crate :: miniscript:: context:: ScriptContext ;
5758 use crate :: miniscript:: types;
59+ use crate :: prelude:: sync:: Arc ;
5860 use crate :: { Error , MiniscriptKey , Terminal , MAX_RECURSION_DEPTH } ;
5961
6062 /// The top-level miniscript abstract syntax tree (AST).
61- #[ derive( Clone ) ]
6263 pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
6364 /// A node in the AST.
6465 pub node : Terminal < Pk , Ctx > ,
@@ -69,6 +70,70 @@ mod private {
6970 /// Context PhantomData. Only accessible inside this crate
7071 phantom : PhantomData < Ctx > ,
7172 }
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+
72137 impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
73138 /// The `1` combinator.
74139 pub const TRUE : Self = Miniscript {
0 commit comments