//! Conversion functions for `Key` and associated types. use std::convert::TryFrom; use crate::Error; use crate::cert::prelude::*; use crate::packet::prelude::*; use crate::packet::key::{ KeyParts, KeyRole, PrimaryRole, PublicParts, SubordinateRole, SecretParts, UnspecifiedParts, UnspecifiedRole }; use crate::Result; macro_rules! convert { ( $x:ident ) => { // XXX: This is ugly, but how can we do better? unsafe { std::mem::transmute($x) } } } macro_rules! convert_ref { ( $x:ident ) => { // XXX: This is ugly, but how can we do better? #[allow(clippy::transmute_ptr_to_ptr)] unsafe { std::mem::transmute($x) } } } // Make it possible to go from an arbitrary Key to an // arbitrary Key (or &Key to &Key) in a // single .into(). // // To allow the programmer to make the intent clearer, also // provide explicit conversion function. // In principle, this is as easy as the following: // // impl From> for Key // where P: KeyParts, P2: KeyParts, R: KeyRole, R2: KeyRole // { // fn from(p: Key) -> Self { // unimplemented!() // } // } // // But that results in: // // error[E0119]: conflicting implementations of trait `std::convert::From>` for type `packet::Key<_, _>`: // = note: conflicting implementation in crate `core`: // - impl std::convert::From for T; // // Unfortunately, it's not enough to make one type variable // concrete, as the following errors demonstrate: // // error[E0119]: conflicting implementations of trait `std::convert::From>` for type `packet::Key`: // ... // = note: conflicting implementation in crate `core`: // - impl std::convert::From for T; // // impl From> for Key // where P: KeyParts, R: KeyRole, R2: KeyRole // { // fn from(p: Key) -> Self { // unimplemented!() // } // } // // error[E0119]: conflicting implementations of trait `std::convert::From>` for type `packet::Key`: // --> openpgp/src/packet/key.rs:186:5 // ... // = note: conflicting implementation in crate `core`: // - impl std::convert::From for T; // impl From> for Key // where P2: KeyParts, R: KeyRole, R2: KeyRole // { // fn from(p: Key) -> Self { // unimplemented!() // } // } // // To solve this, we need at least one generic variable to be // concrete on both sides of the `From`. macro_rules! create_part_conversions { ( $Key:ident<$( $l:lifetime ),*; $( $g:ident ),*>) => { create_part_conversions!($Key<$($l),*; $($g),*> where ); }; ( $Key:ident<$( $l:lifetime ),*; $( $g:ident ),*> where $( $w:ident: $c:path ),* ) => { // Convert between two KeyParts for a constant KeyRole. // Unfortunately, we can't let the KeyRole vary as otherwise we // get conflicting types when we do the same to convert between // two KeyRoles for a constant KeyParts. :( macro_rules! p { ( <$from_parts:ty> -> <$to_parts:ty> ) => { impl<$($l, )* $($g, )* > From<$Key<$($l, )* $from_parts, $($g, )* >> for $Key<$($l, )* $to_parts, $($g, )* > where $($w: $c ),* { fn from(p: $Key<$($l, )* $from_parts, $($g, )* >) -> Self { convert!(p) } } impl<$($l, )* $($g, )* > From<&$($l)* $Key<$($l, )* $from_parts, $($g, )* >> for &$($l)* $Key<$($l, )* $to_parts, $($g, )* > where $($w: $c ),* { fn from(p: &$($l)* $Key<$($l, )* $from_parts, $($g, )* >) -> Self { convert_ref!(p) } } impl<$($l, )* $($g, )* > From<&$($l)* mut $Key<$($l, )* $from_parts, $($g, )* >> for &$($l)* mut $Key<$($l, )* $to_parts, $($g, )* > where $($w: $c ),* { fn from(p: &$($l)* mut $Key<$($l, )* $from_parts, $($g, )* >) -> Self { convert_ref!(p) } } } } // Likewise, but using TryFrom. macro_rules! p_try { ( <$from_parts:ty> -> <$to_parts:ty>) => { impl<$($l, )* $($g, )* > TryFrom<$Key<$($l, )* $from_parts, $($g, )* >> for $Key<$($l, )* $to_parts, $($g, )* > where $($w: $c ),* { type Error = anyhow::Error; fn try_from(p: $Key<$($l, )* $from_parts, $($g, )* >) -> Result { p.parts_into_secret() } } impl<$($l, )* $($g, )* > TryFrom<&$($l)* $Key<$($l, )* $from_parts, $($g, )* >> for &$($l)* $Key<$($l, )* $to_parts, $($g, )* > where $($w: $c ),* { type Error = anyhow::Error; fn try_from(p: &$($l)* $Key<$($l, )* $from_parts, $($g, )* >) -> Result { if p.has_secret() { Ok(convert_ref!(p)) } else { Err(Error::InvalidArgument("No secret key".into()) .into()) } } } impl<$($l, )* $($g, )* > TryFrom<&$($l)* mut $Key<$($l, )* $from_parts, $($g, )* >> for &$($l)* mut $Key<$($l, )* $to_parts, $($g, )* > where $($w: $c ),* { type Error = anyhow::Error; fn try_from(p: &$($l)* mut $Key<$($l, )* $from_parts, $($g, )* >) -> Result { if p.has_secret() { Ok(convert_ref!(p)) } else { Err(Error::InvalidArgument("No secret key".into()) .into()) } } } } } p_try!( -> ); p!( -> ); p!( -> ); p!( -> ); p!( -> ); p_try!( -> ); impl<$($l, )* P, $($g, )*> $Key<$($l, )* P, $($g, )*> where P: KeyParts, $($w: $c ),* { /// Changes the key's parts tag to `PublicParts`. pub fn parts_into_public(self) -> $Key<$($l, )* PublicParts, $($g, )*> { // Ideally, we'd use self.into() to do the actually // conversion. But, because P is not concrete, we get the // following error: // // error[E0277]: the trait bound `packet::Key: std::convert::From>` is not satisfied // --> openpgp/src/packet/key.rs:401:18 // | // 401 | self.into() // | ^^^^ the trait `std::convert::From>` is not implemented for `packet::Key` // | // = help: consider adding a `where packet::Key: std::convert::From>` bound // = note: required because of the requirements on the impl of `std::convert::Into>` for `packet::Key` // // But we can't implement implement `From>` for // `Key`, because that conflicts with a // standard conversion! (See the comment for the `p` // macro above.) // // Adding the trait bound is annoying, because then we'd // have to add it everywhere that we use into. convert!(self) } /// Changes the key's parts tag to `PublicParts`. pub fn parts_as_public(&$($l)* self) -> &$($l)* $Key<$($l, )* PublicParts, $($g, )*> { convert_ref!(self) } /// Changes the key's parts tag to `PublicParts`. pub fn parts_as_public_mut(&$($l)* mut self) -> &$($l)* mut $Key<$($l, )* PublicParts, $($g, )*> { convert_ref!(self) } /// Changes the key's parts tag to `SecretParts`. pub fn parts_into_secret(self) -> Result<$Key<$($l, )* SecretParts, $($g, )*>> { if self.has_secret() { Ok(convert!(self)) } else { Err(Error::InvalidArgument("No secret key".into()).into()) } } /// Changes the key's parts tag to `SecretParts`. pub fn parts_as_secret(&$($l)* self) -> Result<&$($l)* $Key<$($l, )* SecretParts, $($g, )*>> { if self.has_secret() { Ok(convert_ref!(self)) } else { Err(Error::InvalidArgument("No secret key".into()).into()) } } /// Changes the key's parts tag to `SecretParts`. pub fn parts_as_secret_mut(&$($l)* mut self) -> Result<&$($l)* mut $Key<$($l, )* SecretParts, $($g, )*>> { if self.has_secret() { Ok(convert_ref!(self)) } else { Err(Error::InvalidArgument("No secret key".into()).into()) } } /// Changes the key's parts tag to `UnspecifiedParts`. pub fn parts_into_unspecified(self) -> $Key<$($l, )* UnspecifiedParts, $($g, )*> { convert!(self) } /// Changes the key's parts tag to `UnspecifiedParts`. pub fn parts_as_unspecified(&$($l)* self) -> &$Key<$($l, )* UnspecifiedParts, $($g, )*> { convert_ref!(self) } /// Changes the key's parts tag to `UnspecifiedParts`. pub fn parts_as_unspecified_mut(&$($l)* mut self) -> &mut $Key<$($l, )* UnspecifiedParts, $($g, )*> { convert_ref!(self) } } } } macro_rules! create_role_conversions { ( $Key:ident<$( $l:lifetime ),*> ) => { // Convert between two KeyRoles for a constant KeyParts. See // the comment for the p macro above. macro_rules! r { ( <$from_role:ty> -> <$to_role:ty>) => { impl<$($l, )* P> From<$Key<$($l, )* P, $from_role>> for $Key<$($l, )* P, $to_role> where P: KeyParts { fn from(p: $Key<$($l, )* P, $from_role>) -> Self { convert!(p) } } impl<$($l, )* P> From<&$($l)* $Key<$($l, )* P, $from_role>> for &$($l)* $Key<$($l, )* P, $to_role> where P: KeyParts { fn from(p: &$($l)* $Key<$($l, )* P, $from_role>) -> Self { convert_ref!(p) } } impl<$($l, )* P> From<&$($l)* mut $Key<$($l, )* P, $from_role>> for &$($l)* mut $Key<$($l, )* P, $to_role> where P: KeyParts { fn from(p: &$($l)* mut $Key<$($l, )* P, $from_role>) -> Self { convert_ref!(p) } } } } r!( -> ); r!( -> ); r!( -> ); r!( -> ); r!( -> ); r!( -> ); } } macro_rules! create_conversions { ( $Key:ident<$( $l:lifetime ),*> ) => { create_part_conversions!($Key<$($l ),* ; R> where R: KeyRole); create_role_conversions!($Key<$($l ),* >); // We now handle converting both the part and the role at the same // time. macro_rules! f { ( <$from_parts:ty, $from_role:ty> -> <$to_parts:ty, $to_role:ty> ) => { impl<$($l ),*> From<$Key<$($l, )* $from_parts, $from_role>> for $Key<$($l, )* $to_parts, $to_role> { fn from(p: $Key<$($l, )* $from_parts, $from_role>) -> Self { convert!(p) } } impl<$($l ),*> From<&$($l)* $Key<$($l, )* $from_parts, $from_role>> for &$($l)* $Key<$($l, )* $to_parts, $to_role> { fn from(p: &$($l)* $Key<$from_parts, $from_role>) -> Self { convert_ref!(p) } } impl<$($l ),*> From<&$($l)* mut $Key<$($l, )* $from_parts, $from_role>> for &$($l)* mut $Key<$($l, )* $to_parts, $to_role> { fn from(p: &$($l)* mut $Key<$from_parts, $from_role>) -> Self { convert_ref!(p) } } } } macro_rules! f_try { ( <$from_parts:ty, $from_role:ty> -> ) => { impl<$($l ),*> TryFrom<$Key<$($l, )* $from_parts, $from_role>> for $Key<$($l, )* SecretParts, $to_role> { type Error = anyhow::Error; fn try_from(p: $Key<$($l, )* $from_parts, $from_role>) -> Result { // First, just change the role. let k: $Key<$($l, )* $from_parts, $to_role> = p.into(); // Now change the parts. k.try_into() } } impl<$($l ),*> TryFrom<&$($l)* $Key<$($l, )* $from_parts, $from_role>> for &$($l)* $Key<$($l, )* SecretParts, $to_role> { type Error = anyhow::Error; fn try_from(p: &$($l)* $Key<$($l, )* $from_parts, $from_role>) -> Result { // First, just change the role. let k: &$($l)* $Key<$($l, )* $from_parts, $to_role> = p.into(); // Now change the parts. k.try_into() } } impl<$($l ),*> TryFrom<&$($l)* mut $Key<$($l, )* $from_parts, $from_role>> for &$($l)* mut $Key<$($l, )* SecretParts, $to_role> { type Error = anyhow::Error; fn try_from(p: &$($l)* mut $Key<$($l, )* $from_parts, $from_role>) -> Result { // First, just change the role. let k: &$($l)* mut $Key<$($l, )* $from_parts, $to_role> = p.into(); // Now change the parts. k.try_into() } } } } // The calls that are comment out are the calls for the // combinations where either the KeyParts or the KeyRole does not // change. //f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f_try!( -> ); f_try!( -> ); //f!( -> ); f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f_try!( -> ); //f!( -> ); f_try!( -> ); f!( -> ); //f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f_try!( -> ); f_try!( -> ); //f!( -> ); f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); f!( -> ); f!( -> ); //f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); //f!( -> ); f!( -> ); f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); f!( -> ); //f!( -> ); f_try!( -> ); f_try!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); //f!( -> ); f!( -> ); f_try!( -> ); //f!( -> ); f_try!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); f!( -> ); f!( -> ); //f!( -> ); f_try!( -> ); f_try!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); //f!( -> ); impl<$($l, )* P, R> $Key<$($l, )* P, R> where P: KeyParts, R: KeyRole { /// Changes the key's role tag to `PrimaryRole`. pub fn role_into_primary(self) -> $Key<$($l, )* P, PrimaryRole> { convert!(self) } /// Changes the key's role tag to `PrimaryRole`. pub fn role_as_primary(&$($l)* self) -> &$($l)* $Key<$($l, )* P, PrimaryRole> { convert_ref!(self) } /// Changes the key's role tag to `PrimaryRole`. pub fn role_as_primary_mut(&$($l)* mut self) -> &$($l)* mut $Key<$($l, )* P, PrimaryRole> { convert_ref!(self) } /// Changes the key's role tag to `SubordinateRole`. pub fn role_into_subordinate(self) -> $Key<$($l, )* P, SubordinateRole> { convert!(self) } /// Changes the key's role tag to `SubordinateRole`. pub fn role_as_subordinate(&$($l)* self) -> &$($l)* $Key<$($l, )* P, SubordinateRole> { convert_ref!(self) } /// Changes the key's role tag to `SubordinateRole`. pub fn role_as_subordinate_mut(&$($l)* mut self) -> &$($l)* mut $Key<$($l, )* P, SubordinateRole> { convert_ref!(self) } /// Changes the key's role tag to `UnspecifiedRole`. pub fn role_into_unspecified(self) -> $Key<$($l, )* P, UnspecifiedRole> { convert!(self) } /// Changes the key's role tag to `UnspecifiedRole`. pub fn role_as_unspecified(&$($l)* self) -> &$($l)* $Key<$($l, )* P, UnspecifiedRole> { convert_ref!(self) } /// Changes the key's role tag to `UnspecifiedRole`. pub fn role_as_unspecified_mut(&$($l)* mut self) -> &$($l)* mut $Key<$($l, )* P, UnspecifiedRole> { convert_ref!(self) } } } } create_conversions!(Key<>); create_conversions!(Key4<>); create_conversions!(KeyBundle<>); // A hack, since the type has to be an ident, which means that we // can't use <>. type KeyComponentAmalgamation<'a, P, R> = ComponentAmalgamation<'a, Key>; create_conversions!(KeyComponentAmalgamation<'a>); create_part_conversions!(PrimaryKeyAmalgamation<'a;>); create_part_conversions!(SubordinateKeyAmalgamation<'a;>); create_part_conversions!(ErasedKeyAmalgamation<'a;>); create_part_conversions!(ValidPrimaryKeyAmalgamation<'a;>); create_part_conversions!(ValidSubordinateKeyAmalgamation<'a;>); create_part_conversions!(ValidErasedKeyAmalgamation<'a;>);