Skip to main content

sequoia_openpgp/packet/
any.rs

1//! Convenient downcasting from Packets to Packet Bodies.
2
3use crate::packet::{
4    Packet,
5    Unknown,
6    Signature,
7    OnePassSig,
8    Key,
9    key,
10    Marker,
11    Trust,
12    UserID,
13    UserAttribute,
14    Literal,
15    CompressedData,
16    PKESK,
17    SKESK,
18    SEIP,
19    MDC,
20    Padding,
21};
22
23/// Convenient downcasting from Packets to Packet Bodies.
24///
25/// This trait offers functionality similar to [`std::any::Any`],
26/// hence the name.
27///
28/// # Sealed trait
29///
30/// This trait is [sealed] and cannot be implemented for types outside
31/// this crate.  Therefore it can be extended in a non-breaking way.
32///
33/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
34pub trait Any<T>: crate::seal::Sealed {
35    /// Attempts to downcast to `T`, returning the packet if it fails.
36    ///
37    /// # Examples
38    ///
39    /// ```rust
40    /// # use sequoia_openpgp::packet::prelude::*;
41    /// let p: Packet = Marker::default().into();
42    /// let m: Marker = p.downcast().unwrap();
43    /// # let _ = m;
44    /// ```
45    #[expect(clippy::result_large_err, reason = "returning the value on error is intentional")]
46    fn downcast(self) -> std::result::Result<T, Packet>;
47
48    /// Attempts to downcast to `&T`, returning `None` if it fails.
49    ///
50    /// # Examples
51    ///
52    /// ```rust
53    /// # use sequoia_openpgp::packet::prelude::*;
54    /// let p: Packet = Marker::default().into();
55    /// let m: &Marker = p.downcast_ref().unwrap();
56    /// # let _ = m;
57    /// ```
58    fn downcast_ref(&self) -> Option<&T>;
59
60    /// Attempts to downcast to `&mut T`, returning `None` if it fails.
61    ///
62    /// # Examples
63    ///
64    /// ```rust
65    /// # use sequoia_openpgp::packet::prelude::*;
66    /// let mut p: Packet = Marker::default().into();
67    /// let m: &mut Marker = p.downcast_mut().unwrap();
68    /// # let _ = m;
69    /// ```
70    fn downcast_mut(&mut self) -> Option<&mut T>;
71}
72
73macro_rules! impl_downcast_for {
74    ($typ: tt) => {
75        impl_downcast_for!($typ => $typ);
76    };
77    ($($typ: tt)|* => $subtyp: ty) => {
78        #[allow(deprecated)]
79        impl Any<$subtyp> for Packet {
80            fn downcast(self) -> std::result::Result<$subtyp, Packet> {
81                match self {
82                    $(Packet::$typ(v) => Ok(v.into()),)*
83                    p => Err(p),
84                }
85            }
86
87            fn downcast_ref(&self) -> Option<&$subtyp> {
88                match self {
89                    $(Packet::$typ(v) => Some(v.into()),)*
90                    _ => None,
91                }
92            }
93
94            fn downcast_mut(&mut self) -> Option<&mut $subtyp> {
95                match self {
96                    $(Packet::$typ(v) => Some(v.into()),)*
97                    _ => None,
98                }
99            }
100        }
101    };
102}
103
104macro_rules! impl_downcasts {
105    ($($typ:ident, )*) => {
106        $(impl_downcast_for!($typ);)*
107
108        /// Checks that all packet types have implementations of `Any`.
109        ///
110        /// Not visible outside this module, isn't supposed to be
111        /// called, this is a compile-time check.
112        #[allow(unused, deprecated)]
113        fn check_exhaustion(p: Packet) {
114            match p {
115                $(Packet::$typ(_) => (),)*
116                // The downcasts to Key<P, R> are handled below.
117                Packet::PublicKey(_) => (),
118                Packet::PublicSubkey(_) => (),
119                Packet::SecretKey(_) => (),
120                Packet::SecretSubkey(_) => (),
121            }
122        }
123    }
124}
125
126impl_downcasts!(
127    Unknown,
128    Signature,
129    OnePassSig,
130    Marker,
131    Trust,
132    UserID,
133    UserAttribute,
134    Literal,
135    CompressedData,
136    PKESK,
137    SKESK,
138    SEIP,
139    MDC,
140    Padding,
141);
142
143// We ow selectively implement downcasts for the key types that alias
144// with the packet type.
145
146// 1. PublicParts, any role.
147impl_downcast_for!(PublicKey | SecretKey
148                   => Key<key::PublicParts, key::PrimaryRole>);
149impl_downcast_for!(PublicSubkey | SecretSubkey
150                   => Key<key::PublicParts, key::SubordinateRole>);
151impl_downcast_for!(PublicKey | PublicSubkey | SecretKey | SecretSubkey
152                   => Key<key::PublicParts, key::UnspecifiedRole>);
153
154// 2. SecretParts, any role.
155impl_downcast_for!(SecretKey
156                   => Key<key::SecretParts, key::PrimaryRole>);
157impl_downcast_for!(SecretSubkey
158                   => Key<key::SecretParts, key::SubordinateRole>);
159impl_downcast_for!(SecretKey | SecretSubkey
160                   => Key<key::SecretParts, key::UnspecifiedRole>);
161
162// 3. UnspecifiedParts, any role.
163impl_downcast_for!(PublicKey | SecretKey
164                   => Key<key::UnspecifiedParts, key::PrimaryRole>);
165impl_downcast_for!(PublicSubkey | SecretSubkey
166                   => Key<key::UnspecifiedParts, key::SubordinateRole>);
167impl_downcast_for!(PublicKey | PublicSubkey | SecretKey | SecretSubkey
168                   => Key<key::UnspecifiedParts, key::UnspecifiedRole>);
169
170#[cfg(test)]
171mod test {
172    use super::*;
173
174    #[test]
175    fn downcast() {
176        let p: Packet = Marker::default().into();
177        let mut p = Any::<UserID>::downcast(p).unwrap_err();
178        let r: Option<&UserID> = p.downcast_ref();
179        assert!(r.is_none());
180        let r: Option<&mut UserID> = p.downcast_mut();
181        assert!(r.is_none());
182        let _: &Marker = p.downcast_ref().unwrap();
183        let _: &mut Marker = p.downcast_mut().unwrap();
184        let _: Marker = p.downcast().unwrap();
185    }
186}