From 50a8131156684353cb51f62c2ea5fa9d7be5c549 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 12 Dec 2023 11:37:20 +0100 Subject: openpgp: Tweak lifetime of filter function's argument. - Previously, the filter operated on references with the lifetime 'a only, which is the lifetime associated with the Cert the TSK object references. Change the signature to take a reference with an anonymous lifetime instead. - This makes the filter more general, but it can no longer rely on the fact that the references are live for 'a. However, the function is a Fn, not a FnMut, and returns a bool, so the function cannot store the reference anywhere, so this shouldn't make a difference in practice. - Annoyingly, there is a wrinkle. If a closure bound to an identifier is given to TSK::set_filter, the Rust compiler incorrectly (or over eagerly?) specializes the function in a way that it doesn't match the callback's prototype: error[E0308]: mismatched types --> openpgp/src/serialize/cert.rs:946:16 | 946 | check!(tsk_0.as_tsk().set_filter(no_secrets), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected trait `for<'a> Fn<(&'a packet::Key,)>` found trait `Fn<(&packet::Key,)>` note: this closure does not fulfill the lifetime requirements --> openpgp/src/serialize/cert.rs:940:26 | 940 | let no_secrets = |_| false; | ^^^ note: the lifetime requirement is introduced here --> openpgp/src/serialize/cert.rs:318:23 | 318 | where P: 'a + Fn(&key::UnspecifiedSecret) -> bool | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of `FnOnce` is not general enough --> openpgp/src/serialize/cert.rs:946:16 | 946 | check!(tsk_0.as_tsk().set_filter(no_secrets), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'2 packet::Key) -> bool` must implement `FnOnce<(&'1 packet::Key,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 packet::Key,)>`, for some specific lifetime `'2` This is easily fixed by providing a partial type for the callback's argument. This commit includes a tweak for our test. --- openpgp/src/serialize/cert.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'openpgp') diff --git a/openpgp/src/serialize/cert.rs b/openpgp/src/serialize/cert.rs index 4d98569a..83e804ed 100644 --- a/openpgp/src/serialize/cert.rs +++ b/openpgp/src/serialize/cert.rs @@ -294,7 +294,7 @@ impl Cert { /// ``` pub struct TSK<'a> { pub(crate) cert: &'a Cert, - filter: Box bool + 'a>, + filter: Box bool + 'a>, emit_stubs: bool, } @@ -385,7 +385,7 @@ impl<'a> TSK<'a> { /// # Ok(()) } /// ``` pub fn set_filter

(mut self, predicate: P) -> Self - where P: 'a + Fn(&'a key::UnspecifiedSecret) -> bool + where P: 'a + Fn(&key::UnspecifiedSecret) -> bool { self.filter = Box::new(predicate); self @@ -1029,7 +1029,7 @@ mod test { check!(&cert_0, &tsk_0, true); // Filters out secrets. - let no_secrets = |_| false; + let no_secrets = |_: &_| false; // TSK's equality. check!(tsk_0.as_tsk(), tsk_1.as_tsk(), true); @@ -1070,7 +1070,7 @@ mod test { let tsk = Cert::from_bytes(crate::tests::key("testy-private.pgp"))?; // Filters out secrets. - let no_secrets = |_| false; + let no_secrets = |_: &_| false; assert!(! cert.as_tsk().emits_secret_key_packets()); assert!(cert.as_tsk().emit_secret_key_stubs(true) -- cgit v1.2.3