use alloc::{
format,
string::{FromUtf8Error, String, ToString},
vec::Vec,
};
use crate::{Pointer, Token};
use core::{
fmt::{Debug, Display, Formatter},
num::ParseIntError,
};
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Error {
Index(IndexError),
Unresolvable(UnresolvableError),
NotFound(NotFoundError),
MalformedPointer(MalformedPointerError),
}
impl Error {
pub fn is_index(&self) -> bool {
matches!(self, Error::Index(_))
}
pub fn is_unresolvable(&self) -> bool {
matches!(self, Error::Unresolvable(_))
}
pub fn is_not_found(&self) -> bool {
matches!(self, Error::NotFound(_))
}
pub fn is_malformed_pointer(&self) -> bool {
matches!(self, Error::MalformedPointer(_))
}
}
impl From<MalformedPointerError> for Error {
fn from(err: MalformedPointerError) -> Self {
Error::MalformedPointer(err)
}
}
impl From<IndexError> for Error {
fn from(err: IndexError) -> Self {
Error::Index(err)
}
}
impl From<NotFoundError> for Error {
fn from(err: NotFoundError) -> Self {
Error::NotFound(err)
}
}
impl From<OutOfBoundsError> for Error {
fn from(err: OutOfBoundsError) -> Self {
Error::Index(IndexError::from(err))
}
}
impl From<UnresolvableError> for Error {
fn from(err: UnresolvableError) -> Self {
Error::Unresolvable(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Error::Index(err) => Display::fmt(err, f),
Error::Unresolvable(err) => Display::fmt(err, f),
Error::NotFound(err) => Display::fmt(err, f),
Error::MalformedPointer(err) => Display::fmt(err, f),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct UnresolvableError {
pub pointer: Pointer,
pub leaf: Option<Token>,
}
impl UnresolvableError {
pub fn new(pointer: Pointer) -> Self {
let leaf = if pointer.count() >= 2 {
Some(pointer.get(pointer.count() - 2).unwrap())
} else {
None
};
Self { pointer, leaf }
}
}
impl Display for UnresolvableError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(
f,
"can not resolve \"{}\" due to {} being a scalar value",
self.pointer,
self.leaf
.as_deref()
.map_or_else(|| "the root value".to_string(), |l| format!("\"{l}\""))
)
}
}
#[derive(PartialEq, Eq, Clone)]
pub enum IndexError {
Parse(ParseError),
OutOfBounds(OutOfBoundsError),
}
impl Display for IndexError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
IndexError::Parse(err) => Display::fmt(&err, f),
IndexError::OutOfBounds(err) => Display::fmt(&err, f),
}
}
}
impl Debug for IndexError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Display::fmt(self, f)
}
}
#[cfg(feature = "std")]
impl std::error::Error for IndexError {}
impl From<OutOfBoundsError> for IndexError {
fn from(err: OutOfBoundsError) -> Self {
IndexError::OutOfBounds(err)
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct ParseError {
pub source: ParseIntError,
pub token: Token,
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.source)
}
}
impl Debug for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParseError")
.field("source", &self.source)
.field("token", &self.token)
.finish()
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct OutOfBoundsError {
pub len: usize,
pub index: usize,
pub token: Token,
}
#[cfg(feature = "std")]
impl std::error::Error for OutOfBoundsError {}
impl Display for OutOfBoundsError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "index {} out of bounds", self.index)
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct NotUtf8Error {
pub source: FromUtf8Error,
pub path: Vec<u8>,
}
impl core::fmt::Display for NotUtf8Error {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "not utf8: {}", self.source)
}
}
#[cfg(feature = "std")]
impl std::error::Error for NotUtf8Error {}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum MalformedPointerError {
NoLeadingSlash(String),
InvalidEncoding(String),
NotUtf8(NotUtf8Error),
}
impl From<NotUtf8Error> for MalformedPointerError {
fn from(err: NotUtf8Error) -> Self {
MalformedPointerError::NotUtf8(err)
}
}
impl From<FromUtf8Error> for MalformedPointerError {
fn from(err: FromUtf8Error) -> Self {
MalformedPointerError::NotUtf8(NotUtf8Error {
source: err,
path: Vec::new(),
})
}
}
impl Display for MalformedPointerError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
MalformedPointerError::NoLeadingSlash(s) => {
write!(
f,
"json pointer \"{s}\" is malformed due to missing starting slash",
)
}
MalformedPointerError::InvalidEncoding(s) => {
write!(f, "json pointer \"{s}\" is improperly encoded")
}
MalformedPointerError::NotUtf8(err) => {
write!(f, "json pointer is not UTF-8: {}", err.source)
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for MalformedPointerError {}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct NotFoundError {
pub pointer: Pointer,
}
impl NotFoundError {
pub fn new(pointer: Pointer) -> Self {
NotFoundError { pointer }
}
}
impl Display for NotFoundError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(
f,
"the resource at json pointer \"{}\" was not found",
self.pointer
)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ReplaceTokenError {
pub index: usize,
pub count: usize,
pub pointer: Pointer,
}
#[cfg(feature = "std")]
impl std::error::Error for ReplaceTokenError {}
impl Display for ReplaceTokenError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(
f,
"index {} is out of bounds ({}) for the pointer {}",
self.index, self.count, self.pointer
)
}
}