1use std::{borrow::Cow, fmt, str};
2
3use chrono::{Month, NaiveDate};
4use serde::{
5 de::{
6 value::{StrDeserializer, StringDeserializer},
7 DeserializeOwned, Visitor,
8 },
9 ser::SerializeStruct,
10 Deserialize, Serialize,
11};
12
13use crate::{B64Url, Extension};
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct EditableField<T, E = ()> {
17 pub id: Option<B64Url>,
20 pub value: Expected<T>,
22 pub label: Option<String>,
25 pub extensions: Option<Vec<Extension<E>>>,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq)]
36#[non_exhaustive]
37pub enum UnexpectedField {
38 String(EditableFieldString),
39 ConcealedString(EditableFieldConcealedString),
40 Boolean(EditableFieldBoolean),
41 Date(EditableFieldDate),
42 YearMonth(EditableFieldYearMonth),
43 SubdivisionCode(EditableFieldSubdivisionCode),
44 CountryCode(EditableFieldCountryCode),
45 WifiNetworkSecurityType(EditableFieldWifiNetworkSecurityType),
46 Email(EditableFieldEmail),
47 Number(EditableFieldNumber),
48 Unknown {
49 field_type: FieldType,
51 value: String,
55 },
56}
57
58impl UnexpectedField {
59 #[inline]
61 pub fn field_type(&self) -> FieldType {
62 match self {
63 Self::String(_) => EditableFieldString::field_type(),
64 Self::ConcealedString(_) => EditableFieldConcealedString::field_type(),
65 Self::Boolean(_) => EditableFieldBoolean::field_type(),
66 Self::Date(_) => EditableFieldDate::field_type(),
67 Self::YearMonth(_) => EditableFieldYearMonth::field_type(),
68 Self::SubdivisionCode(_) => EditableFieldSubdivisionCode::field_type(),
69 Self::CountryCode(_) => EditableFieldCountryCode::field_type(),
70 Self::WifiNetworkSecurityType(_) => EditableFieldWifiNetworkSecurityType::field_type(),
71 Self::Email(_) => EditableFieldEmail::field_type(),
72 Self::Number(_) => EditableFieldNumber::field_type(),
73 Self::Unknown { field_type, .. } => field_type.clone(),
74 }
75 }
76}
77
78impl From<UnexpectedField> for String {
79 #[inline]
80 fn from(value: UnexpectedField) -> Self {
81 match value {
82 UnexpectedField::String(v) => v.0,
83 UnexpectedField::ConcealedString(v) => v.0,
84 UnexpectedField::WifiNetworkSecurityType(v) => v.into(),
85 UnexpectedField::SubdivisionCode(v) => v.0,
86 UnexpectedField::CountryCode(v) => v.0,
87 UnexpectedField::Unknown { value: v, .. } => v,
88 UnexpectedField::Email(v) => v.0,
89 UnexpectedField::Number(v) => v.0,
90 UnexpectedField::Boolean(v) => v.into(),
91 UnexpectedField::Date(v) => v.into(),
92 UnexpectedField::YearMonth(v) => v.into(),
93 }
94 }
95}
96
97#[derive(Clone, Debug, PartialEq, Eq)]
99enum ExpectedInner<T> {
100 Expected(T),
102 Unexpected(UnexpectedField),
104}
105
106#[derive(Clone, Debug, PartialEq, Eq)]
114pub struct Expected<T>(ExpectedInner<T>);
115
116impl<T> Expected<T>
117where
118 T: EditableFieldType,
119{
120 #[inline]
122 pub fn field_type(&self) -> FieldType {
123 match &self.0 {
124 ExpectedInner::Expected(_) => T::field_type(),
125 ExpectedInner::Unexpected(f) => f.field_type(),
126 }
127 }
128
129 #[inline]
131 pub fn as_expected(&self) -> Result<&T, &UnexpectedField> {
132 match &self.0 {
133 ExpectedInner::Expected(t) => Ok(t),
134 ExpectedInner::Unexpected(f) => Err(f),
135 }
136 }
137
138 #[inline]
140 pub fn into_expected(self) -> Result<T, UnexpectedField> {
141 match self.0 {
142 ExpectedInner::Expected(t) => Ok(t),
143 ExpectedInner::Unexpected(f) => Err(f),
144 }
145 }
146}
147
148impl<T> From<T> for Expected<T> {
149 #[inline]
150 fn from(t: T) -> Self {
151 Self(ExpectedInner::Expected(t))
152 }
153}
154
155impl<T> From<Expected<T>> for String
156where
157 T: Into<String>,
158{
159 #[inline]
160 fn from(value: Expected<T>) -> Self {
161 match value.0 {
162 ExpectedInner::Expected(t) => t.into(),
163 ExpectedInner::Unexpected(f) => f.into(),
164 }
165 }
166}
167
168#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
169#[serde(rename_all = "kebab-case")]
170#[non_exhaustive]
171pub enum FieldType {
172 String,
174 ConcealedString,
177 Email,
181 Number,
183 Boolean,
185 Date,
188 YearMonth,
192 WifiNetworkSecurityType,
194 SubdivisionCode,
196 CountryCode,
198 #[serde(untagged)]
199 Unknown(String),
200}
201
202pub trait EditableFieldType {
204 fn field_type() -> FieldType;
206}
207
208impl<T, E> Serialize for EditableField<T, E>
209where
210 T: EditableFieldType + Serialize,
211 E: Serialize,
212{
213 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
214 where
215 S: serde::Serializer,
216 {
217 let len = 2
218 + self.id.is_some() as usize
219 + self.label.is_some() as usize
220 + self.extensions.is_some() as usize;
221 let mut state = serializer.serialize_struct("editable_field", len)?;
222
223 if let Some(ref id) = self.id {
224 state.serialize_field("id", id)?;
225 } else {
226 state.skip_field("id")?;
227 }
228
229 state.serialize_field("fieldType", &self.value.field_type())?;
230 match &self.value.0 {
231 ExpectedInner::Expected(t) => {
232 state.serialize_field("value", &t)?;
233 }
234 ExpectedInner::Unexpected(t) => match t {
235 UnexpectedField::String(v) => state.serialize_field("value", &v)?,
236 UnexpectedField::ConcealedString(v) => state.serialize_field("value", &v)?,
237 UnexpectedField::WifiNetworkSecurityType(v) => {
238 state.serialize_field("value", &v)?
239 }
240 UnexpectedField::SubdivisionCode(v) => state.serialize_field("value", &v)?,
241 UnexpectedField::CountryCode(v) => state.serialize_field("value", &v)?,
242 UnexpectedField::Unknown { value: v, .. } => state.serialize_field("value", &v)?,
243 UnexpectedField::Boolean(b) => {
244 let v = if b.0 { "true" } else { "false" };
245 state.serialize_field("value", v)?
246 }
247 UnexpectedField::Date(date) => state.serialize_field("value", &date)?,
248 UnexpectedField::YearMonth(v) => state.serialize_field("value", &v)?,
249 UnexpectedField::Email(v) => state.serialize_field("value", &v)?,
250 UnexpectedField::Number(v) => state.serialize_field("value", &v)?,
251 },
252 }
253
254 if let Some(ref label) = self.label {
255 state.serialize_field("label", label)?;
256 } else {
257 state.skip_field("label")?;
258 }
259
260 if let Some(ref ext) = self.extensions {
261 if ext.is_empty() {
262 state.skip_field("extensions")?;
263 } else {
264 state.serialize_field("extensions", ext)?;
265 }
266 } else {
267 state.skip_field("extensions")?;
268 }
269
270 state.end()
271 }
272}
273
274#[derive(Deserialize)]
275#[serde(rename_all = "camelCase")]
276struct EditableFieldHelper<E> {
277 #[serde(default)]
278 id: Option<B64Url>,
279 value: String,
280 field_type: FieldType,
281 #[serde(default)]
282 label: Option<String>,
283 #[serde(default = "none::<E>")]
284 extensions: Option<Vec<Extension<E>>>,
285}
286
287fn none<E>() -> Option<Vec<Extension<E>>> {
290 None
291}
292
293impl<'de, T, E> Deserialize<'de> for EditableField<T, E>
294where
295 T: EditableFieldType + DeserializeOwned,
296 E: Deserialize<'de>,
297{
298 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
299 where
300 D: serde::Deserializer<'de>,
301 {
302 let helper: EditableFieldHelper<E> = EditableFieldHelper::deserialize(deserializer)?;
303
304 let value = if T::field_type() == helper.field_type {
305 match T::deserialize(StrDeserializer::<serde::de::value::Error>::new(
306 helper.value.as_str(),
307 )) {
308 Ok(t) => ExpectedInner::Expected(t),
309 Err(_) => ExpectedInner::Unexpected(UnexpectedField::Unknown {
310 field_type: helper.field_type,
311 value: helper.value,
312 }),
313 }
314 } else {
315 macro_rules! deserialize_from_str {
316 ($t:tt => $variant:ident) => {
317 match $t::deserialize(StrDeserializer::<D::Error>::new(&helper.value)) {
318 Ok(v) => UnexpectedField::$variant(v),
319 _ => UnexpectedField::Unknown {
320 field_type: helper.field_type,
321 value: helper.value,
322 },
323 }
324 };
325 }
326
327 let value = match helper.field_type {
328 FieldType::String => UnexpectedField::String(EditableFieldString(helper.value)),
329 FieldType::ConcealedString => {
330 UnexpectedField::ConcealedString(EditableFieldConcealedString(helper.value))
331 }
332 FieldType::Boolean => deserialize_from_str!(EditableFieldBoolean => Boolean),
333 FieldType::Date => deserialize_from_str!(EditableFieldDate => Date),
334 FieldType::YearMonth => deserialize_from_str!(EditableFieldYearMonth => YearMonth),
335 FieldType::WifiNetworkSecurityType => {
336 deserialize_from_str!(EditableFieldWifiNetworkSecurityType => WifiNetworkSecurityType)
337 }
338 FieldType::SubdivisionCode => {
339 UnexpectedField::SubdivisionCode(EditableFieldSubdivisionCode(helper.value))
340 }
341 FieldType::CountryCode => {
342 UnexpectedField::CountryCode(EditableFieldCountryCode(helper.value))
343 }
344 FieldType::Email => UnexpectedField::Email(EditableFieldEmail(helper.value)),
345 FieldType::Number => UnexpectedField::Number(EditableFieldNumber(helper.value)),
346 FieldType::Unknown(_) => UnexpectedField::Unknown {
347 field_type: helper.field_type,
348 value: helper.value,
349 },
350 };
351
352 ExpectedInner::Unexpected(value)
353 };
354
355 Ok(Self {
356 id: helper.id,
357 value: Expected(value),
358 label: helper.label,
359 extensions: helper.extensions,
360 })
361 }
362}
363
364impl<T, E> From<T> for EditableField<T, E> {
366 fn from(s: T) -> Self {
367 EditableField {
368 id: None,
369 value: s.into(),
370 label: None,
371 extensions: None,
372 }
373 }
374}
375
376macro_rules! editable_field_string_type {
379 ($name:ident, $variant:ident) => {
380 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
381 #[serde(transparent)]
382 pub struct $name(pub String);
383
384 impl EditableFieldType for $name {
385 fn field_type() -> FieldType {
386 FieldType::$variant
387 }
388 }
389
390 impl From<String> for $name {
391 #[inline]
392 fn from(s: String) -> Self {
393 $name(s)
394 }
395 }
396
397 impl<E> From<String> for EditableField<$name, E> {
398 #[inline]
399 fn from(s: String) -> Self {
400 $name(s).into()
401 }
402 }
403
404 impl<E> From<EditableField<$name, E>> for String {
405 fn from(s: EditableField<$name, E>) -> Self {
406 match s.value.0 {
407 ExpectedInner::Expected(f) => f.0.into(),
408 ExpectedInner::Unexpected(f) => f.into(),
409 }
410 }
411 }
412
413 impl From<$name> for String {
414 #[inline]
415 fn from(v: $name) -> Self {
416 v.0
417 }
418 }
419
420 impl AsRef<str> for $name {
421 #[inline]
422 fn as_ref(&self) -> &str {
423 &self.0
424 }
425 }
426 };
427}
428
429editable_field_string_type!(EditableFieldString, String);
430editable_field_string_type!(EditableFieldConcealedString, ConcealedString);
431editable_field_string_type!(EditableFieldEmail, Email);
432editable_field_string_type!(EditableFieldNumber, Number);
433editable_field_string_type!(EditableFieldSubdivisionCode, SubdivisionCode);
434editable_field_string_type!(EditableFieldCountryCode, CountryCode);
435
436#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
437#[serde(transparent)]
438pub struct EditableFieldBoolean(#[serde(with = "serde_bool")] pub bool);
439impl EditableFieldType for EditableFieldBoolean {
440 fn field_type() -> FieldType {
441 FieldType::Boolean
442 }
443}
444
445impl<E> From<bool> for EditableField<EditableFieldBoolean, E> {
446 fn from(b: bool) -> Self {
447 EditableFieldBoolean(b).into()
448 }
449}
450
451impl From<EditableFieldBoolean> for String {
452 #[inline]
453 fn from(value: EditableFieldBoolean) -> Self {
454 if value.0 { "true" } else { "false" }.into()
455 }
456}
457
458#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
459#[serde(transparent)]
460pub struct EditableFieldDate(pub NaiveDate);
461impl EditableFieldType for EditableFieldDate {
462 fn field_type() -> FieldType {
463 FieldType::Date
464 }
465}
466
467impl From<EditableFieldDate> for String {
468 #[inline]
469 fn from(value: EditableFieldDate) -> Self {
470 value.0.format("%Y-%m-%d").to_string()
471 }
472}
473
474#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
475#[serde(into = "String")]
476pub struct EditableFieldYearMonth {
477 pub year: u16,
479 pub month: Month,
481}
482
483impl From<EditableFieldYearMonth> for String {
484 #[inline]
485 fn from(value: EditableFieldYearMonth) -> String {
486 format!("{:04}-{:02}", value.year, value.month.number_from_month())
487 }
488}
489
490impl EditableFieldType for EditableFieldYearMonth {
491 fn field_type() -> FieldType {
492 FieldType::YearMonth
493 }
494}
495
496impl<'de> Deserialize<'de> for EditableFieldYearMonth {
497 fn deserialize<D>(deserializer: D) -> Result<EditableFieldYearMonth, D::Error>
498 where
499 D: serde::Deserializer<'de>,
500 {
501 let s = deserializer.deserialize_str(CowVisitor)?;
502 let (year_str, month_str) = s
503 .split_once('-')
504 .ok_or_else(|| serde::de::Error::custom("Invalid format"))?;
505
506 Ok(EditableFieldYearMonth {
507 year: year_str
508 .parse::<u16>()
509 .map_err(|_| serde::de::Error::custom("Invalid year"))?,
510 month: month_str
511 .parse::<u8>()
512 .map_err(|_| serde::de::Error::custom("Invalid month"))?
513 .try_into()
514 .map_err(|_| serde::de::Error::custom("Invalid month"))?,
515 })
516 }
517}
518
519struct CowVisitor;
521impl<'de> Visitor<'de> for CowVisitor {
522 type Value = Cow<'de, str>;
523
524 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
525 formatter.write_str("a string")
526 }
527
528 fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
529 where
530 E: serde::de::Error,
531 {
532 Ok(Cow::Borrowed(value))
533 }
534
535 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
536 where
537 E: serde::de::Error,
538 {
539 Ok(Cow::Owned(value.to_owned()))
540 }
541
542 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
543 where
544 E: serde::de::Error,
545 {
546 Ok(Cow::Owned(value))
547 }
548}
549
550#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
551#[serde(rename_all = "kebab-case")]
552#[non_exhaustive]
553pub enum EditableFieldWifiNetworkSecurityType {
554 Unsecured,
555 WpaPersonal,
556 Wpa2Personal,
557 Wpa3Personal,
558 Wep,
559
560 #[serde(untagged)]
561 Other(String),
562}
563impl EditableFieldType for EditableFieldWifiNetworkSecurityType {
564 fn field_type() -> FieldType {
565 FieldType::WifiNetworkSecurityType
566 }
567}
568
569impl From<EditableFieldWifiNetworkSecurityType> for String {
570 #[inline]
571 fn from(value: EditableFieldWifiNetworkSecurityType) -> Self {
572 match value {
573 EditableFieldWifiNetworkSecurityType::Unsecured => "unsecured".into(),
574 EditableFieldWifiNetworkSecurityType::WpaPersonal => "wpa-personal".into(),
575 EditableFieldWifiNetworkSecurityType::Wpa2Personal => "wpa2-personal".into(),
576 EditableFieldWifiNetworkSecurityType::Wpa3Personal => "wpa3-personal".into(),
577 EditableFieldWifiNetworkSecurityType::Wep => "wep".into(),
578 EditableFieldWifiNetworkSecurityType::Other(o) => o,
579 }
580 }
581}
582
583#[derive(Clone, Debug, Serialize)]
585#[serde(untagged, bound(deserialize = "E: Deserialize<'de>"))]
586#[non_exhaustive]
587pub enum EditableFieldValue<E = ()> {
588 String(EditableField<EditableFieldString, E>),
589 ConcealedString(EditableField<EditableFieldConcealedString, E>),
590 Email(EditableField<EditableFieldEmail, E>),
591 Number(EditableField<EditableFieldNumber, E>),
592 Boolean(EditableField<EditableFieldBoolean, E>),
593 Date(EditableField<EditableFieldDate, E>),
594 YearMonth(EditableField<EditableFieldYearMonth, E>),
595 SubdivisionCode(EditableField<EditableFieldSubdivisionCode, E>),
596 CountryCode(EditableField<EditableFieldCountryCode, E>),
597 WifiNetworkSecurityType(EditableField<EditableFieldWifiNetworkSecurityType, E>),
598}
599
600impl<'de, E> Deserialize<'de> for EditableFieldValue<E>
601where
602 E: Deserialize<'de>,
603{
604 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
605 where
606 D: serde::Deserializer<'de>,
607 {
608 let helper: EditableFieldHelper<E> = EditableFieldHelper::deserialize(deserializer)?;
609
610 macro_rules! deserialize_field {
611 ($t: tt) => {{
612 let v = $t::deserialize(StringDeserializer::new(helper.value))?;
613
614 EditableField {
615 id: helper.id,
616 value: Expected(ExpectedInner::Expected(v)),
617 label: helper.label,
618 extensions: helper.extensions,
619 }
620 }};
621 }
622
623 let res = match helper.field_type {
624 FieldType::String => Self::String(deserialize_field!(EditableFieldString)),
625 FieldType::ConcealedString => {
626 Self::ConcealedString(deserialize_field!(EditableFieldConcealedString))
627 }
628 FieldType::Boolean => Self::Boolean(deserialize_field!(EditableFieldBoolean)),
629 FieldType::Date => Self::Date(deserialize_field!(EditableFieldDate)),
630 FieldType::YearMonth => Self::YearMonth(deserialize_field!(EditableFieldYearMonth)),
631 FieldType::WifiNetworkSecurityType => Self::WifiNetworkSecurityType(
632 deserialize_field!(EditableFieldWifiNetworkSecurityType),
633 ),
634 FieldType::SubdivisionCode => {
635 Self::SubdivisionCode(deserialize_field!(EditableFieldSubdivisionCode))
636 }
637 FieldType::CountryCode => {
638 Self::CountryCode(deserialize_field!(EditableFieldCountryCode))
639 }
640 FieldType::Email => Self::Email(deserialize_field!(EditableFieldEmail)),
641 FieldType::Number => Self::Number(deserialize_field!(EditableFieldNumber)),
642 FieldType::Unknown(_) => {
643 return Err(serde::de::Error::custom("Unknown custom field type"))
644 }
645 };
646
647 Ok(res)
648 }
649}
650
651mod serde_bool {
652 pub fn serialize<S>(value: &bool, serializer: S) -> Result<S::Ok, S::Error>
653 where
654 S: serde::Serializer,
655 {
656 serializer.serialize_str(&value.to_string())
657 }
658
659 pub fn deserialize<'de, D>(deserializer: D) -> Result<bool, D::Error>
660 where
661 D: serde::Deserializer<'de>,
662 {
663 let s = deserializer.deserialize_str(super::CowVisitor)?;
664
665 s.trim()
666 .to_lowercase()
667 .parse()
668 .map_err(serde::de::Error::custom)
669 }
670}
671
672#[cfg(test)]
673mod tests {
674 use serde_json::json;
675
676 use super::*;
677
678 #[test]
679 fn test_serialize_editable_field_string() {
680 let field: EditableField<EditableFieldString> = EditableField {
681 id: None,
682 value: EditableFieldString("value".to_string()).into(),
683 label: Some("label".to_string()),
684 extensions: None,
685 };
686 let json = json!({
687 "value": "value",
688 "fieldType": "string",
689 "label": "label",
690 });
691 assert_eq!(serde_json::to_value(&field).unwrap(), json);
692 }
693
694 #[test]
695 fn test_deserialize_field_string() {
696 let json = json!({
697 "value": "value",
698 "fieldType": "string",
699 "label": "label",
700 });
701 let field: EditableField<EditableFieldString> = serde_json::from_value(json).unwrap();
702
703 assert_eq!(
704 field,
705 EditableField {
706 id: None,
707 value: EditableFieldString("value".to_string()).into(),
708 label: Some("label".to_string()),
709 extensions: None,
710 }
711 );
712 }
713
714 #[test]
715 fn test_serialize_field_concealed_string() {
716 let field: EditableField<EditableFieldConcealedString> = EditableField {
717 id: None,
718 value: EditableFieldConcealedString("value".to_string()).into(),
719 label: Some("label".to_string()),
720 extensions: None,
721 };
722 let json = json!({
723 "fieldType": "concealed-string",
724 "value": "value",
725 "label": "label",
726 });
727 assert_eq!(serde_json::to_value(&field).unwrap(), json);
728 }
729
730 #[test]
731 fn test_deserialize_field_wrong_type() {
732 let json = json!({
733 "value": "value",
734 "fieldType": "string",
735 "label": "label",
736 });
737 let field: Result<EditableField<EditableFieldConcealedString>, _> =
738 serde_json::from_value(json);
739
740 assert!(field.unwrap().value.as_expected().is_err());
741 }
742
743 #[test]
744 fn test_deserialize_field_bad_value_string() {
745 let json = json!({
746 "value": 5,
747 "fieldType": "string",
748 "label": "label",
749 });
750 let field: Result<EditableField<EditableFieldString>, _> = serde_json::from_value(json);
751
752 assert!(field.is_err());
753 }
754
755 #[test]
756 fn test_deserialize_field_bad_value_bool() {
757 let json = json!({
758 "value": "bad",
759 "fieldType": "bool",
760 "label": "label",
761 });
762 let field: Result<EditableField<EditableFieldBoolean>, _> = serde_json::from_value(json);
763
764 assert!(field.unwrap().value.as_expected().is_err());
765 }
766
767 #[test]
768 fn test_deserialize_field_missing_type() {
769 let json = json!({
770 "value": "value",
771 "label": "label",
772 });
773 let field: Result<EditableField<EditableFieldConcealedString>, _> =
774 serde_json::from_value(json);
775
776 assert!(field.is_err());
777 }
778
779 #[test]
780 fn test_deserialize_field_concealed_string() {
781 let json = json!({
782 "value": "value",
783 "fieldType": "concealed-string",
784 "label": "label",
785 });
786 let field: EditableField<EditableFieldConcealedString> =
787 serde_json::from_value(json).unwrap();
788
789 assert_eq!(
790 field,
791 EditableField {
792 id: None,
793 value: EditableFieldConcealedString("value".to_string()).into(),
794 label: Some("label".to_string()),
795 extensions: None,
796 }
797 );
798 }
799
800 #[test]
801 fn test_serialize_field_boolean() {
802 let field: EditableField<EditableFieldBoolean> = EditableField {
803 id: None,
804 value: EditableFieldBoolean(true).into(),
805 label: Some("label".to_string()),
806 extensions: None,
807 };
808 let json = json!({
809 "fieldType": "boolean",
810 "value": "true",
811 "label": "label",
812 });
813 assert_eq!(serde_json::to_value(&field).unwrap(), json);
814 }
815
816 #[test]
817 fn test_serialize_field_date() {
818 let field: EditableField<EditableFieldDate> = EditableField {
819 id: None,
820 value: EditableFieldDate(NaiveDate::from_ymd_opt(2025, 2, 24).unwrap()).into(),
821 label: None,
822 extensions: None,
823 };
824 let json = json!({
825 "fieldType": "date",
826 "value": "2025-02-24",
827 });
828 assert_eq!(serde_json::to_value(&field).unwrap(), json);
829 }
830
831 #[test]
832 fn test_serialize_editable_field_year_month() {
833 let field: EditableField<EditableFieldYearMonth> = EditableField {
834 id: None,
835 value: EditableFieldYearMonth {
836 year: 2025,
837 month: Month::February,
838 }
839 .into(),
840 label: None,
841 extensions: None,
842 };
843 let json = json!({
844 "fieldType": "year-month",
845 "value": "2025-02",
846 });
847 assert_eq!(serde_json::to_value(&field).unwrap(), json);
848 }
849
850 #[test]
851 fn test_deserialize_editable_field_year_month() {
852 let json = json!({
853 "fieldType": "year-month",
854 "value": "2025-02",
855 });
856 let field: EditableField<EditableFieldYearMonth> = serde_json::from_value(json).unwrap();
857
858 assert_eq!(
859 field,
860 EditableField {
861 id: None,
862 value: EditableFieldYearMonth {
863 year: 2025,
864 month: Month::February,
865 }
866 .into(),
867 label: None,
868 extensions: None,
869 }
870 );
871 }
872
873 #[test]
874 fn test_deserialize_editable_field_year_month_invalid_format() {
875 let json = json!({
876 "fieldType": "year-month",
877 "value": "2025/02",
878 });
879 let field: EditableField<EditableFieldYearMonth> = serde_json::from_value(json).unwrap();
880 assert_eq!(
881 field.value.as_expected(),
882 Err(&UnexpectedField::Unknown {
883 field_type: FieldType::YearMonth,
884 value: "2025/02".into(),
885 })
886 );
887 }
888
889 #[test]
890 fn test_extension_round_trip() {
891 let json = json!({
892 "fieldType": "string",
893 "value": "hello",
894 "extensions": [
895 {
896 "name": "test",
897 "contents": "world"
898 }
899 ]
900 });
901 #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
902 #[serde(tag = "name", rename_all = "camelCase")]
903 enum CustomExtension {
904 Test { contents: String },
905 }
906
907 let field: EditableField<EditableFieldString, CustomExtension> =
908 serde_json::from_value(json.clone()).expect("Could not deserialize custom extensions");
909
910 assert_eq!(
911 field,
912 EditableField {
913 id: None,
914 value: EditableFieldString("hello".to_string()).into(),
915 label: None,
916 extensions: Some(vec![Extension::External(CustomExtension::Test {
917 contents: "world".into()
918 })])
919 }
920 );
921
922 let returned = serde_json::to_value(field).expect("Could not serialize custom extensions");
923
924 assert_eq!(returned, json);
925 }
926
927 #[test]
928 fn editable_string_deserialized_from_others() {
929 for (field_type, expected) in [
930 (
931 "concealed-string",
932 UnexpectedField::ConcealedString("hello".to_owned().into()),
933 ),
934 (
935 "unknown",
936 UnexpectedField::Unknown {
937 field_type: FieldType::Unknown("unknown".into()),
938 value: "hello".into(),
939 },
940 ),
941 (
942 "date",
943 UnexpectedField::Unknown {
944 field_type: FieldType::Date,
945 value: "hello".into(),
946 },
947 ),
948 ] {
949 let json = json!({
950 "fieldType": field_type,
951 "value": "hello",
952 });
953
954 let field: EditableField<EditableFieldString> =
955 serde_json::from_value(json.clone()).expect("Could not deserialize field");
956
957 assert_eq!(field.value.into_expected(), Err(expected));
958 }
959 }
960}