#[cfg(feature = "alloc")]
pub(crate) mod other_prime_info;
use crate::{Error, Result, RsaPublicKey, Version};
use core::fmt;
use der::{asn1::UIntRef, Decode, DecodeValue, Encode, Header, Reader, Sequence, Tag};
#[cfg(feature = "alloc")]
use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument};
#[cfg(feature = "pem")]
use der::pem::PemLabel;
#[derive(Clone)]
pub struct RsaPrivateKey<'a> {
    pub modulus: UIntRef<'a>,
    pub public_exponent: UIntRef<'a>,
    pub private_exponent: UIntRef<'a>,
    pub prime1: UIntRef<'a>,
    pub prime2: UIntRef<'a>,
    pub exponent1: UIntRef<'a>,
    pub exponent2: UIntRef<'a>,
    pub coefficient: UIntRef<'a>,
    pub other_prime_infos: Option<OtherPrimeInfos<'a>>,
}
impl<'a> RsaPrivateKey<'a> {
    pub fn public_key(&self) -> RsaPublicKey<'a> {
        RsaPublicKey {
            modulus: self.modulus,
            public_exponent: self.public_exponent,
        }
    }
    pub fn version(&self) -> Version {
        if self.other_prime_infos.is_some() {
            Version::Multi
        } else {
            Version::TwoPrime
        }
    }
}
impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> {
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
        reader.read_nested(header.length, |reader| {
            let version = Version::decode(reader)?;
            let result = Self {
                modulus: reader.decode()?,
                public_exponent: reader.decode()?,
                private_exponent: reader.decode()?,
                prime1: reader.decode()?,
                prime2: reader.decode()?,
                exponent1: reader.decode()?,
                exponent2: reader.decode()?,
                coefficient: reader.decode()?,
                other_prime_infos: reader.decode()?,
            };
            if version.is_multi() != result.other_prime_infos.is_some() {
                return Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }));
            }
            Ok(result)
        })
    }
}
impl<'a> Sequence<'a> for RsaPrivateKey<'a> {
    fn fields<F, T>(&self, f: F) -> der::Result<T>
    where
        F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
    {
        f(&[
            &self.version(),
            &self.modulus,
            &self.public_exponent,
            &self.private_exponent,
            &self.prime1,
            &self.prime2,
            &self.exponent1,
            &self.exponent2,
            &self.coefficient,
            #[cfg(feature = "alloc")]
            &self.other_prime_infos,
        ])
    }
}
impl<'a> From<RsaPrivateKey<'a>> for RsaPublicKey<'a> {
    fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
        private_key.public_key()
    }
}
impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> {
    fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
        private_key.public_key()
    }
}
impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> {
    type Error = Error;
    fn try_from(bytes: &'a [u8]) -> Result<Self> {
        Ok(Self::from_der(bytes)?)
    }
}
impl fmt::Debug for RsaPrivateKey<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("RsaPrivateKey")
            .field("version", &self.version())
            .field("modulus", &self.modulus)
            .field("public_exponent", &self.public_exponent)
            .finish_non_exhaustive()
    }
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl TryFrom<RsaPrivateKey<'_>> for SecretDocument {
    type Error = Error;
    fn try_from(private_key: RsaPrivateKey<'_>) -> Result<SecretDocument> {
        SecretDocument::try_from(&private_key)
    }
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument {
    type Error = Error;
    fn try_from(private_key: &RsaPrivateKey<'_>) -> Result<SecretDocument> {
        Ok(Self::encode_msg(private_key)?)
    }
}
#[cfg(feature = "pem")]
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
impl PemLabel for RsaPrivateKey<'_> {
    const PEM_LABEL: &'static str = "RSA PRIVATE KEY";
}
#[cfg(not(feature = "alloc"))]
#[derive(Clone)]
#[non_exhaustive]
pub struct OtherPrimeInfos<'a> {
    _lifetime: core::marker::PhantomData<&'a ()>,
}
#[cfg(not(feature = "alloc"))]
impl<'a> Decode<'a> for OtherPrimeInfos<'a> {
    fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
        Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }))
    }
}
#[cfg(not(feature = "alloc"))]
impl<'a> der::FixedTag for OtherPrimeInfos<'a> {
    const TAG: Tag = Tag::Sequence;
}
#[cfg(feature = "alloc")]
pub type OtherPrimeInfos<'a> = Vec<OtherPrimeInfo<'a>>;