use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
use core::str::FromStr;
use crate::utils::dst::{UnsizedCopy, UnsizedCopyFrom};
use super::{
build::{BuildInMessage, NameCompressor},
parse::{ParseMessageBytes, SplitMessageBytes},
wire::{BuildBytes, ParseBytes, ParseError, SplitBytes, TruncationError},
};
#[derive(UnsizedCopy)]
#[repr(transparent)]
pub struct CharStr {
pub octets: [u8],
}
impl CharStr {
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
core::mem::transmute(bytes)
}
pub unsafe fn from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut Self {
core::mem::transmute(bytes)
}
}
impl CharStr {
pub const fn len(&self) -> usize {
self.octets.len()
}
pub const fn is_empty(&self) -> bool {
self.octets.is_empty()
}
}
impl<'a> SplitMessageBytes<'a> for &'a CharStr {
fn split_message_bytes(
contents: &'a [u8],
start: usize,
) -> Result<(Self, usize), ParseError> {
Self::split_bytes(&contents[start..])
.map(|(this, rest)| (this, contents.len() - start - rest.len()))
}
}
impl<'a> ParseMessageBytes<'a> for &'a CharStr {
fn parse_message_bytes(
contents: &'a [u8],
start: usize,
) -> Result<Self, ParseError> {
Self::parse_bytes(&contents[start..])
}
}
impl BuildInMessage for CharStr {
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
_compressor: &mut NameCompressor,
) -> Result<usize, TruncationError> {
let end = start + self.len() + 1;
let bytes = contents.get_mut(start..end).ok_or(TruncationError)?;
bytes[0] = self.len() as u8;
bytes[1..].copy_from_slice(&self.octets);
Ok(end)
}
}
impl<'a> SplitBytes<'a> for &'a CharStr {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError> {
let (&length, rest) = bytes.split_first().ok_or(ParseError)?;
if length as usize > rest.len() {
return Err(ParseError);
}
let (bytes, rest) = rest.split_at(length as usize);
Ok((unsafe { core::mem::transmute::<&[u8], Self>(bytes) }, rest))
}
}
impl<'a> ParseBytes<'a> for &'a CharStr {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
let (&length, rest) = bytes.split_first().ok_or(ParseError)?;
if length as usize != rest.len() {
return Err(ParseError);
}
Ok(unsafe { core::mem::transmute::<&[u8], Self>(rest) })
}
}
impl BuildBytes for CharStr {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
let (length, bytes) =
bytes.split_first_mut().ok_or(TruncationError)?;
*length = self.octets.len() as u8;
self.octets.build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
1 + self.octets.len()
}
}
#[cfg(feature = "alloc")]
impl Clone for alloc::boxed::Box<CharStr> {
fn clone(&self) -> Self {
(*self).unsized_copy_into()
}
}
impl PartialEq for CharStr {
fn eq(&self, other: &Self) -> bool {
self.octets.eq_ignore_ascii_case(&other.octets)
}
}
impl Eq for CharStr {}
impl Hash for CharStr {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u8(self.len() as u8);
for byte in &self.octets {
state.write_u8(byte.to_ascii_lowercase());
}
}
}
impl fmt::Debug for CharStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Write;
struct Native<'a>(&'a [u8]);
impl fmt::Debug for Native<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("b\"")?;
for &b in self.0 {
f.write_str(match b {
b'"' => "\\\"",
b' ' => " ",
b'\n' => "\\n",
b'\r' => "\\r",
b'\t' => "\\t",
b'\\' => "\\\\",
_ => {
if b.is_ascii_graphic() {
f.write_char(b as char)?;
} else {
write!(f, "\\x{:02X}", b)?;
}
continue;
}
})?;
}
f.write_char('"')?;
Ok(())
}
}
f.debug_struct("CharStr")
.field("content", &Native(&self.octets))
.finish()
}
}
#[derive(Clone)]
#[repr(C)] pub struct CharStrBuf {
size: u8,
data: [u8; 255],
}
impl CharStrBuf {
const fn empty() -> Self {
Self {
size: 0,
data: [0u8; 255],
}
}
pub fn copy_from(string: &CharStr) -> Self {
let mut this = Self::empty();
this.size = string.len() as u8;
this.data[..string.len()].copy_from_slice(&string.octets);
this
}
}
impl UnsizedCopyFrom for CharStrBuf {
type Source = CharStr;
fn unsized_copy_from(value: &Self::Source) -> Self {
Self::copy_from(value)
}
}
impl CharStrBuf {
pub fn wire_bytes(&self) -> &[u8] {
let ptr = self as *const _ as *const u8;
let len = self.len() + 1;
unsafe { core::slice::from_raw_parts(ptr, len) }
}
}
impl SplitMessageBytes<'_> for CharStrBuf {
fn split_message_bytes(
contents: &'_ [u8],
start: usize,
) -> Result<(Self, usize), ParseError> {
<&CharStr>::split_message_bytes(contents, start)
.map(|(this, rest)| (Self::copy_from(this), rest))
}
}
impl ParseMessageBytes<'_> for CharStrBuf {
fn parse_message_bytes(
contents: &'_ [u8],
start: usize,
) -> Result<Self, ParseError> {
<&CharStr>::parse_message_bytes(contents, start).map(Self::copy_from)
}
}
impl BuildInMessage for CharStrBuf {
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
name: &mut NameCompressor,
) -> Result<usize, TruncationError> {
CharStr::build_in_message(self, contents, start, name)
}
}
impl SplitBytes<'_> for CharStrBuf {
fn split_bytes(bytes: &'_ [u8]) -> Result<(Self, &'_ [u8]), ParseError> {
<&CharStr>::split_bytes(bytes)
.map(|(this, rest)| (Self::copy_from(this), rest))
}
}
impl ParseBytes<'_> for CharStrBuf {
fn parse_bytes(bytes: &'_ [u8]) -> Result<Self, ParseError> {
<&CharStr>::parse_bytes(bytes).map(Self::copy_from)
}
}
impl BuildBytes for CharStrBuf {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
(**self).build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
(**self).built_bytes_size()
}
}
impl FromStr for CharStrBuf {
type Err = CharStrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.as_bytes().contains(&b'\\') {
Err(CharStrParseError::InvalidChar)
} else if s.len() > 255 {
Err(CharStrParseError::Overlong)
} else {
let s = unsafe { CharStr::from_bytes_unchecked(s.as_bytes()) };
Ok(Self::copy_from(s))
}
}
}
impl Deref for CharStrBuf {
type Target = CharStr;
fn deref(&self) -> &Self::Target {
let name = &self.data[..self.size as usize];
unsafe { CharStr::from_bytes_unchecked(name) }
}
}
impl DerefMut for CharStrBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
let name = &mut self.data[..self.size as usize];
unsafe { CharStr::from_bytes_unchecked_mut(name) }
}
}
impl Borrow<CharStr> for CharStrBuf {
fn borrow(&self) -> &CharStr {
self
}
}
impl BorrowMut<CharStr> for CharStrBuf {
fn borrow_mut(&mut self) -> &mut CharStr {
self
}
}
impl AsRef<CharStr> for CharStrBuf {
fn as_ref(&self) -> &CharStr {
self
}
}
impl AsMut<CharStr> for CharStrBuf {
fn as_mut(&mut self) -> &mut CharStr {
self
}
}
impl PartialEq for CharStrBuf {
fn eq(&self, that: &Self) -> bool {
**self == **that
}
}
impl Eq for CharStrBuf {}
impl fmt::Debug for CharStrBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CharStrParseError {
Overlong,
InvalidChar,
}
#[cfg(feature = "std")]
impl std::error::Error for CharStrParseError {}
impl fmt::Display for CharStrParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Overlong => "the character string was too long",
Self::InvalidChar => {
"the character string contained an invalid character"
}
})
}
}
#[cfg(test)]
mod test {
use super::CharStr;
use crate::new::base::wire::{
BuildBytes, ParseBytes, ParseError, SplitBytes,
};
#[test]
fn parse_build() {
let bytes = b"\x05Hello!";
let (charstr, rest) = <&CharStr>::split_bytes(bytes).unwrap();
assert_eq!(&charstr.octets, b"Hello");
assert_eq!(rest, b"!");
assert_eq!(<&CharStr>::parse_bytes(bytes), Err(ParseError));
assert!(<&CharStr>::parse_bytes(&bytes[..6]).is_ok());
let mut buffer = [0u8; 6];
assert_eq!(
charstr.build_bytes(&mut buffer),
Ok(&mut [] as &mut [u8])
);
assert_eq!(buffer, &bytes[..6]);
}
}