Skip to content

Commit 0c411db

Browse files
committed
reduce binary bloat by removing generic param from type_check
The binary sizes are increased a lot by the use of generics. In one case, there is a lot of needless bloat by using a generic type param for the callback argument in the type_check function of the Property trait. cargo build --example parse --release && du -sb target/release/examples/parse Results in a binary size of 1784152 bytes. With this commit, the binary size is decreased by 12288 bytes, which is significant for embedded/no_std use. The sizes above were achieved by adding this to Cargo.toml: ``` [profile.release] strip = true panic = "abort" opt-level = 's' codegen-units = 1 lto = true ``` Though the difference is roughly the same also without the optimizations. As an additional benefit, code clarity is improved as the child arg was unused in some of the trait implementations.
1 parent d1051cb commit 0c411db

File tree

6 files changed

+78
-53
lines changed

6 files changed

+78
-53
lines changed

src/miniscript/astelem.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
4747
impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
4848
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4949
f.write_str("[")?;
50-
if let Ok(type_map) = types::Type::type_check(self, |_| None) {
50+
if let Ok(type_map) = types::Type::type_check(self) {
5151
f.write_str(match type_map.corr.base {
5252
types::Base::B => "B",
5353
types::Base::K => "K",

src/miniscript/decode.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ use crate::prelude::*;
2525
use crate::Descriptor;
2626
use crate::{bitcoin, hash256, AbsLockTime, Error, Miniscript, MiniscriptKey, ToPublicKey};
2727

28-
fn return_none<T>(_: usize) -> Option<T> {
29-
None
30-
}
31-
3228
/// Trait for parsing keys from byte slices
3329
pub trait ParseableKey: Sized + ToPublicKey + private::Sealed {
3430
/// Parse a key from slice
@@ -223,8 +219,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> TerminalStack<Pk, Ctx> {
223219

224220
///reduce, type check and push a 0-arg node
225221
fn reduce0(&mut self, ms: Terminal<Pk, Ctx>) -> Result<(), Error> {
226-
let ty = Type::type_check(&ms, return_none)?;
227-
let ext = ExtData::type_check(&ms, return_none)?;
222+
let ty = Type::type_check(&ms)?;
223+
let ext = ExtData::type_check(&ms)?;
228224
let ms = Miniscript {
229225
node: ms,
230226
ty,
@@ -244,8 +240,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> TerminalStack<Pk, Ctx> {
244240
let top = self.pop().unwrap();
245241
let wrapped_ms = wrap(Arc::new(top));
246242

247-
let ty = Type::type_check(&wrapped_ms, return_none)?;
248-
let ext = ExtData::type_check(&wrapped_ms, return_none)?;
243+
let ty = Type::type_check(&wrapped_ms)?;
244+
let ext = ExtData::type_check(&wrapped_ms)?;
249245
let ms = Miniscript {
250246
node: wrapped_ms,
251247
ty,
@@ -267,8 +263,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> TerminalStack<Pk, Ctx> {
267263

268264
let wrapped_ms = wrap(Arc::new(left), Arc::new(right));
269265

270-
let ty = Type::type_check(&wrapped_ms, return_none)?;
271-
let ext = ExtData::type_check(&wrapped_ms, return_none)?;
266+
let ty = Type::type_check(&wrapped_ms)?;
267+
let ext = ExtData::type_check(&wrapped_ms)?;
272268
let ms = Miniscript {
273269
node: wrapped_ms,
274270
ty,
@@ -556,8 +552,8 @@ pub fn parse<Ctx: ScriptContext>(
556552
let c = term.pop().unwrap();
557553
let wrapped_ms = Terminal::AndOr(Arc::new(a), Arc::new(c), Arc::new(b));
558554

559-
let ty = Type::type_check(&wrapped_ms, return_none)?;
560-
let ext = ExtData::type_check(&wrapped_ms, return_none)?;
555+
let ty = Type::type_check(&wrapped_ms)?;
556+
let ext = ExtData::type_check(&wrapped_ms)?;
561557

562558
term.0.push(Miniscript {
563559
node: wrapped_ms,

src/miniscript/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
6868
/// Display code of type_check.
6969
pub fn from_ast(t: Terminal<Pk, Ctx>) -> Result<Miniscript<Pk, Ctx>, Error> {
7070
let res = Miniscript {
71-
ty: Type::type_check(&t, |_| None)?,
72-
ext: ExtData::type_check(&t, |_| None)?,
71+
ty: Type::type_check(&t)?,
72+
ext: ExtData::type_check(&t)?,
7373
node: t,
7474
phantom: PhantomData,
7575
};
@@ -269,7 +269,7 @@ impl<Ctx: ScriptContext> Miniscript<Ctx::Key, Ctx> {
269269

270270
let top = decode::parse(&mut iter)?;
271271
Ctx::check_global_validity(&top)?;
272-
let type_check = types::Type::type_check(&top.node, |_| None)?;
272+
let type_check = types::Type::type_check(&top.node)?;
273273
if type_check.corr.base != types::Base::B {
274274
return Err(Error::NonTopLevel(format!("{:?}", top)));
275275
};

src/miniscript/types/extra_props.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -888,14 +888,22 @@ impl Property for ExtData {
888888
})
889889
}
890890

891+
fn type_check_with_child<Pk, Ctx, C>(
892+
_fragment: &Terminal<Pk, Ctx>,
893+
mut _child: C,
894+
) -> Result<Self, Error<Pk, Ctx>>
895+
where
896+
C: FnMut(usize) -> Self,
897+
Pk: MiniscriptKey,
898+
Ctx: ScriptContext,
899+
{
900+
unreachable!()
901+
}
902+
891903
/// Compute the type of a fragment assuming all the children of
892904
/// Miniscript have been computed already.
893-
fn type_check<Pk, Ctx, C>(
894-
fragment: &Terminal<Pk, Ctx>,
895-
_child: C,
896-
) -> Result<Self, Error<Pk, Ctx>>
905+
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
897906
where
898-
C: FnMut(usize) -> Option<Self>,
899907
Ctx: ScriptContext,
900908
Pk: MiniscriptKey,
901909
{

src/miniscript/types/mod.rs

+41-20
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ pub use self::malleability::{Dissat, Malleability};
2020
use super::ScriptContext;
2121
use crate::{MiniscriptKey, Terminal};
2222

23-
/// None-returning function to help type inference when we need a
24-
/// closure that simply returns `None`
25-
fn return_none<T>(_: usize) -> Option<T> {
26-
None
27-
}
28-
2923
/// Detailed type of a typechecker error
3024
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
3125
pub enum ErrorKind {
@@ -374,20 +368,15 @@ pub trait Property: Sized {
374368
/// Compute the type of a fragment, given a function to look up
375369
/// the types of its children, if available and relevant for the
376370
/// given fragment
377-
fn type_check<Pk, Ctx, C>(
378-
fragment: &Terminal<Pk, Ctx>,
379-
mut child: C,
371+
fn type_check_common<'a, Pk, Ctx, C>(
372+
fragment: &'a Terminal<Pk, Ctx>,
373+
mut get_child: C,
380374
) -> Result<Self, Error<Pk, Ctx>>
381375
where
382-
C: FnMut(usize) -> Option<Self>,
376+
C: FnMut(&'a Terminal<Pk, Ctx>, usize) -> Result<Self, Error<Pk, Ctx>>,
383377
Pk: MiniscriptKey,
384378
Ctx: ScriptContext,
385379
{
386-
let mut get_child = |sub, n| {
387-
child(n)
388-
.map(Ok)
389-
.unwrap_or_else(|| Self::type_check(sub, return_none))
390-
};
391380
let wrap_err = |result: Result<Self, ErrorKind>| {
392381
result.map_err(|kind| Error {
393382
fragment: fragment.clone(),
@@ -523,6 +512,30 @@ pub trait Property: Sized {
523512
}
524513
ret
525514
}
515+
516+
/// Compute the type of a fragment, given a function to look up
517+
/// the types of its children.
518+
fn type_check_with_child<Pk, Ctx, C>(
519+
fragment: &Terminal<Pk, Ctx>,
520+
mut child: C,
521+
) -> Result<Self, Error<Pk, Ctx>>
522+
where
523+
C: FnMut(usize) -> Self,
524+
Pk: MiniscriptKey,
525+
Ctx: ScriptContext,
526+
{
527+
let get_child = |_sub, n| Ok(child(n));
528+
Self::type_check_common(fragment, get_child)
529+
}
530+
531+
/// Compute the type of a fragment.
532+
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
533+
where
534+
Pk: MiniscriptKey,
535+
Ctx: ScriptContext,
536+
{
537+
Self::type_check_common(fragment, |sub, _n| Self::type_check(sub))
538+
}
526539
}
527540

528541
impl Property for Type {
@@ -767,14 +780,22 @@ impl Property for Type {
767780
})
768781
}
769782

783+
fn type_check_with_child<Pk, Ctx, C>(
784+
_fragment: &Terminal<Pk, Ctx>,
785+
mut _child: C,
786+
) -> Result<Self, Error<Pk, Ctx>>
787+
where
788+
C: FnMut(usize) -> Self,
789+
Pk: MiniscriptKey,
790+
Ctx: ScriptContext,
791+
{
792+
unreachable!()
793+
}
794+
770795
/// Compute the type of a fragment assuming all the children of
771796
/// Miniscript have been computed already.
772-
fn type_check<Pk, Ctx, C>(
773-
fragment: &Terminal<Pk, Ctx>,
774-
_child: C,
775-
) -> Result<Self, Error<Pk, Ctx>>
797+
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
776798
where
777-
C: FnMut(usize) -> Option<Self>,
778799
Pk: MiniscriptKey,
779800
Ctx: ScriptContext,
780801
{

src/policy/compiler.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
480480
impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
481481
fn terminal(ast: Terminal<Pk, Ctx>) -> AstElemExt<Pk, Ctx> {
482482
AstElemExt {
483-
comp_ext_data: CompilerExtData::type_check(&ast, |_| None).unwrap(),
483+
comp_ext_data: CompilerExtData::type_check(&ast).unwrap(),
484484
ms: Arc::new(Miniscript::from_ast(ast).expect("Terminal creation must always succeed")),
485485
}
486486
}
@@ -491,15 +491,15 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
491491
r: &AstElemExt<Pk, Ctx>,
492492
) -> Result<AstElemExt<Pk, Ctx>, types::Error<Pk, Ctx>> {
493493
let lookup_ext = |n| match n {
494-
0 => Some(l.comp_ext_data),
495-
1 => Some(r.comp_ext_data),
494+
0 => l.comp_ext_data,
495+
1 => r.comp_ext_data,
496496
_ => unreachable!(),
497497
};
498498
//Types and ExtData are already cached and stored in children. So, we can
499499
//type_check without cache. For Compiler extra data, we supply a cache.
500-
let ty = types::Type::type_check(&ast, |_| None)?;
501-
let ext = types::ExtData::type_check(&ast, |_| None)?;
502-
let comp_ext_data = CompilerExtData::type_check(&ast, lookup_ext)?;
500+
let ty = types::Type::type_check(&ast)?;
501+
let ext = types::ExtData::type_check(&ast)?;
502+
let comp_ext_data = CompilerExtData::type_check_with_child(&ast, lookup_ext)?;
503503
Ok(AstElemExt {
504504
ms: Arc::new(Miniscript::from_components_unchecked(ast, ty, ext)),
505505
comp_ext_data,
@@ -513,16 +513,16 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
513513
c: &AstElemExt<Pk, Ctx>,
514514
) -> Result<AstElemExt<Pk, Ctx>, types::Error<Pk, Ctx>> {
515515
let lookup_ext = |n| match n {
516-
0 => Some(a.comp_ext_data),
517-
1 => Some(b.comp_ext_data),
518-
2 => Some(c.comp_ext_data),
516+
0 => a.comp_ext_data,
517+
1 => b.comp_ext_data,
518+
2 => c.comp_ext_data,
519519
_ => unreachable!(),
520520
};
521521
//Types and ExtData are already cached and stored in children. So, we can
522522
//type_check without cache. For Compiler extra data, we supply a cache.
523-
let ty = types::Type::type_check(&ast, |_| None)?;
524-
let ext = types::ExtData::type_check(&ast, |_| None)?;
525-
let comp_ext_data = CompilerExtData::type_check(&ast, lookup_ext)?;
523+
let ty = types::Type::type_check(&ast)?;
524+
let ext = types::ExtData::type_check(&ast)?;
525+
let comp_ext_data = CompilerExtData::type_check_with_child(&ast, lookup_ext)?;
526526
Ok(AstElemExt {
527527
ms: Arc::new(Miniscript::from_components_unchecked(ast, ty, ext)),
528528
comp_ext_data,

0 commit comments

Comments
 (0)