1pub use super::ContentSource;
4use crate::Status;
5use indexmap::IndexMap;
6use serde::{de::Unexpected, Deserialize, Serialize, Serializer};
7use std::borrow::Cow;
8use std::str::FromStr;
9use thiserror::Error;
10use warg_crypto::hash::AnyHash;
11
12#[derive(Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct ContentSourcesResponse {
16 pub content_sources: IndexMap<AnyHash, Vec<ContentSource>>,
19}
20
21#[non_exhaustive]
23#[derive(Debug, Error)]
24pub enum ContentError {
25 #[error("content digest `{0}` was not found")]
27 ContentDigestNotFound(AnyHash),
28 #[error("{message}")]
30 Message {
31 status: u16,
33 message: String,
35 },
36}
37
38impl ContentError {
39 pub fn status(&self) -> u16 {
41 match self {
42 Self::ContentDigestNotFound(_) => 404,
43 Self::Message { status, .. } => *status,
44 }
45 }
46}
47
48#[derive(Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50enum EntityType {
51 ContentDigest,
52}
53
54#[derive(Serialize, Deserialize)]
55#[serde(untagged, rename_all = "camelCase")]
56enum RawError<'a, T>
57where
58 T: Clone + ToOwned,
59 <T as ToOwned>::Owned: Serialize + for<'b> Deserialize<'b>,
60{
61 NotFound {
62 status: Status<404>,
63 #[serde(rename = "type")]
64 ty: EntityType,
65 id: Cow<'a, T>,
66 },
67 Message {
68 status: u16,
69 message: Cow<'a, str>,
70 },
71}
72
73impl Serialize for ContentError {
74 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
75 match self {
76 Self::ContentDigestNotFound(digest) => RawError::NotFound {
77 status: Status::<404>,
78 ty: EntityType::ContentDigest,
79 id: Cow::Borrowed(digest),
80 }
81 .serialize(serializer),
82 Self::Message { status, message } => RawError::Message::<()> {
83 status: *status,
84 message: Cow::Borrowed(message),
85 }
86 .serialize(serializer),
87 }
88 }
89}
90
91impl<'de> Deserialize<'de> for ContentError {
92 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93 where
94 D: serde::Deserializer<'de>,
95 {
96 match RawError::<String>::deserialize(deserializer)? {
97 RawError::NotFound { status: _, ty, id } => match ty {
98 EntityType::ContentDigest => Ok(Self::ContentDigestNotFound(
99 AnyHash::from_str(&id).map_err(|_| {
100 serde::de::Error::invalid_value(Unexpected::Str(&id), &"a valid digest")
101 })?,
102 )),
103 },
104 RawError::Message { status, message } => Ok(Self::Message {
105 status,
106 message: message.into_owned(),
107 }),
108 }
109 }
110}