#[cfg(not(feature = "std"))]
use alloc::{fmt, format, string::{FromUtf8Error, String, ToString}};
#[cfg(feature = "std")]
use std::{fmt, string::FromUtf8Error};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConversionError {
InvalidUtf8(String, FromUtf8Error),
ValidationFailed(String, String),
BoundedVecOverflow(String),
Custom(String),
}
impl fmt::Display for ConversionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConversionError::InvalidUtf8(field, err) => {
write!(f, "Invalid UTF-8 in field '{field}': {err}")
}
ConversionError::ValidationFailed(field, msg) => {
write!(f, "Validation failed for field '{field}': {msg}")
}
ConversionError::BoundedVecOverflow(field) => {
write!(f, "BoundedVec capacity overflow in field '{field}'")
}
ConversionError::Custom(msg) => write!(f, "{msg}"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ConversionError {}
impl From<ValidationError> for ConversionError {
fn from(err: ValidationError) -> Self {
ConversionError::ValidationFailed(
err.field.unwrap_or_else(|| "Unknown".to_string()),
err.message,
)
}
}
pub trait Validatable {
type Error;
fn validate(&self) -> Result<(), Self::Error>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ValidationError {
pub field: Option<String>,
pub message: String,
}
impl ValidationError {
pub fn new(message: impl Into<String>) -> Self {
Self {
field: None,
message: message.into(),
}
}
pub fn field(field: impl Into<String>, message: impl Into<String>) -> Self {
Self {
field: Some(field.into()),
message: message.into(),
}
}
#[must_use]
pub fn invalid_format(type_name: &str, value: &str) -> Self {
Self::new(format!("Invalid {type_name} format: '{value}'"))
}
}
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref field) = self.field {
write!(f, "Validation error in field '{}': {}", field, self.message)
} else {
write!(f, "Validation error: {}", self.message)
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ValidationError {}