use super::BoxError;
use crate::json::JsonValue;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("{message}")]
pub struct EmptyResponseBodyError {
pub message: String,
}
impl EmptyResponseBodyError {
#[must_use]
pub fn new() -> Self {
Self {
message: "empty response body".to_owned(),
}
}
#[must_use]
pub fn with_message(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
}
impl Default for EmptyResponseBodyError {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("{message}")]
pub struct NoContentGeneratedError {
pub message: String,
}
impl NoContentGeneratedError {
#[must_use]
pub fn new() -> Self {
Self {
message: "no content generated".to_owned(),
}
}
#[must_use]
pub fn with_message(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
}
impl Default for NoContentGeneratedError {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, thiserror::Error)]
#[error("{message}")]
pub struct InvalidResponseDataError {
pub message: String,
pub data: JsonValue,
}
impl InvalidResponseDataError {
#[must_use]
pub fn new(message: impl Into<String>, data: JsonValue) -> Self {
Self {
message: message.into(),
data,
}
}
#[must_use]
pub fn from_data(data: JsonValue) -> Self {
let rendered = data.to_string();
let message = format!(
"invalid response data: {}",
super::truncate_for_display(&rendered, 512)
);
Self { message, data }
}
}
#[derive(Debug, thiserror::Error)]
#[error("json parsing failed: {cause}")]
pub struct JsonParseError {
pub text: String,
#[source]
pub cause: BoxError,
}
impl JsonParseError {
#[must_use]
pub fn new(
text: impl Into<String>,
cause: impl std::error::Error + Send + Sync + 'static,
) -> Self {
Self {
text: text.into(),
cause: Box::new(cause),
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct TypeValidationContext {
pub field: Option<String>,
pub entity_name: Option<String>,
pub entity_id: Option<String>,
}
#[derive(Debug, thiserror::Error)]
pub struct TypeValidationError {
pub value: JsonValue,
pub context: Option<Box<TypeValidationContext>>,
#[source]
pub cause: BoxError,
}
impl TypeValidationError {
#[must_use]
pub fn new(value: JsonValue, cause: impl std::error::Error + Send + Sync + 'static) -> Self {
Self {
value,
context: None,
cause: Box::new(cause),
}
}
#[must_use]
pub fn with_context(mut self, context: TypeValidationContext) -> Self {
self.context = Some(Box::new(context));
self
}
#[must_use]
pub fn wrap(value: JsonValue, cause: BoxError, context: Option<TypeValidationContext>) -> Self {
let context = context.map(Box::new);
match cause.downcast::<TypeValidationError>() {
Ok(existing) if existing.value == value && existing.context == context => *existing,
Ok(existing) => Self {
value,
context,
cause: existing,
},
Err(cause) => Self {
value,
context,
cause,
},
}
}
}
impl std::fmt::Display for TypeValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("type validation failed")?;
if let Some(context) = &self.context {
if let Some(field) = &context.field {
write!(f, " for {field}")?;
}
let mut parts = Vec::new();
if let Some(name) = &context.entity_name {
parts.push(name.clone());
}
if let Some(id) = &context.entity_id {
parts.push(format!("id: \"{id}\""));
}
if !parts.is_empty() {
write!(f, " ({})", parts.join(", "))?;
}
}
write!(f, ": {}", self.cause)
}
}