use crate::packet::{
Packet,
Unknown,
Signature,
OnePassSig,
Key,
key,
Marker,
Trust,
UserID,
UserAttribute,
Literal,
CompressedData,
PKESK,
SKESK,
SEIP,
MDC,
Padding,
};
pub trait Any<T>: crate::seal::Sealed {
fn downcast(self) -> std::result::Result<T, Packet>;
fn downcast_ref(&self) -> Option<&T>;
fn downcast_mut(&mut self) -> Option<&mut T>;
}
macro_rules! impl_downcast_for {
($typ: tt) => {
impl_downcast_for!($typ => $typ);
};
($($typ: tt)|* => $subtyp: ty) => {
#[allow(deprecated)]
impl Any<$subtyp> for Packet {
fn downcast(self) -> std::result::Result<$subtyp, Packet> {
match self {
$(Packet::$typ(v) => Ok(v.into()),)*
p => Err(p),
}
}
fn downcast_ref(&self) -> Option<&$subtyp> {
match self {
$(Packet::$typ(v) => Some(v.into()),)*
_ => None,
}
}
fn downcast_mut(&mut self) -> Option<&mut $subtyp> {
match self {
$(Packet::$typ(v) => Some(v.into()),)*
_ => None,
}
}
}
};
}
macro_rules! impl_downcasts {
($($typ:ident, )*) => {
$(impl_downcast_for!($typ);)*
#[allow(unused, deprecated)]
fn check_exhaustion(p: Packet) {
match p {
$(Packet::$typ(_) => (),)*
Packet::PublicKey(_) => (),
Packet::PublicSubkey(_) => (),
Packet::SecretKey(_) => (),
Packet::SecretSubkey(_) => (),
}
}
}
}
impl_downcasts!(
Unknown,
Signature,
OnePassSig,
Marker,
Trust,
UserID,
UserAttribute,
Literal,
CompressedData,
PKESK,
SKESK,
SEIP,
MDC,
Padding,
);
impl_downcast_for!(PublicKey | SecretKey
=> Key<key::PublicParts, key::PrimaryRole>);
impl_downcast_for!(PublicSubkey | SecretSubkey
=> Key<key::PublicParts, key::SubordinateRole>);
impl_downcast_for!(PublicKey | PublicSubkey | SecretKey | SecretSubkey
=> Key<key::PublicParts, key::UnspecifiedRole>);
impl_downcast_for!(SecretKey
=> Key<key::SecretParts, key::PrimaryRole>);
impl_downcast_for!(SecretSubkey
=> Key<key::SecretParts, key::SubordinateRole>);
impl_downcast_for!(SecretKey | SecretSubkey
=> Key<key::SecretParts, key::UnspecifiedRole>);
impl_downcast_for!(PublicKey | SecretKey
=> Key<key::UnspecifiedParts, key::PrimaryRole>);
impl_downcast_for!(PublicSubkey | SecretSubkey
=> Key<key::UnspecifiedParts, key::SubordinateRole>);
impl_downcast_for!(PublicKey | PublicSubkey | SecretKey | SecretSubkey
=> Key<key::UnspecifiedParts, key::UnspecifiedRole>);
#[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();
}
}