use core::fmt::{self, Display, Formatter};
use core::str::{from_utf8, Utf8Error};
#[cfg(feature = "std")]
use std::error;
use super::{read_marker, RmpRead, RmpReadErr, ValueReadError};
use crate::Marker;
#[derive(Debug)]
#[allow(deprecated)] pub enum DecodeStringError<'a, E: RmpReadErr = super::Error> {
InvalidMarkerRead(E),
InvalidDataRead(E),
TypeMismatch(Marker),
BufferSizeTooSmall(u32),
InvalidUtf8(&'a [u8], Utf8Error),
}
#[cfg(feature = "std")]
impl<E: RmpReadErr> error::Error for DecodeStringError<'_, E> {
#[cold]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
DecodeStringError::InvalidMarkerRead(ref err) |
DecodeStringError::InvalidDataRead(ref err) => Some(err),
DecodeStringError::TypeMismatch(..) |
DecodeStringError::BufferSizeTooSmall(..) => None,
DecodeStringError::InvalidUtf8(_, ref err) => Some(err),
}
}
}
impl<E: RmpReadErr> Display for DecodeStringError<'_, E> {
#[cold]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("error while decoding string")
}
}
impl<E: RmpReadErr> From<ValueReadError<E>> for DecodeStringError<'_, E> {
#[cold]
fn from(err: ValueReadError<E>) -> Self {
match err {
ValueReadError::InvalidMarkerRead(err) => DecodeStringError::InvalidMarkerRead(err),
ValueReadError::InvalidDataRead(err) => DecodeStringError::InvalidDataRead(err),
ValueReadError::TypeMismatch(marker) => DecodeStringError::TypeMismatch(marker),
}
}
}
#[inline]
pub fn read_str_len<R: RmpRead>(rd: &mut R) -> Result<u32, ValueReadError<R::Error>> {
Ok(read_str_len_with_nread(rd)?.0)
}
fn read_str_len_with_nread<R>(rd: &mut R) -> Result<(u32, usize), ValueReadError<R::Error>>
where R: RmpRead
{
match read_marker(rd)? {
Marker::FixStr(size) => Ok((u32::from(size), 1)),
Marker::Str8 => Ok((u32::from(rd.read_data_u8()?), 2)),
Marker::Str16 => Ok((u32::from(rd.read_data_u16()?), 3)),
Marker::Str32 => Ok((rd.read_data_u32()?, 5)),
marker => Err(ValueReadError::TypeMismatch(marker)),
}
}
pub fn read_str<'r, R>(rd: &mut R, buf: &'r mut [u8]) -> Result<&'r str, DecodeStringError<'r, R::Error>>
where
R: RmpRead,
{
let len = read_str_len(rd)?;
let ulen = len as usize;
if buf.len() < ulen {
return Err(DecodeStringError::BufferSizeTooSmall(len));
}
read_str_data(rd, len, &mut buf[0..ulen])
}
pub fn read_str_data<'r, R>(rd: &mut R,
len: u32,
buf: &'r mut [u8])
-> Result<&'r str, DecodeStringError<'r, R::Error>>
where R: RmpRead
{
debug_assert_eq!(len as usize, buf.len());
match rd.read_exact_buf(buf) {
Ok(()) => match from_utf8(buf) {
Ok(decoded) => Ok(decoded),
Err(err) => Err(DecodeStringError::InvalidUtf8(buf, err)),
},
Err(err) => Err(DecodeStringError::InvalidDataRead(err)),
}
}
#[deprecated(since = "0.8.6", note = "useless, use `read_str_from_slice` instead")]
pub fn read_str_ref(rd: &[u8]) -> Result<&[u8], DecodeStringError<'_, super::bytes::BytesReadError>> {
let mut cur = super::Bytes::new(rd);
let len = read_str_len(&mut cur)?;
Ok(&cur.remaining_slice()[..len as usize])
}
pub fn read_str_from_slice<T: ?Sized + AsRef<[u8]>>(
buf: &T,
) -> Result<(&str, &[u8]), DecodeStringError<'_, super::bytes::BytesReadError>> {
let buf = buf.as_ref();
let (len, nread) = read_str_len_with_nread(&mut super::Bytes::new(buf))?;
let ulen = len as usize;
if buf[nread..].len() >= ulen {
let (head, tail) = buf.split_at(nread + ulen);
match from_utf8(&head[nread..]) {
Ok(val) => Ok((val, tail)),
Err(err) => Err(DecodeStringError::InvalidUtf8(buf, err)),
}
} else {
Err(DecodeStringError::BufferSizeTooSmall(len))
}
}