Skip to content

Commit 7ad6d5c

Browse files
committed
add conditional formatting for Terminal
fmt functions produce big binaries. Since Debug and Display implementation of the match are equal except the Debug or Display representation of its child, this introduce conditional fmt trading performance for code size. Since performance shouldn't be that important in string conversion seems an interesting trade-off.
1 parent 4c4597e commit 7ad6d5c

File tree

1 file changed

+22
-143
lines changed

1 file changed

+22
-143
lines changed

src/miniscript/astelem.rs

+22-143
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! encoding in Bitcoin script, as well as a datatype. Full details
88
//! are given on the Miniscript website.
99
10-
use core::fmt;
10+
use core::fmt::{self, Write};
1111
use core::str::FromStr;
1212

1313
use bitcoin::hashes::{hash160, Hash};
@@ -41,6 +41,25 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
4141
_ => None,
4242
}
4343
}
44+
45+
fn conditional_fmt(&self, f: &mut fmt::Formatter, is_debug: bool)-> fmt::Result {
46+
match *self {
47+
Terminal::PkK(ref pk) => {
48+
f.write_str("pk_k(")?;
49+
conditional_fmt(f, pk, is_debug)?;
50+
f.write_char(')')
51+
}
52+
_ => todo!()
53+
}
54+
}
55+
}
56+
57+
fn conditional_fmt<D: fmt::Debug + fmt::Display>(f: &mut fmt::Formatter, data: &D, is_debug: bool) -> fmt::Result {
58+
if is_debug {
59+
fmt::Debug::fmt(data, f)
60+
} else {
61+
fmt::Display::fmt(data, f)
62+
}
4463
}
4564

4665
impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
@@ -89,154 +108,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
89108
}
90109
write!(f, "{:?}", sub)
91110
} else {
92-
match *self {
93-
Terminal::PkK(ref pk) => write!(f, "pk_k({:?})", pk),
94-
Terminal::PkH(ref pk) => write!(f, "pk_h({:?})", pk),
95-
Terminal::RawPkH(ref pkh) => write!(f, "expr_raw_pk_h({:?})", pkh),
96-
Terminal::After(t) => write!(f, "after({})", t),
97-
Terminal::Older(t) => write!(f, "older({})", t),
98-
Terminal::Sha256(ref h) => write!(f, "sha256({})", h),
99-
Terminal::Hash256(ref h) => write!(f, "hash256({})", h),
100-
Terminal::Ripemd160(ref h) => write!(f, "ripemd160({})", h),
101-
Terminal::Hash160(ref h) => write!(f, "hash160({})", h),
102-
Terminal::True => f.write_str("1"),
103-
Terminal::False => f.write_str("0"),
104-
Terminal::AndV(ref l, ref r) => write!(f, "and_v({:?},{:?})", l, r),
105-
Terminal::AndB(ref l, ref r) => write!(f, "and_b({:?},{:?})", l, r),
106-
Terminal::AndOr(ref a, ref b, ref c) => {
107-
if c.node == Terminal::False {
108-
write!(f, "and_n({:?},{:?})", a, b)
109-
} else {
110-
write!(f, "andor({:?},{:?},{:?})", a, b, c)
111-
}
112-
}
113-
Terminal::OrB(ref l, ref r) => write!(f, "or_b({:?},{:?})", l, r),
114-
Terminal::OrD(ref l, ref r) => write!(f, "or_d({:?},{:?})", l, r),
115-
Terminal::OrC(ref l, ref r) => write!(f, "or_c({:?},{:?})", l, r),
116-
Terminal::OrI(ref l, ref r) => write!(f, "or_i({:?},{:?})", l, r),
117-
Terminal::Thresh(k, ref subs) => {
118-
write!(f, "thresh({}", k)?;
119-
for s in subs {
120-
write!(f, ",{:?}", s)?;
121-
}
122-
f.write_str(")")
123-
}
124-
Terminal::Multi(k, ref keys) => {
125-
write!(f, "multi({}", k)?;
126-
for k in keys {
127-
write!(f, ",{:?}", k)?;
128-
}
129-
f.write_str(")")
130-
}
131-
Terminal::MultiA(k, ref keys) => {
132-
write!(f, "multi_a({}", k)?;
133-
for k in keys {
134-
write!(f, ",{}", k)?;
135-
}
136-
f.write_str(")")
137-
}
138-
_ => unreachable!(),
139-
}
111+
self.conditional_fmt(f, true)
140112
}
141113
}
142114
}
143115

