1#[cfg(feature = "schema")]
12use schemars::JsonSchema;
13use serde::de::{self, MapAccess, Visitor};
14use serde::ser::SerializeMap as _;
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use serde_json::{Map as JsonMap, Value as JsonValue};
17
18#[cfg(feature = "schema")]
19use super::types::legal::{Brief, Hearing, LegalCase, Regulation, Statute, Treaty};
20#[cfg(feature = "schema")]
21use super::types::specialized::{
22 AudioVisualWork, Classic, Dataset, Event, Patent, Software, Standard,
23};
24#[cfg(feature = "schema")]
25use super::types::structural::{
26 Collection, CollectionComponent, Monograph, Serial, SerialComponent,
27};
28use super::{ClassExtension, InputReference, ReferenceClass, UnknownClassData};
29
30fn duplicate_field_error<E: de::Error>(field: &str) -> E {
38 de::Error::custom(format_args!("duplicate field `{field}`"))
39}
40
41impl<'de> Deserialize<'de> for InputReference {
42 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
43 where
44 D: Deserializer<'de>,
45 {
46 struct ReferenceVisitor;
47
48 impl<'de> Visitor<'de> for ReferenceVisitor {
49 type Value = InputReference;
50
51 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 formatter.write_str("a flat reference object with a `class` discriminator")
53 }
54
55 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
56 where
57 M: MapAccess<'de>,
58 {
59 let mut class = None;
60 let mut body = JsonMap::new();
61
62 while let Some(key) = map.next_key::<String>()? {
63 if key == "class" {
64 if class.is_some() {
65 return Err(duplicate_field_error::<M::Error>("class"));
69 }
70 class = Some(map.next_value::<String>()?);
71 } else {
72 let value = map.next_value::<JsonValue>()?;
73 if body.insert(key.clone(), value).is_some() {
74 return Err(duplicate_field_error::<M::Error>(&key));
75 }
76 }
77 }
78
79 let class = class.ok_or_else(|| de::Error::missing_field("class"))?;
80 deserialize_reference_body(&class, body).map_err(de::Error::custom)
81 }
82 }
83
84 deserializer.deserialize_map(ReferenceVisitor)
85 }
86}
87
88#[derive(Serialize)]
93struct FlatClassProxy<'a, T: Serialize + ?Sized> {
94 class: &'a str,
95 #[serde(flatten)]
96 inner: &'a T,
97}
98
99impl Serialize for InputReference {
100 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
101 where
102 S: Serializer,
103 {
104 match &self.extension {
110 ClassExtension::Monograph(inner) => FlatClassProxy {
111 class: self.extension.class_name(),
112 inner: inner.as_ref(),
113 }
114 .serialize(serializer),
115 ClassExtension::CollectionComponent(inner) => FlatClassProxy {
116 class: self.extension.class_name(),
117 inner: inner.as_ref(),
118 }
119 .serialize(serializer),
120 ClassExtension::SerialComponent(inner) => FlatClassProxy {
121 class: self.extension.class_name(),
122 inner: inner.as_ref(),
123 }
124 .serialize(serializer),
125 ClassExtension::Collection(inner) => FlatClassProxy {
126 class: self.extension.class_name(),
127 inner: inner.as_ref(),
128 }
129 .serialize(serializer),
130 ClassExtension::Serial(inner) => FlatClassProxy {
131 class: self.extension.class_name(),
132 inner: inner.as_ref(),
133 }
134 .serialize(serializer),
135 ClassExtension::LegalCase(inner) => FlatClassProxy {
136 class: self.extension.class_name(),
137 inner: inner.as_ref(),
138 }
139 .serialize(serializer),
140 ClassExtension::Statute(inner) => FlatClassProxy {
141 class: self.extension.class_name(),
142 inner: inner.as_ref(),
143 }
144 .serialize(serializer),
145 ClassExtension::Treaty(inner) => FlatClassProxy {
146 class: self.extension.class_name(),
147 inner: inner.as_ref(),
148 }
149 .serialize(serializer),
150 ClassExtension::Hearing(inner) => FlatClassProxy {
151 class: self.extension.class_name(),
152 inner: inner.as_ref(),
153 }
154 .serialize(serializer),
155 ClassExtension::Regulation(inner) => FlatClassProxy {
156 class: self.extension.class_name(),
157 inner: inner.as_ref(),
158 }
159 .serialize(serializer),
160 ClassExtension::Brief(inner) => FlatClassProxy {
161 class: self.extension.class_name(),
162 inner: inner.as_ref(),
163 }
164 .serialize(serializer),
165 ClassExtension::Classic(inner) => FlatClassProxy {
166 class: self.extension.class_name(),
167 inner: inner.as_ref(),
168 }
169 .serialize(serializer),
170 ClassExtension::Patent(inner) => FlatClassProxy {
171 class: self.extension.class_name(),
172 inner: inner.as_ref(),
173 }
174 .serialize(serializer),
175 ClassExtension::Dataset(inner) => FlatClassProxy {
176 class: self.extension.class_name(),
177 inner: inner.as_ref(),
178 }
179 .serialize(serializer),
180 ClassExtension::Standard(inner) => FlatClassProxy {
181 class: self.extension.class_name(),
182 inner: inner.as_ref(),
183 }
184 .serialize(serializer),
185 ClassExtension::Software(inner) => FlatClassProxy {
186 class: self.extension.class_name(),
187 inner: inner.as_ref(),
188 }
189 .serialize(serializer),
190 ClassExtension::Event(inner) => FlatClassProxy {
191 class: self.extension.class_name(),
192 inner: inner.as_ref(),
193 }
194 .serialize(serializer),
195 ClassExtension::AudioVisual(inner) => FlatClassProxy {
196 class: self.extension.class_name(),
197 inner: inner.as_ref(),
198 }
199 .serialize(serializer),
200 ClassExtension::Unknown(data) => {
201 let mut out = serializer.serialize_map(Some(data.fields.len() + 1))?;
202 out.serialize_entry("class", &data.class)?;
203 for (key, value) in &data.fields {
204 out.serialize_entry(key, value)?;
205 }
206 out.end()
207 }
208 }
209 }
210}
211
212#[cfg(feature = "schema")]
213impl JsonSchema for InputReference {
214 fn schema_name() -> std::borrow::Cow<'static, str> {
215 "InputReference".into()
216 }
217
218 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
219 let variants = [
220 reference_schema_branch::<Monograph>(generator, ReferenceClass::Monograph.name()),
221 reference_schema_branch::<CollectionComponent>(
222 generator,
223 ReferenceClass::CollectionComponent.name(),
224 ),
225 reference_schema_branch::<SerialComponent>(
226 generator,
227 ReferenceClass::SerialComponent.name(),
228 ),
229 reference_schema_branch::<Collection>(generator, ReferenceClass::Collection.name()),
230 reference_schema_branch::<Serial>(generator, ReferenceClass::Serial.name()),
231 reference_schema_branch::<LegalCase>(generator, ReferenceClass::LegalCase.name()),
232 reference_schema_branch::<Statute>(generator, ReferenceClass::Statute.name()),
233 reference_schema_branch::<Treaty>(generator, ReferenceClass::Treaty.name()),
234 reference_schema_branch::<Hearing>(generator, ReferenceClass::Hearing.name()),
235 reference_schema_branch::<Regulation>(generator, ReferenceClass::Regulation.name()),
236 reference_schema_branch::<Brief>(generator, ReferenceClass::Brief.name()),
237 reference_schema_branch::<Classic>(generator, ReferenceClass::Classic.name()),
238 reference_schema_branch::<Patent>(generator, ReferenceClass::Patent.name()),
239 reference_schema_branch::<Dataset>(generator, ReferenceClass::Dataset.name()),
240 reference_schema_branch::<Standard>(generator, ReferenceClass::Standard.name()),
241 reference_schema_branch::<Software>(generator, ReferenceClass::Software.name()),
242 reference_schema_branch::<Event>(generator, ReferenceClass::Event.name()),
243 reference_schema_branch::<AudioVisualWork>(
244 generator,
245 ReferenceClass::AudioVisual.name(),
246 ),
247 ];
248
249 schemars::json_schema!({
250 "oneOf": variants,
251 "unevaluatedProperties": false
252 })
253 }
254}
255
256#[cfg(feature = "schema")]
257fn reference_schema_branch<T: JsonSchema>(
258 generator: &mut schemars::SchemaGenerator,
259 class: &str,
260) -> JsonValue {
261 let mut schema = T::json_schema(generator);
262 let object = schema.ensure_object();
263 if !object.get("properties").is_some_and(JsonValue::is_object) {
264 object.insert("properties".to_string(), JsonValue::Object(JsonMap::new()));
265 }
266 let Some(properties) = object
267 .get_mut("properties")
268 .and_then(JsonValue::as_object_mut)
269 else {
270 return schema.to_value();
271 };
272 properties.insert(
273 "class".to_string(),
274 serde_json::json!({
275 "type": "string",
276 "const": class
277 }),
278 );
279
280 if !object.get("required").is_some_and(JsonValue::is_array) {
281 object.insert("required".to_string(), JsonValue::Array(Vec::new()));
282 }
283 let Some(required) = object.get_mut("required").and_then(JsonValue::as_array_mut) else {
284 return schema.to_value();
285 };
286 if !required.iter().any(|value| value.as_str() == Some("class")) {
287 required.push(JsonValue::String("class".to_string()));
288 }
289
290 schema.to_value()
291}
292
293fn deserialize_reference_body(
294 class: &str,
295 body: JsonMap<String, JsonValue>,
296) -> Result<InputReference, serde_json::Error> {
297 let value = JsonValue::Object(body);
298 match ReferenceClass::from_known_name(class) {
299 Some(ReferenceClass::Monograph) => {
300 InputReference::from_known(ClassExtension::Monograph, value)
301 }
302 Some(ReferenceClass::CollectionComponent) => {
303 InputReference::from_known(ClassExtension::CollectionComponent, value)
304 }
305 Some(ReferenceClass::SerialComponent) => {
306 InputReference::from_known(ClassExtension::SerialComponent, value)
307 }
308 Some(ReferenceClass::Collection) => {
309 InputReference::from_known(ClassExtension::Collection, value)
310 }
311 Some(ReferenceClass::Serial) => InputReference::from_known(ClassExtension::Serial, value),
312 Some(ReferenceClass::LegalCase) => {
313 InputReference::from_known(ClassExtension::LegalCase, value)
314 }
315 Some(ReferenceClass::Statute) => InputReference::from_known(ClassExtension::Statute, value),
316 Some(ReferenceClass::Treaty) => InputReference::from_known(ClassExtension::Treaty, value),
317 Some(ReferenceClass::Hearing) => InputReference::from_known(ClassExtension::Hearing, value),
318 Some(ReferenceClass::Regulation) => {
319 InputReference::from_known(ClassExtension::Regulation, value)
320 }
321 Some(ReferenceClass::Brief) => InputReference::from_known(ClassExtension::Brief, value),
322 Some(ReferenceClass::Classic) => InputReference::from_known(ClassExtension::Classic, value),
323 Some(ReferenceClass::Patent) => InputReference::from_known(ClassExtension::Patent, value),
324 Some(ReferenceClass::Dataset) => InputReference::from_known(ClassExtension::Dataset, value),
325 Some(ReferenceClass::Standard) => {
326 InputReference::from_known(ClassExtension::Standard, value)
327 }
328 Some(ReferenceClass::Software) => {
329 InputReference::from_known(ClassExtension::Software, value)
330 }
331 Some(ReferenceClass::Event) => InputReference::from_known(ClassExtension::Event, value),
332 Some(ReferenceClass::AudioVisual) => {
333 InputReference::from_known(ClassExtension::AudioVisual, value)
334 }
335 Some(ReferenceClass::Unknown(_)) | None => {
336 let fields = if let JsonValue::Object(fields) = value {
337 fields
338 } else {
339 JsonMap::new()
340 };
341 Ok(InputReference::Unknown(Box::new(UnknownClassData {
342 class: class.to_string(),
343 fields,
344 })))
345 }
346 }
347}