summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openpgp/NEWS1
-rw-r--r--openpgp/src/packet/any.rs158
-rw-r--r--openpgp/src/packet/mod.rs3
-rw-r--r--openpgp/src/packet/prelude.rs1
4 files changed, 163 insertions, 0 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index a66dae21..c458e9bc 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -4,6 +4,7 @@
* Changes in 1.9.0
** New functionality
+ - packet::Any
- Packet::version
- SignatureBuilder::set_reference_time
- SignatureBuilder::effective_signature_creation_time
diff --git a/openpgp/src/packet/any.rs b/openpgp/src/packet/any.rs
new file mode 100644
index 00000000..8af73eaf
--- /dev/null
+++ b/openpgp/src/packet/any.rs
@@ -0,0 +1,158 @@
+//! Convenient downcasting from Packets to Packet Bodies.
+
+use crate::packet::{
+ Packet,
+ Unknown,
+ Signature,
+ OnePassSig,
+ key::{
+ PublicKey,
+ PublicSubkey,
+ SecretKey,
+ SecretSubkey,
+ },
+ Marker,
+ Trust,
+ UserID,
+ UserAttribute,
+ Literal,
+ CompressedData,
+ PKESK,
+ SKESK,
+ SEIP,
+ MDC,
+ AED,
+};
+
+/// Convenient downcasting from Packets to Packet Bodies.
+///
+/// This trait offers functionality similar to [`std::any::Any`],
+/// hence the name.
+///
+/// # Sealed trait
+///
+/// This trait is [sealed] and cannot be implemented for types outside
+/// this crate. Therefore it can be extended in a non-breaking way.
+///
+/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
+pub trait Any<T>: crate::seal::Sealed {
+ /// Attempts to downcast to `T`, returning the packet if it fails.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use sequoia_openpgp::packet::prelude::*;
+ /// let p: Packet = Marker::default().into();
+ /// let m: Marker = p.downcast().unwrap();
+ /// # let _ = m;
+ /// ```
+ fn downcast(self) -> std::result::Result<T, Packet>;
+
+ /// Attempts to downcast to `&T`, returning `None` if it fails.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use sequoia_openpgp::packet::prelude::*;
+ /// let p: Packet = Marker::default().into();
+ /// let m: &Marker = p.downcast_ref().unwrap();
+ /// # let _ = m;
+ /// ```
+ fn downcast_ref(&self) -> Option<&T>;
+
+ /// Attempts to downcast to `&mut T`, returning `None` if it fails.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use sequoia_openpgp::packet::prelude::*;
+ /// let mut p: Packet = Marker::default().into();
+ /// let m: &mut Marker = p.downcast_mut().unwrap();
+ /// # let _ = m;
+ /// ```
+ fn downcast_mut(&mut self) -> Option<&mut T>;
+}
+
+macro_rules! impl_downcast_for {
+ ($typ: tt) => {
+ impl Any<$typ> for Packet {
+ fn downcast(self) -> std::result::Result<$typ, Packet> {
+ match self {
+ Packet::$typ(v) => Ok(v),
+ p => Err(p),
+ }
+ }
+
+ fn downcast_ref(&self) -> Option<&$typ> {
+ match self {
+ Packet::$typ(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ fn downcast_mut(&mut self) -> Option<&mut $typ> {
+ match self {
+ Packet::$typ(v) => Some(v),
+ _ => None,
+ }
+ }
+ }
+ };
+}
+
+macro_rules! impl_downcasts {
+ ($($typ:ident, )*) => {
+ $(impl_downcast_for!($typ);)*
+
+ /// Checks that all packet types have implementations of `Any`.
+ ///
+ /// Not visible outside this module, isn't supposed to be
+ /// called, this is a compile-time check.
+ #[allow(unused)]
+ fn check_exhaustion(p: Packet) {
+ match p {
+ $(Packet::$typ(_) => (),)*
+ }
+ }
+ }
+}
+
+impl_downcasts!(
+ Unknown,
+ Signature,
+ OnePassSig,
+ PublicKey,
+ PublicSubkey,
+ SecretKey,
+ SecretSubkey,
+ Marker,
+ Trust,
+ UserID,
+ UserAttribute,
+ Literal,
+ CompressedData,
+ PKESK,
+ SKESK,
+ SEIP,
+ MDC,
+ AED,
+);
+
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn downcast() {
+ let p: Packet = Marker::default().into();
+ let mut p = Any::<UserID>::downcast(p).unwrap_err();
+ let r: Option<&UserID> = p.downcast_ref();
+ assert!(r.is_none());
+ let r: Option<&mut UserID> = p.downcast_mut();
+ assert!(r.is_none());
+ let _: &Marker = p.downcast_ref().unwrap();
+ let _: &mut Marker = p.downcast_mut().unwrap();
+ let _: Marker = p.downcast().unwrap();
+ }
+}
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs
index 991d3e38..b112eaf2 100644
--- a/openpgp/src/packet/mod.rs
+++ b/openpgp/src/packet/mod.rs
@@ -173,6 +173,9 @@ use crate::crypto::{
Password,
};
+mod any;
+pub use self::any::Any;
+
mod tag;
pub use self::tag::Tag;
pub mod header;
diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs
index 74b96284..3a1e6d88 100644
--- a/openpgp/src/packet/prelude.rs
+++ b/openpgp/src/packet/prelude.rs
@@ -22,6 +22,7 @@
pub use crate::packet::{
AED,
+ Any,
Body,
CompressedData,
Container,