use crate::shared::UnexpectedState;
use crate::slice_input_buffer;
use crate::stream_buffer;
use crate::ujson;
#[derive(Debug, PartialEq)]
pub enum ParseError {
TokenizerError(ujson::Error),
ScratchBufferFull,
InvalidUtf8(core::str::Utf8Error),
InputBufferFull,
InvalidNumber,
Unexpected(UnexpectedState),
EndOfData,
InvalidUnicodeHex,
InvalidUnicodeCodepoint,
InvalidEscapeSequence,
FloatNotAllowed,
ReaderError,
NumericOverflow,
}
#[cfg(feature = "defmt")]
impl defmt::Format for ParseError {
fn format(&self, fmt: defmt::Formatter) {
match self {
ParseError::TokenizerError(err) => {
defmt::write!(fmt, "ParseError::TokenizerError({:?})", err)
}
ParseError::ScratchBufferFull => defmt::write!(fmt, "ParseError::ScratchBufferFull"),
ParseError::InvalidUtf8(err) => match err.error_len() {
Some(len) => defmt::write!(
fmt,
"ParseError::InvalidUtf8(valid_up_to={=usize}, error_len={=usize})",
err.valid_up_to(),
len
),
None => defmt::write!(
fmt,
"ParseError::InvalidUtf8(valid_up_to={=usize}, incomplete)",
err.valid_up_to()
),
},
ParseError::InputBufferFull => defmt::write!(fmt, "ParseError::InputBufferFull"),
ParseError::InvalidNumber => defmt::write!(fmt, "ParseError::InvalidNumber"),
ParseError::Unexpected(state) => {
defmt::write!(fmt, "ParseError::Unexpected({:?})", state)
}
ParseError::EndOfData => defmt::write!(fmt, "ParseError::EndOfData"),
ParseError::InvalidUnicodeHex => defmt::write!(fmt, "ParseError::InvalidUnicodeHex"),
ParseError::InvalidUnicodeCodepoint => {
defmt::write!(fmt, "ParseError::InvalidUnicodeCodepoint")
}
ParseError::InvalidEscapeSequence => {
defmt::write!(fmt, "ParseError::InvalidEscapeSequence")
}
ParseError::FloatNotAllowed => defmt::write!(fmt, "ParseError::FloatNotAllowed"),
ParseError::ReaderError => defmt::write!(fmt, "ParseError::ReaderError"),
ParseError::NumericOverflow => defmt::write!(fmt, "ParseError::NumericOverflow"),
}
}
}
impl From<slice_input_buffer::Error> for ParseError {
fn from(err: slice_input_buffer::Error) -> Self {
match err {
slice_input_buffer::Error::ReachedEnd => ParseError::EndOfData,
slice_input_buffer::Error::InvalidSliceBounds => {
UnexpectedState::InvalidSliceBounds.into()
}
}
}
}
impl From<stream_buffer::StreamBufferError> for ParseError {
fn from(err: stream_buffer::StreamBufferError) -> Self {
match err {
stream_buffer::StreamBufferError::BufferFull => ParseError::ScratchBufferFull,
stream_buffer::StreamBufferError::EndOfData => ParseError::EndOfData,
stream_buffer::StreamBufferError::Unexpected => {
ParseError::Unexpected(UnexpectedState::BufferCapacityExceeded)
}
stream_buffer::StreamBufferError::InvalidSliceBounds => {
ParseError::Unexpected(UnexpectedState::InvalidSliceBounds)
}
}
}
}
impl From<core::str::Utf8Error> for ParseError {
fn from(err: core::str::Utf8Error) -> Self {
ParseError::InvalidUtf8(err)
}
}
impl From<UnexpectedState> for ParseError {
fn from(info: UnexpectedState) -> Self {
ParseError::Unexpected(info)
}
}
impl From<ujson::Error> for ParseError {
fn from(err: ujson::Error) -> Self {
ParseError::TokenizerError(err)
}
}
impl core::fmt::Display for ParseError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ParseError::TokenizerError(e) => write!(f, "{e}"),
ParseError::InvalidUtf8(e) => write!(f, "Invalid UTF-8: {e}"),
_ => write!(f, "{self:?}"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_constructors() {
let error: ParseError = UnexpectedState::StateMismatch.into();
match error {
ParseError::Unexpected(info) => {
assert_eq!(info, UnexpectedState::StateMismatch);
}
_ => panic!("Expected UnexpectedState error"),
}
let error: ParseError = UnexpectedState::InvalidUnicodeEscape.into();
match error {
ParseError::Unexpected(info) => {
assert_eq!(info, UnexpectedState::InvalidUnicodeEscape);
}
_ => panic!("Expected UnexpectedState error"),
}
let error: ParseError = UnexpectedState::InvalidUnicodeEscape.into();
match error {
ParseError::Unexpected(info) => {
assert_eq!(info, UnexpectedState::InvalidUnicodeEscape);
}
_ => panic!("Expected UnexpectedState error"),
}
}
#[test]
fn test_utf8_error_conversion() {
use core::str;
let mut invalid_utf8_array = [0u8; 1];
invalid_utf8_array[0] = 0b10000000u8; let invalid_utf8 = &invalid_utf8_array;
match str::from_utf8(invalid_utf8) {
Err(utf8_error) => {
let parse_error: ParseError = utf8_error.into();
match parse_error {
ParseError::InvalidUtf8(_) => {
}
_ => panic!("Expected InvalidUtf8 error"),
}
}
Ok(_) => panic!("Expected UTF-8 validation to fail"),
}
}
}