use crate::{checked::CheckedSum, writer::Writer, Error};
use core::str;
#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
#[cfg(feature = "bytes")]
use bytes::Bytes;
#[cfg(feature = "pem")]
use {
crate::PEM_LINE_WIDTH,
pem::{LineEnding, PemLabel},
};
pub trait Encode {
fn encoded_len(&self) -> Result<usize, Error>;
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error>;
fn encoded_len_prefixed(&self) -> Result<usize, Error> {
[4, self.encoded_len()?].checked_sum()
}
fn encode_prefixed(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.encoded_len()?.encode(writer)?;
self.encode(writer)
}
}
#[cfg(feature = "pem")]
pub trait EncodePem: Encode + PemLabel {
fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error>;
#[cfg(feature = "alloc")]
fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Error>;
}
#[cfg(feature = "pem")]
impl<T: Encode + PemLabel> EncodePem for T {
fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error> {
let mut writer =
pem::Encoder::new_wrapped(Self::PEM_LABEL, PEM_LINE_WIDTH, line_ending, out)
.map_err(Error::from)?;
self.encode(&mut writer)?;
let encoded_len = writer.finish().map_err(Error::from)?;
str::from_utf8(&out[..encoded_len]).map_err(Error::from)
}
#[cfg(feature = "alloc")]
fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Error> {
let encoded_len = pem::encapsulated_len_wrapped(
Self::PEM_LABEL,
PEM_LINE_WIDTH,
line_ending,
self.encoded_len()?,
)
.map_err(Error::from)?;
let mut buf = vec![0u8; encoded_len];
let actual_len = self.encode_pem(line_ending, &mut buf)?.len();
buf.truncate(actual_len);
String::from_utf8(buf).map_err(Error::from)
}
}
impl Encode for u8 {
fn encoded_len(&self) -> Result<usize, Error> {
Ok(1)
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
writer.write(&[*self])
}
}
impl Encode for u32 {
fn encoded_len(&self) -> Result<usize, Error> {
Ok(4)
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
writer.write(&self.to_be_bytes())
}
}
impl Encode for u64 {
fn encoded_len(&self) -> Result<usize, Error> {
Ok(8)
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
writer.write(&self.to_be_bytes())
}
}
impl Encode for usize {
fn encoded_len(&self) -> Result<usize, Error> {
Ok(4)
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
u32::try_from(*self)?.encode(writer)
}
}
impl Encode for [u8] {
fn encoded_len(&self) -> Result<usize, Error> {
[4, self.len()].checked_sum()
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.len().encode(writer)?;
writer.write(self)
}
}
impl<const N: usize> Encode for [u8; N] {
fn encoded_len(&self) -> Result<usize, Error> {
self.as_slice().encoded_len()
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.as_slice().encode(writer)
}
}
impl Encode for &str {
fn encoded_len(&self) -> Result<usize, Error> {
self.as_bytes().encoded_len()
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.as_bytes().encode(writer)
}
}
#[cfg(feature = "alloc")]
impl Encode for Vec<u8> {
fn encoded_len(&self) -> Result<usize, Error> {
self.as_slice().encoded_len()
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.as_slice().encode(writer)
}
}
#[cfg(feature = "alloc")]
impl Encode for String {
fn encoded_len(&self) -> Result<usize, Error> {
self.as_str().encoded_len()
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.as_str().encode(writer)
}
}
#[cfg(feature = "alloc")]
impl Encode for Vec<String> {
fn encoded_len(&self) -> Result<usize, Error> {
self.iter().try_fold(4usize, |acc, string| {
acc.checked_add(string.encoded_len()?).ok_or(Error::Length)
})
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.encoded_len()?
.checked_sub(4)
.ok_or(Error::Length)?
.encode(writer)?;
for entry in self {
entry.encode(writer)?;
}
Ok(())
}
}
#[cfg(feature = "bytes")]
impl Encode for Bytes {
fn encoded_len(&self) -> Result<usize, Error> {
self.as_ref().encoded_len()
}
fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.as_ref().encode(writer)
}
}