diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-07-16 11:28:09 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-07-16 11:57:26 +0200 |
commit | 67274203bb852749c420f0ef7fd7dec8d55ef4ef (patch) | |
tree | f0cb2814f95af9b256da05dfd91bbfe3e5b9b3ee /ipc | |
parent | 9772cb922c0c5bd406a5572df380b84a0d0f11f5 (diff) |
ipc: Bring in our bag of macros.
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/src/lib.rs | 2 | ||||
-rw-r--r-- | ipc/src/macros.rs | 177 | ||||
-rw-r--r-- | ipc/src/trace.rs | 63 |
3 files changed, 178 insertions, 64 deletions
diff --git a/ipc/src/lib.rs b/ipc/src/lib.rs index 10b1b563..9cb0fe1f 100644 --- a/ipc/src/lib.rs +++ b/ipc/src/lib.rs @@ -65,7 +65,7 @@ use std::thread; use sequoia_openpgp as openpgp; -#[macro_use] mod trace; +#[macro_use] mod macros; pub mod assuan; pub mod gnupg; pub mod keybox; diff --git a/ipc/src/macros.rs b/ipc/src/macros.rs new file mode 100644 index 00000000..18ace037 --- /dev/null +++ b/ipc/src/macros.rs @@ -0,0 +1,177 @@ +use std::cmp; + +macro_rules! trace { + ( $TRACE:expr, $fmt:expr, $($pargs:expr),* ) => { + if $TRACE { + eprintln!($fmt, $($pargs),*); + } + }; + ( $TRACE:expr, $fmt:expr ) => { + trace!($TRACE, $fmt, ); + }; +} + +// Converts an indentation level to whitespace. +pub(crate) fn indent(i: isize) -> &'static str { + use std::convert::TryFrom; + let s = " "; + &s[0..cmp::min(usize::try_from(i).unwrap_or(0), s.len())] +} + +macro_rules! tracer { + ( $TRACE:expr, $func:expr ) => { + tracer!($TRACE, $func, 0) + }; + ( $TRACE:expr, $func:expr, $indent:expr ) => { + // Currently, Rust doesn't support $( ... ) in a nested + // macro's definition. See: + // https://users.rust-lang.org/t/nested-macros-issue/8348/2 + macro_rules! t { + ( $fmt:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, $fmt) }; + ( $fmt:expr, $a:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a)) }; + ( $fmt:expr, $a:expr, $b:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e, $f)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h, $i)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j)) }; + ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr ) => + { trace!($TRACE, "{}{}: {}", crate::macros::indent($indent), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k)) }; + } + } +} + + +/// A very simple profiling tool. +/// +/// Note: don't ever profile code that has not been compiled in +/// release mode. There can be orders of magnitude difference in +/// execution time between it and debug mode! +/// +/// This macro measures the wall time it takes to execute the block. +/// If the time is at least $ms_threshold (in milli-seconds), then it +/// displays the output on stderr. The output is prefixed with label, +/// if it is provided. +/// +/// ``` +/// let result = time_it!("Some code", 10, { +/// // Some code. +/// 5 +/// }); +/// assert_eq!(result, 5); +/// ``` +#[allow(unused_macros)] +macro_rules! time_it { + ( $label:expr, $ms_threshold:expr, $body:expr ) => {{ + use std::time::{SystemTime, Duration}; + + // We use drop so that code that uses non-local exits (e.g., + // using break 'label) still works. + struct Timer { + start: SystemTime, + }; + impl Drop for Timer { + fn drop(&mut self) { + let elapsed = self.start.elapsed(); + if elapsed.clone().unwrap_or(Duration::from_millis($ms_threshold)) + >= Duration::from_millis($ms_threshold) + { + if $label.len() > 0 { + eprint!("{}:", $label); + } + eprintln!("{}:{}: {:?}", file!(), line!(), elapsed); + } + } + } + + let _start = Timer { start: SystemTime::now() }; + $body + }}; + ( $label:expr, $body:expr ) => { + time_it!($label, 0, $body) + }; + ( $body:expr ) => { + time_it!("", $body) + }; +} + +/// A simple shortcut for ensuring a type is send and sync. +/// +/// For most types just call it after defining the type: +/// +/// ``` +/// pub struct MyStruct {} +/// assert_send_and_sync!(MyStruct); +/// ``` +/// +/// For types with lifetimes, use the anonymous lifetime: +/// +/// ``` +/// pub struct WithLifetime<'a> {} +/// assert_send_and_sync!(MyStruct<'_>); +/// ``` +/// +/// For a type generic over another type `W`, +/// pass the type `W` as a where clause +/// including a trait bound when needed: +/// +/// ``` +/// pub struct MyWriter<W: io::Write> {} +/// assert_send_and_sync!(MyWriterStruct<W> where W: io::Write); +/// ``` +/// +/// This will assert that `MyWriterStruct<W>` is `Send` and `Sync` +/// if `W` is `Send` and `Sync`. +/// +/// You can also combine the two and be generic over multiple types. +/// Just make sure to list all the types - even those without additional +/// trait bounds: +/// +/// ``` +/// pub struct MyWriterWithLifetime<a', C, W: io::Write> {} +/// assert_send_and_sync!(MyWriterStruct<'_, C, W> where C, W: io::Write); +/// ``` +/// +/// If you need multiple additional trait bounds on a single type +/// you can add them separated by `+` like in normal where clauses. +/// However you have to make sure they are `Identifiers` like `Write`. +/// In macro patterns `Paths` (like `io::Write`) may not be followed +/// by `+` characters. +macro_rules! assert_send_and_sync { + ( $x:ty where $( $g:ident$( : $a:path )? $(,)?)*) => { + impl<$( $g ),*> crate::types::Sendable for $x + where $( $g: Send + Sync $( + $a )? ),* + {} + impl<$( $g ),*> crate::types::Syncable for $x + where $( $g: Send + Sync $( + $a )? ),* + {} + }; + ( $x:ty where $( $g:ident$( : $a:ident $( + $b:ident )* )? $(,)?)*) => { + impl<$( $g ),*> crate::types::Sendable for $x + where $( $g: Send + Sync $( + $a $( + $b )* )? ),* + {} + impl<$( $g ),*> crate::types::Syncable for $x + where $( $g: Send + Sync $( + $a $( + $b )* )? ),* + {} + }; + ( $x:ty ) => { + impl crate::macros::Sendable for $x {} + impl crate::macros::Syncable for $x {} + }; +} +pub(crate) trait Sendable : Send {} +pub(crate) trait Syncable : Sync {} diff --git a/ipc/src/trace.rs b/ipc/src/trace.rs deleted file mode 100644 index c93e1e04..00000000 --- a/ipc/src/trace.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::cmp; - -macro_rules! trace { - ( $TRACE:expr, $fmt:expr, $($pargs:expr),* ) => { - if $TRACE { - eprintln!($fmt, $($pargs),*); - } - }; - ( $TRACE:expr, $fmt:expr ) => { - trace!($TRACE, $fmt, ); - }; -} - -// Converts an indentation level to whitespace. -pub(crate) fn indent(i: usize) -> &'static str { - let s = " "; - &s[0..cmp::min(i, s.len())] -} - -// A very simply tracer. -// -// ```text -// tracer!(enable_predicate, "function_name"); -// t!("(arg1: {:?}, arg2: {:?})", arg1, arg2); -// ... -// t!("=> {:?}", return_value); -// ``` -macro_rules! tracer { - ( $TRACE:expr, $func:expr ) => { - tracer!($TRACE, $func, 0) - }; - ( $TRACE:expr, $func:expr, $indent:expr ) => { - // Currently, Rust doesn't support $( ... ) in a nested - // macro's definition. See: - // https://users.rust-lang.org/t/nested-macros-issue/8348/2 - macro_rules! t { - ( $fmt:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, $fmt) }; - ( $fmt:expr, $a:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a)) }; - ( $fmt:expr, $a:expr, $b:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e, $f)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h, $i)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j)) }; - ( $fmt:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr ) => - { trace!($TRACE, "{}{}: {}", crate::trace::indent($indent as usize), $func, format!($fmt, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k)) }; - } - }; -} |