From 7fefbc950a9fc39437a89443dc5eb8ad824a7bb0 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Wed, 24 Jan 2024 09:47:01 +0100 Subject: openpgp: Add UserID::from_static_bytes, which is constant. - Add `UserID::from_static_bytes`, which is equivalent to `UserID::from` for a byte slice, but is a constant function. --- openpgp/NEWS | 1 + openpgp/src/packet/mod.rs | 12 ++++++++++++ openpgp/src/packet/userid.rs | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 6 deletions(-) (limited to 'openpgp') diff --git a/openpgp/NEWS b/openpgp/NEWS index 9b8204f4..d5b7debf 100644 --- a/openpgp/NEWS +++ b/openpgp/NEWS @@ -16,6 +16,7 @@ - armor::Reader::from_buffered_reader - Cert::exportable - CertBuilder::set_exportable + - UserID::from_static_bytes * Changes in 1.17.0 ** Notable fixes - Sequoia now ignores some formatting errors when reading secret diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs index 3a773a3a..68058053 100644 --- a/openpgp/src/packet/mod.rs +++ b/openpgp/src/packet/mod.rs @@ -610,6 +610,18 @@ pub struct Common { } assert_send_and_sync!(Common); +impl Common { + /// Returns a default version of `Common`. + /// + /// This is equivalent to using `Common::from`, but the function + /// is constant. + pub(crate) const fn new() -> Self { + Common { + dummy: std::marker::PhantomData + } + } +} + #[cfg(test)] impl Arbitrary for Common { fn arbitrary(_: &mut Gen) -> Self { diff --git a/openpgp/src/packet/userid.rs b/openpgp/src/packet/userid.rs index 53613d4d..6abc9d5c 100644 --- a/openpgp/src/packet/userid.rs +++ b/openpgp/src/packet/userid.rs @@ -472,20 +472,44 @@ pub struct UserID { /// [RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.11 /// /// Use `UserID::default()` to get a UserID with a default settings. - value: Vec, + value: Cow<'static, [u8]>, - hash_algo_security: HashAlgoSecurity, + hash_algo_security: OnceCell, parsed: OnceCell, } assert_send_and_sync!(UserID); +impl UserID { + /// Returns a User ID. + /// + /// This is equivalent to using `UserID::from`, but the function + /// is constant, and the slice must have a static lifetime. + /// + /// # Examples + /// + /// ``` + /// use sequoia_openpgp::packet::UserID; + /// + /// const TRUST_ROOT_USERID: UserID + /// = UserID::from_static_bytes(b"Local Trust Root"); + /// ``` + pub const fn from_static_bytes(u: &'static [u8]) -> Self { + UserID { + common: packet::Common::new(), + hash_algo_security: OnceCell::new(), + value: Cow::Borrowed(u), + parsed: OnceCell::new(), + } + } +} + impl From> for UserID { fn from(u: Vec) -> Self { UserID { common: Default::default(), - hash_algo_security: UserID::determine_hash_algo_security(&u), - value: u, + hash_algo_security: Default::default(), + value: Cow::Owned(u), parsed: Default::default(), } } @@ -570,7 +594,7 @@ impl Clone for UserID { fn clone(&self) -> Self { UserID { common: self.common.clone(), - hash_algo_security: self.hash_algo_security, + hash_algo_security: self.hash_algo_security.clone(), value: self.value.clone(), parsed: if let Some(p) = self.parsed.get() { OnceCell::with_value(p.clone()) @@ -729,6 +753,10 @@ impl UserID { /// [HashAlgoSecurity]: crate::policy::HashAlgoSecurity pub fn hash_algo_security(&self) -> HashAlgoSecurity { self.hash_algo_security + .get_or_init(|| { + UserID::determine_hash_algo_security(&self.value) + }) + .clone() } // See documentation for hash_algo_security. @@ -846,7 +874,7 @@ impl UserID { /// [`UserID::comment`]: UserID::comment() /// [conventional User ID]: #conventional-user-ids pub fn value(&self) -> &[u8] { - self.value.as_slice() + &self.value } fn do_parse(&self) -> Result<&ConventionallyParsedUserID> { -- cgit v1.2.3