use serde_json::Value;
pub trait ProtocolError: core::fmt::Debug + Send + Sync + Sized + 'static {
fn code(&self) -> &str;
fn description(&self) -> &str;
fn details(&self) -> &Value;
fn not_implemented(action: &str) -> Self;
fn from_wire(code: &str, description: &str, details: Value) -> Self;
}
#[derive(Debug)]
pub enum ClientError<E> {
Protocol(E),
Timeout,
Decode(serde_json::Error),
Transport(crate::transport::TransportError),
Closed,
}
impl<E: ProtocolError> core::fmt::Display for ClientError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ClientError::Protocol(e) => {
write!(f, "protocol error: {} ({})", e.code(), e.description())
}
ClientError::Timeout => write!(f, "request timed out"),
ClientError::Decode(e) => write!(f, "failed to decode payload: {e}"),
ClientError::Transport(e) => write!(f, "transport error: {e}"),
ClientError::Closed => write!(f, "connection closed"),
}
}
}
impl<E: ProtocolError> core::error::Error for ClientError<E> {}
#[cfg(all(
feature = "validate",
any(feature = "ocpp_1_6", feature = "ocpp_2_0_1", feature = "ocpp_2_1")
))]
pub(crate) fn validation_error_parts(
error: &ocpp_types::validate::ValidationError,
) -> (alloc::string::String, Value) {
use alloc::string::ToString;
use core::fmt::Write;
use ocpp_types::validate::PathSegment;
let mut path = alloc::string::String::new();
if error.path_truncated() {
path.push_str("...");
}
if error.path().is_empty() && !error.path_truncated() {
path.push_str("<payload>");
}
for (position, segment) in error.path().iter().enumerate() {
match segment {
PathSegment::Field(name) => {
if position > 0 || error.path_truncated() {
path.push('.');
}
path.push_str(name);
}
PathSegment::Index(index) => {
let _ = write!(path, "[{index}]");
}
}
}
(error.to_string(), serde_json::json!({ "path": path }))
}