use super::{GuestDecodeError, GuestDecodeField, GuestDecodeLimits};
use crate::text_stream::TextRange;
use std::{
fmt::{Debug, Formatter},
str,
};
#[derive(Clone, Eq, PartialEq)]
pub struct DecodedGuestString {
value: String,
}
impl DecodedGuestString {
pub fn from_bytes(
field: GuestDecodeField,
bytes: &[u8],
limits: GuestDecodeLimits,
) -> Result<Self, GuestDecodeError> {
let size = checked_len(field, bytes.len(), limits.max_string_bytes())?;
let value = str::from_utf8(bytes)
.map_err(|_source| GuestDecodeError::MalformedUtf8 { field, size })?
.to_owned();
Ok(Self { value })
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.value
}
#[must_use]
pub const fn byte_len(&self) -> usize {
self.value.len()
}
#[must_use]
pub fn into_string(self) -> String {
self.value
}
}
impl Debug for DecodedGuestString {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("DecodedGuestString")
.field("byte_len", &self.value.len())
.finish()
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct DecodedPayload {
bytes: Vec<u8>,
}
impl DecodedPayload {
pub fn from_bytes(
field: GuestDecodeField,
bytes: &[u8],
limits: GuestDecodeLimits,
) -> Result<Self, GuestDecodeError> {
let _size = checked_len(field, bytes.len(), limits.max_payload_bytes())?;
Ok(Self {
bytes: bytes.to_vec(),
})
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
#[must_use]
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
}
impl Debug for DecodedPayload {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("DecodedPayload")
.field("byte_len", &self.bytes.len())
.finish()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DecodedCount {
value: usize,
}
impl DecodedCount {
pub fn new(
field: GuestDecodeField,
value: u64,
limits: GuestDecodeLimits,
) -> Result<Self, GuestDecodeError> {
if value > limits.max_count() {
return Err(GuestDecodeError::CountTooLarge {
field,
value,
max: limits.max_count(),
});
}
let host_max = u64::try_from(usize::MAX).unwrap_or(u64::MAX);
if value > host_max {
return Err(GuestDecodeError::CountTooLarge {
field,
value,
max: host_max,
});
}
let value = usize::try_from(value).map_err(|_source| GuestDecodeError::CountTooLarge {
field,
value,
max: host_max,
})?;
Ok(Self { value })
}
#[must_use]
pub const fn get(self) -> usize {
self.value
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DecodedTextRange {
range: TextRange,
}
impl DecodedTextRange {
pub fn new(
field: GuestDecodeField,
start: u64,
end: u64,
limits: GuestDecodeLimits,
) -> Result<Self, GuestDecodeError> {
if start > end {
return Err(GuestDecodeError::ReversedRange { field, start, end });
}
let host_max = u64::try_from(usize::MAX).unwrap_or(u64::MAX);
let max = limits.max_count().min(host_max);
if end > max {
return Err(GuestDecodeError::RangeTooLarge {
field,
start,
end,
max,
});
}
let start = usize::try_from(start).map_err(|_source| GuestDecodeError::RangeTooLarge {
field,
start,
end,
max,
})?;
let end = usize::try_from(end).map_err(|_source| GuestDecodeError::RangeTooLarge {
field,
start: u64::try_from(start).unwrap_or(u64::MAX),
end,
max,
})?;
Ok(Self {
range: TextRange::new(start, end),
})
}
#[must_use]
pub const fn get(self) -> TextRange {
self.range
}
}
fn checked_len(field: GuestDecodeField, len: usize, max: u64) -> Result<u64, GuestDecodeError> {
let size = u64::try_from(len).unwrap_or(u64::MAX);
if size > max {
return Err(GuestDecodeError::PayloadTooLarge { field, size, max });
}
Ok(size)
}