//! 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)
}
}
}
}
// 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())
}
}
}
}
}
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 `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 `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)
}
}
}
}
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)
}
}
}
}
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)
}
}
}
}
// 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!( -> );
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!( -> );
//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!( -> );
//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 `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 `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)
}
}
}
}
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;>);