pub use super::ContentSource;
use crate::Status;
use indexmap::IndexMap;
use serde::{de::Unexpected, Deserialize, Serialize, Serializer};
use std::borrow::Cow;
use std::str::FromStr;
use thiserror::Error;
use warg_crypto::hash::AnyHash;
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ContentSourcesResponse {
pub content_sources: IndexMap<AnyHash, Vec<ContentSource>>,
}
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum ContentError {
#[error("content digest `{0}` was not found")]
ContentDigestNotFound(AnyHash),
#[error("{message}")]
Message {
status: u16,
message: String,
},
}
impl ContentError {
pub fn status(&self) -> u16 {
match self {
Self::ContentDigestNotFound(_) => 404,
Self::Message { status, .. } => *status,
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
enum EntityType {
ContentDigest,
}
#[derive(Serialize, Deserialize)]
#[serde(untagged, rename_all = "camelCase")]
enum RawError<'a, T>
where
T: Clone + ToOwned,
<T as ToOwned>::Owned: Serialize + for<'b> Deserialize<'b>,
{
NotFound {
status: Status<404>,
#[serde(rename = "type")]
ty: EntityType,
id: Cow<'a, T>,
},
Message {
status: u16,
message: Cow<'a, str>,
},
}
impl Serialize for ContentError {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::ContentDigestNotFound(digest) => RawError::NotFound {
status: Status::<404>,
ty: EntityType::ContentDigest,
id: Cow::Borrowed(digest),
}
.serialize(serializer),
Self::Message { status, message } => RawError::Message::<()> {
status: *status,
message: Cow::Borrowed(message),
}
.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for ContentError {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
match RawError::<String>::deserialize(deserializer)? {
RawError::NotFound { status: _, ty, id } => match ty {
EntityType::ContentDigest => Ok(Self::ContentDigestNotFound(
AnyHash::from_str(&id).map_err(|_| {
serde::de::Error::invalid_value(Unexpected::Str(&id), &"a valid digest")
})?,
)),
},
RawError::Message { status, message } => Ok(Self::Message {
status,
message: message.into_owned(),
}),
}
}
}