use super::{
ordinary::OneShotError,
specifications::{Base64, Codec},
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BufferLengthError {
length: usize,
capacity: usize,
}
impl BufferLengthError {
pub(super) const fn new(length: usize, capacity: usize) -> Self {
Self { length, capacity }
}
#[must_use]
pub const fn length(self) -> usize {
self.length
}
#[must_use]
pub const fn capacity(self) -> usize {
self.capacity
}
}
impl core::fmt::Display for BufferLengthError {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
formatter,
"visible buffer length {} exceeds capacity {}",
self.length, self.capacity
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for BufferLengthError {}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct EncodedArray<const CAP: usize> {
bytes: [u8; CAP],
len: usize,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct DecodedArray<const CAP: usize> {
bytes: [u8; CAP],
len: usize,
}
macro_rules! ordinary_array {
($name:ident, $description:literal) => {
impl<const CAP: usize> $name<CAP> {
#[doc = $description]
pub const fn from_array(
bytes: [u8; CAP],
len: usize,
) -> Result<Self, BufferLengthError> {
if len > CAP {
Err(BufferLengthError::new(len, CAP))
} else {
Ok(Self { bytes, len })
}
}
pub(crate) const fn from_initialized(
bytes: [u8; CAP],
len: usize,
) -> Result<Self, BufferLengthError> {
Self::from_array(bytes, len)
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..self.len]
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[must_use]
pub const fn capacity(&self) -> usize {
CAP
}
#[must_use]
pub const fn remaining_capacity(&self) -> usize {
CAP - self.len
}
#[must_use]
pub const fn into_parts(self) -> ([u8; CAP], usize) {
(self.bytes, self.len)
}
}
};
}
ordinary_array!(
EncodedArray,
"Constructs ordinary encoded storage with a checked visible prefix."
);
ordinary_array!(
DecodedArray,
"Constructs ordinary decoded storage with a checked visible prefix."
);
impl<S: Codec> Base64<S> {
pub fn encode_bounded<const CAP: usize>(
&self,
input: &[u8],
) -> Result<EncodedArray<CAP>, OneShotError> {
let mut bytes = [0u8; CAP];
let len = self.encode_into(input, &mut bytes)?;
EncodedArray::from_initialized(bytes, len)
.map_err(|_| OneShotError::Backend(super::contracts::BackendFault::ImpossibleState))
}
pub fn decode_bounded<const CAP: usize>(
&self,
input: &[u8],
) -> Result<DecodedArray<CAP>, OneShotError> {
let mut bytes = [0u8; CAP];
let len = self.decode_into(input, &mut bytes)?;
DecodedArray::from_initialized(bytes, len)
.map_err(|_| OneShotError::Backend(super::contracts::BackendFault::ImpossibleState))
}
}