From c8864666e0160870c328d0c2b6cb2c7e85661298 Mon Sep 17 00:00:00 2001 From: Guillaume Endignoux Date: Tue, 9 Jun 2020 17:41:42 +0200 Subject: [PATCH] Extract some logic to a separate function, to reduce binary size overhead of read_cbor_map. --- libraries/cbor/src/macros.rs | 67 +++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/libraries/cbor/src/macros.rs b/libraries/cbor/src/macros.rs index 5814a2a..29d76b1 100644 --- a/libraries/cbor/src/macros.rs +++ b/libraries/cbor/src/macros.rs @@ -12,6 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::values::{KeyType, Value}; +use alloc::collections::btree_map; +use core::cmp::Ordering; +use core::iter::Peekable; + /// This macro generates code to extract multiple values from a `BTreeMap` at once /// in an optimized manner, consuming the input map. /// @@ -65,39 +70,47 @@ macro_rules! read_cbor_map { #[cfg(test)] test_ordered_keys!($( $key, )+); - use $crate::values::{IntoCborKey, KeyType, Value}; - use ::core::cmp::Ordering; - use ::core::iter::Peekable; - use ::alloc::collections::btree_map::IntoIter; + use $crate::values::{IntoCborKey, Value}; + use $crate::macros::read_cbor_map_peek_value; - let mut it: Peekable> = $map.into_iter().peekable(); + let mut it = $map.into_iter().peekable(); $( - let $variable: Option = { - let needle: KeyType = $key.into_cbor_key(); - loop { - match it.peek() { - None => break None, - Some(item) => { - let key: &KeyType = &item.0; - match key.cmp(&needle) { - Ordering::Less => { - it.next(); - continue - }, - Ordering::Equal => { - let value: Value = it.next().unwrap().1; - break Some(value) - }, - Ordering::Greater => break None, - } - } - } - } - }; + let $variable: Option = read_cbor_map_peek_value(&mut it, $key.into_cbor_key()); )+ }; } +/// This function is an internal detail of the `read_cbor_map!` macro, but has public visibility so +/// that users of the macro can use it. +/// +/// The logic is separated into its own function to reduce binary size, as otherwise the logic +/// would be inlined for every use case. As of June 2020, this saves ~40KB of binary size for the +/// CTAP2 application of OpenSK. +pub fn read_cbor_map_peek_value( + it: &mut Peekable>, + needle: KeyType, +) -> Option { + loop { + match it.peek() { + None => return None, + Some(item) => { + let key: &KeyType = &item.0; + match key.cmp(&needle) { + Ordering::Less => { + it.next(); + continue; + } + Ordering::Equal => { + let value: Value = it.next().unwrap().1; + return Some(value); + } + Ordering::Greater => return None, + } + } + } + } +} + #[macro_export] macro_rules! test_ordered_keys { // Last key