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    fn downcast(self) -> std::result::Result<T, Packet>;
46
47    /// Attempts to downcast to `&T`, returning `None` if it fails.
48    ///
49    /// # Examples
50    ///
51    /// ```rust
52    /// # use sequoia_openpgp::packet::prelude::*;
53    /// let p: Packet = Marker::default().into();
54    /// let m: &Marker = p.downcast_ref().unwrap();
55    /// # let _ = m;
56    /// ```
57    fn downcast_ref(&self) -> Option<&T>;
58
59    /// Attempts to downcast to `&mut T`, returning `None` if it fails.
60    ///
61    /// # Examples
62    ///
63    /// ```rust
64    /// # use sequoia_openpgp::packet::prelude::*;
65    /// let mut p: Packet = Marker::default().into();
66    /// let m: &mut Marker = p.downcast_mut().unwrap();
67    /// # let _ = m;
68    /// ```
69    fn downcast_mut(&mut self) -> Option<&mut T>;
70}
71
72macro_rules! impl_downcast_for {
73    ($typ: tt) => {
74        impl_downcast_for!($typ => $typ);
75    };
76    ($($typ: tt)|* => $subtyp: ty) => {
77        #[allow(deprecated)]
78        impl Any<$subtyp> for Packet {
79            fn downcast(self) -> std::result::Result<$subtyp, Packet> {
80                match self {
81                    $(Packet::$typ(v) => Ok(v.into()),)*
82                    p => Err(p),
83                }
84            }
85
86            fn downcast_ref(&self) -> Option<&$subtyp> {
87                match self {
88                    $(Packet::$typ(v) => Some(v.into()),)*
89                    _ => None,
90                }
91            }
92
93            fn downcast_mut(&mut self) -> Option<&mut $subtyp> {
94                match self {
95                    $(Packet::$typ(v) => Some(v.into()),)*
96                    _ => None,
97                }
98            }
99        }
100    };
101}
102
103macro_rules! impl_downcasts {
104    ($($typ:ident, )*) => {
105        $(impl_downcast_for!($typ);)*
106
107        /// Checks that all packet types have implementations of `Any`.
108        ///
109        /// Not visible outside this module, isn't supposed to be
110        /// called, this is a compile-time check.
111        #[allow(unused, deprecated)]
112        fn check_exhaustion(p: Packet) {
113            match p {
114                $(Packet::$typ(_) => (),)*
115                // The downcasts to Key<P, R> are handled below.
116                Packet::PublicKey(_) => (),
117                Packet::PublicSubkey(_) => (),
118                Packet::SecretKey(_) => (),
119                Packet::SecretSubkey(_) => (),
120            }
121        }
122    }
123}
124
125impl_downcasts!(
126    Unknown,
127    Signature,
128    OnePassSig,
129    Marker,
130    Trust,
131    UserID,
132    UserAttribute,
133    Literal,
134    CompressedData,
135    PKESK,
136    SKESK,
137    SEIP,
138    MDC,
139    Padding,
140);
141
142// We ow selectively implement downcasts for the key types that alias
143// with the packet type.
144
145// 1. PublicParts, any role.
146impl_downcast_for!(PublicKey | SecretKey
147                   => Key<key::PublicParts, key::PrimaryRole>);
148impl_downcast_for!(PublicSubkey | SecretSubkey
149                   => Key<key::PublicParts, key::SubordinateRole>);
150impl_downcast_for!(PublicKey | PublicSubkey | SecretKey | SecretSubkey
151                   => Key<key::PublicParts, key::UnspecifiedRole>);
152
153// 2. SecretParts, any role.
154impl_downcast_for!(SecretKey
155                   => Key<key::SecretParts, key::PrimaryRole>);
156impl_downcast_for!(SecretSubkey
157                   => Key<key::SecretParts, key::SubordinateRole>);
158impl_downcast_for!(SecretKey | SecretSubkey
159                   => Key<key::SecretParts, key::UnspecifiedRole>);
160
161// 3. UnspecifiedParts, any role.
162impl_downcast_for!(PublicKey | SecretKey
163                   => Key<key::UnspecifiedParts, key::PrimaryRole>);
164impl_downcast_for!(PublicSubkey | SecretSubkey
165                   => Key<key::UnspecifiedParts, key::SubordinateRole>);
166impl_downcast_for!(PublicKey | PublicSubkey | SecretKey | SecretSubkey
167                   => Key<key::UnspecifiedParts, key::UnspecifiedRole>);
168
169#[cfg(test)]
170mod test {
171    use super::*;
172
173    #[test]
174    fn downcast() {
175        let p: Packet = Marker::default().into();
176        let mut p = Any::<UserID>::downcast(p).unwrap_err();
177        let r: Option<&UserID> = p.downcast_ref();
178        assert!(r.is_none());
179        let r: Option<&mut UserID> = p.downcast_mut();
180        assert!(r.is_none());
181        let _: &Marker = p.downcast_ref().unwrap();
182        let _: &mut Marker = p.downcast_mut().unwrap();
183        let _: Marker = p.downcast().unwrap();
184    }
185}