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