144116
impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Terminal<Pk, Ctx> {
145117
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146-
match *self {
147-
Terminal::PkK(ref pk) => write!(f, "pk_k({})", pk),
148-
Terminal::PkH(ref pk) => write!(f, "pk_h({})", pk),
149-
Terminal::RawPkH(ref pkh) => write!(f, "expr_raw_pk_h({})", pkh),
150-
Terminal::After(t) => write!(f, "after({})", t),
151-
Terminal::Older(t) => write!(f, "older({})", t),
152-
Terminal::Sha256(ref h) => write!(f, "sha256({})", h),
153-
Terminal::Hash256(ref h) => write!(f, "hash256({})", h),
154-
Terminal::Ripemd160(ref h) => write!(f, "ripemd160({})", h),
155-
Terminal::Hash160(ref h) => write!(f, "hash160({})", h),
156-
Terminal::True => f.write_str("1"),
157-
Terminal::False => f.write_str("0"),
158-
Terminal::AndV(ref l, ref r) if r.node != Terminal::True => {
159-
write!(f, "and_v({},{})", l, r)
160-
}
161-
Terminal::AndB(ref l, ref r) => write!(f, "and_b({},{})", l, r),
162-
Terminal::AndOr(ref a, ref b, ref c) => {
163-
if c.node == Terminal::False {
164-
write!(f, "and_n({},{})", a, b)
165-
} else {
166-
write!(f, "andor({},{},{})", a, b, c)
167-
}
168-
}
169-
Terminal::OrB(ref l, ref r) => write!(f, "or_b({},{})", l, r),
170-
Terminal::OrD(ref l, ref r) => write!(f, "or_d({},{})", l, r),
171-
Terminal::OrC(ref l, ref r) => write!(f, "or_c({},{})", l, r),
172-
Terminal::OrI(ref l, ref r)
173-
if l.node != Terminal::False && r.node != Terminal::False =>
174-
{
175-
write!(f, "or_i({},{})", l, r)
176-
}
177-
Terminal::Thresh(k, ref subs) => {
178-
write!(f, "thresh({}", k)?;
179-
for s in subs {
180-
write!(f, ",{}", s)?;
181-
}
182-
f.write_str(")")
183-
}
184-
Terminal::Multi(k, ref keys) => {
185-
write!(f, "multi({}", k)?;
186-
for k in keys {
187-
write!(f, ",{}", k)?;
188-
}
189-
f.write_str(")")
190-
}
191-
Terminal::MultiA(k, ref keys) => {
192-
write!(f, "multi_a({}", k)?;
193-
for k in keys {
194-
write!(f, ",{}", k)?;
195-
}
196-
f.write_str(")")
197-
}
198-
// wrappers
199-
_ => {
200-
if let Some((ch, sub)) = self.wrap_char() {
201-
if ch == 'c' {
202-
if let Terminal::PkK(ref pk) = sub.node {
203-
// alias: pk(K) = c:pk_k(K)
204-
return write!(f, "pk({})", pk);
205-
} else if let Terminal::RawPkH(ref pkh) = sub.node {
206-
// `RawPkH` is currently unsupported in the descriptor spec
207-
// alias: pkh(K) = c:pk_h(K)
208-
// We temporarily display there using raw_pkh, but these descriptors
209-
// are not defined in the spec yet. These are prefixed with `expr`
210-
// in the descriptor string.
211-
// We do not support parsing these descriptors yet.
212-
return write!(f, "expr_raw_pkh({})", pkh);
213-
} else if let Terminal::PkH(ref pk) = sub.node {
214-
// alias: pkh(K) = c:pk_h(K)
215-
return write!(f, "pkh({})", pk);
216-
}
217-
}
218-
219-
fmt::Write::write_char(f, ch)?;
220-
match sub.node.wrap_char() {
221-
None => {
222-
fmt::Write::write_char(f, ':')?;
223-
}
224-
// Add a ':' wrapper if there are other wrappers apart from c:pk_k()
225-
// tvc:pk_k() -> tv:pk()
226-
Some(('c', ms)) => match ms.node {
227-
Terminal::PkK(_) | Terminal::PkH(_) | Terminal::RawPkH(_) => {
228-
fmt::Write::write_char(f, ':')?
229-
}
230-
_ => {}
231-
},
232-
_ => {}
233-
};
234-
write!(f, "{}", sub)
235-
} else {
236-
unreachable!();
237-
}
238-
}
239-
}
118+
self.conditional_fmt(f, false)
240119
}
241120
}
242121

0 commit comments

Comments
 (0)