1#[cfg(test)]
5use std::collections::BTreeMap;
6
7use serde::ser::{
8 Impossible, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
9 SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer,
10};
11use time::{Month, PrimitiveDateTime, Time};
12
13use crate::date::Date;
14use crate::error::{Error, Result};
15use crate::uid::Uid;
16use crate::value::{Dictionary, Integer, Real, Value};
17
18pub(crate) const DATE_NEWTYPE: &str = "$__plist_private_Date";
21
22pub(crate) const UID_NEWTYPE: &str = "$__plist_private_Uid";
25
26const NANOS_PER_SECOND: i128 = 1_000_000_000;
27
28pub fn to_value<T>(value: &T) -> Result<Value>
57where
58 T: Serialize + ?Sized,
59{
60 match value.serialize(ValueSerializer) {
61 Err(Error::NullNotRepresentable) => Err(Error::NoRootElement),
62 result => result,
63 }
64}
65
66pub(crate) fn format_sentinel_date(date: Date) -> String {
70 let mut formatted = date.format_rfc3339();
71 let (_, nanos) = date.unix_parts();
72 if nanos != 0 && formatted.ends_with('Z') {
73 formatted.truncate(formatted.len() - 1);
74 let fraction = format!("{nanos:09}");
75 formatted.push('.');
76 formatted.push_str(fraction.trim_end_matches('0'));
77 formatted.push('Z');
78 }
79 formatted
80}
81
82pub(crate) fn parse_sentinel_date(payload: &str) -> Option<Date> {
86 payload
87 .strip_prefix('-')
88 .map_or_else(|| Date::parse_rfc3339(payload), parse_negative_year_date)
89}
90
91pub(crate) const fn narrow_f32(real: Real) -> f32 {
94 #[expect(
95 clippy::cast_possible_truncation,
96 reason = "narrow reals are constructed from f32, so the round-trip is exact"
97 )]
98 let narrow = real.value() as f32;
99 narrow
100}
101
102fn ascii_number(bytes: &[u8]) -> Option<u32> {
103 bytes.iter().try_fold(0_u32, |acc, &byte| {
104 byte.is_ascii_digit()
105 .then(|| acc * 10 + u32::from(byte - b'0'))
106 })
107}
108
109fn byte_at(bytes: &[u8], index: usize, expected: u8) -> Option<()> {
110 (bytes.get(index) == Some(&expected)).then_some(())
111}
112
113fn parse_negative_year_date(rest: &str) -> Option<Date> {
116 let bytes = rest.as_bytes();
117 let year = ascii_number(bytes.get(0..4)?)?;
118 byte_at(bytes, 4, b'-')?;
119 let month = ascii_number(bytes.get(5..7)?)?;
120 byte_at(bytes, 7, b'-')?;
121 let day = ascii_number(bytes.get(8..10)?)?;
122 byte_at(bytes, 10, b'T')?;
123 let hour = ascii_number(bytes.get(11..13)?)?;
124 byte_at(bytes, 13, b':')?;
125 let minute = ascii_number(bytes.get(14..16)?)?;
126 byte_at(bytes, 16, b':')?;
127 let second = ascii_number(bytes.get(17..19)?)?;
128 let nanos = match bytes.get(19) {
129 Some(b'Z') if bytes.len() == 20 => 0,
130 Some(b'.') if bytes.last() == Some(&b'Z') => {
131 let fraction = bytes.get(20..bytes.len() - 1)?;
132 if fraction.is_empty() || fraction.len() > 9 {
133 return None;
134 }
135 let mut value = ascii_number(fraction)?;
136 for _ in fraction.len()..9 {
137 value *= 10;
138 }
139 value
140 }
141 _ => return None,
142 };
143
144 let calendar = time::Date::from_calendar_date(
145 -i32::try_from(year).ok()?,
146 Month::try_from(u8::try_from(month).ok()?).ok()?,
147 u8::try_from(day).ok()?,
148 )
149 .ok()?;
150 let clock = Time::from_hms_nano(
151 u8::try_from(hour).ok()?,
152 u8::try_from(minute).ok()?,
153 u8::try_from(second).ok()?,
154 nanos,
155 )
156 .ok()?;
157 let unix_nanos = PrimitiveDateTime::new(calendar, clock)
158 .assume_utc()
159 .unix_timestamp_nanos();
160 Some(Date::from_unix(
161 i64::try_from(unix_nanos.div_euclid(NANOS_PER_SECOND)).ok()?,
162 i64::try_from(unix_nanos.rem_euclid(NANOS_PER_SECOND)).ok()?,
163 ))
164}
165
166fn uid_payload_error() -> Error {
167 Error::Message("uid sentinel payload must be an unsigned integer".to_owned())
168}
169
170fn date_payload_error() -> Error {
171 Error::Message("date sentinel payload must be an rfc 3339 string".to_owned())
172}
173
174pub(crate) struct ValueSerializer;
177
178macro_rules! serialize_integer {
179 ($($method:ident: $ty:ty,)*) => {$(
180 fn $method(self, value: $ty) -> Result<Value> {
181 Ok(Value::Integer(Integer::from(value)))
182 }
183 )*};
184}
185
186impl Serializer for ValueSerializer {
187 type Ok = Value;
188 type Error = Error;
189 type SerializeSeq = SeqBuilder;
190 type SerializeTuple = SeqBuilder;
191 type SerializeTupleStruct = SeqBuilder;
192 type SerializeTupleVariant = VariantSeqBuilder;
193 type SerializeMap = MapBuilder;
194 type SerializeStruct = MapBuilder;
195 type SerializeStructVariant = VariantMapBuilder;
196
197 serialize_integer! {
198 serialize_i8: i8,
199 serialize_i16: i16,
200 serialize_i32: i32,
201 serialize_i64: i64,
202 serialize_u8: u8,
203 serialize_u16: u16,
204 serialize_u32: u32,
205 serialize_u64: u64,
206 }
207
208 fn serialize_bool(self, value: bool) -> Result<Value> {
209 Ok(Value::Boolean(value))
210 }
211
212 fn serialize_i128(self, value: i128) -> Result<Value> {
213 i64::try_from(value)
214 .map(Value::from)
215 .or_else(|_| u64::try_from(value).map(Value::from))
216 .map_err(|_| Error::UnknownType("i128"))
217 }
218
219 fn serialize_u128(self, value: u128) -> Result<Value> {
220 u64::try_from(value)
221 .map(Value::from)
222 .map_err(|_| Error::UnknownType("u128"))
223 }
224
225 fn serialize_f32(self, value: f32) -> Result<Value> {
226 Ok(Value::Real(Real::from(value)))
227 }
228
229 fn serialize_f64(self, value: f64) -> Result<Value> {
230 Ok(Value::Real(Real::from(value)))
231 }
232
233 fn serialize_char(self, value: char) -> Result<Value> {
234 Ok(Value::String(value.to_string()))
235 }
236
237 fn serialize_str(self, value: &str) -> Result<Value> {
238 Ok(Value::String(value.to_owned()))
239 }
240
241 fn serialize_bytes(self, value: &[u8]) -> Result<Value> {
242 Ok(Value::Data(value.to_vec()))
243 }
244
245 fn serialize_none(self) -> Result<Value> {
246 Err(Error::NullNotRepresentable)
247 }
248
249 fn serialize_some<T>(self, value: &T) -> Result<Value>
250 where
251 T: Serialize + ?Sized,
252 {
253 value.serialize(self)
254 }
255
256 fn serialize_unit(self) -> Result<Value> {
257 Err(Error::NullNotRepresentable)
258 }
259
260 fn serialize_unit_struct(self, _name: &'static str) -> Result<Value> {
261 Err(Error::NullNotRepresentable)
262 }
263
264 fn serialize_unit_variant(
265 self,
266 _name: &'static str,
267 _variant_index: u32,
268 variant: &'static str,
269 ) -> Result<Value> {
270 Ok(Value::String(variant.to_owned()))
271 }
272
273 fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Value>
274 where
275 T: Serialize + ?Sized,
276 {
277 match name {
278 UID_NEWTYPE => {
279 if let Value::Integer(integer) = value.serialize(Self)?
280 && let Some(uid) = integer.as_unsigned()
281 {
282 Ok(Value::Uid(Uid::from(uid)))
283 } else {
284 Err(uid_payload_error())
285 }
286 }
287 DATE_NEWTYPE => {
288 if let Value::String(payload) = value.serialize(Self)?
289 && let Some(date) = parse_sentinel_date(&payload)
290 {
291 Ok(Value::Date(date))
292 } else {
293 Err(date_payload_error())
294 }
295 }
296 _ => value.serialize(self),
297 }
298 }
299
300 fn serialize_newtype_variant<T>(
301 self,
302 _name: &'static str,
303 _variant_index: u32,
304 variant: &'static str,
305 value: &T,
306 ) -> Result<Value>
307 where
308 T: Serialize + ?Sized,
309 {
310 let inner = value.serialize(Self)?;
311 Ok(Value::Dictionary(Dictionary::from([(
312 variant.to_owned(),
313 inner,
314 )])))
315 }
316
317 fn serialize_seq(self, _len: Option<usize>) -> Result<SeqBuilder> {
318 Ok(SeqBuilder::default())
319 }
320
321 fn serialize_tuple(self, _len: usize) -> Result<SeqBuilder> {
322 Ok(SeqBuilder::default())
323 }
324
325 fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<SeqBuilder> {
326 Ok(SeqBuilder::default())
327 }
328
329 fn serialize_tuple_variant(
330 self,
331 _name: &'static str,
332 _variant_index: u32,
333 variant: &'static str,
334 _len: usize,
335 ) -> Result<VariantSeqBuilder> {
336 Ok(VariantSeqBuilder {
337 variant,
338 elements: SeqBuilder::default(),
339 })
340 }
341
342 fn serialize_map(self, _len: Option<usize>) -> Result<MapBuilder> {
343 Ok(MapBuilder::default())
344 }
345
346 fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<MapBuilder> {
347 Ok(MapBuilder::default())
348 }
349
350 fn serialize_struct_variant(
351 self,
352 _name: &'static str,
353 _variant_index: u32,
354 variant: &'static str,
355 _len: usize,
356 ) -> Result<VariantMapBuilder> {
357 Ok(VariantMapBuilder {
358 variant,
359 entries: MapBuilder::default(),
360 })
361 }
362
363 fn is_human_readable(&self) -> bool {
364 true
365 }
366}
367
368#[derive(Default)]
371pub(crate) struct SeqBuilder {
372 elements: Vec<Value>,
373}
374
375impl SeqBuilder {
376 fn push<T>(&mut self, value: &T) -> Result<()>
377 where
378 T: Serialize + ?Sized,
379 {
380 match value.serialize(ValueSerializer) {
381 Ok(element) => {
382 self.elements.push(element);
383 Ok(())
384 }
385 Err(Error::NullNotRepresentable) => Ok(()),
386 Err(error) => Err(error),
387 }
388 }
389}
390
391impl SerializeSeq for SeqBuilder {
392 type Ok = Value;
393 type Error = Error;
394
395 fn serialize_element<T>(&mut self, value: &T) -> Result<()>
396 where
397 T: Serialize + ?Sized,
398 {
399 self.push(value)
400 }
401
402 fn end(self) -> Result<Value> {
403 Ok(Value::Array(self.elements))
404 }
405}
406
407impl SerializeTuple for SeqBuilder {
408 type Ok = Value;
409 type Error = Error;
410
411 fn serialize_element<T>(&mut self, value: &T) -> Result<()>
412 where
413 T: Serialize + ?Sized,
414 {
415 self.push(value)
416 }
417
418 fn end(self) -> Result<Value> {
419 Ok(Value::Array(self.elements))
420 }
421}
422
423impl SerializeTupleStruct for SeqBuilder {
424 type Ok = Value;
425 type Error = Error;
426
427 fn serialize_field<T>(&mut self, value: &T) -> Result<()>
428 where
429 T: Serialize + ?Sized,
430 {
431 self.push(value)
432 }
433
434 fn end(self) -> Result<Value> {
435 Ok(Value::Array(self.elements))
436 }
437}
438
439pub(crate) struct VariantSeqBuilder {
442 variant: &'static str,
443 elements: SeqBuilder,
444}
445
446impl SerializeTupleVariant for VariantSeqBuilder {
447 type Ok = Value;
448 type Error = Error;
449
450 fn serialize_field<T>(&mut self, value: &T) -> Result<()>
451 where
452 T: Serialize + ?Sized,
453 {
454 self.elements.push(value)
455 }
456
457 fn end(self) -> Result<Value> {
458 Ok(Value::Dictionary(Dictionary::from([(
459 self.variant.to_owned(),
460 Value::Array(self.elements.elements),
461 )])))
462 }
463}
464
465#[derive(Default)]
469pub(crate) struct MapBuilder {
470 entries: Dictionary,
471 pending_key: Option<String>,
472}
473
474impl MapBuilder {
475 fn insert_pending<T>(&mut self, value: &T) -> Result<()>
476 where
477 T: Serialize + ?Sized,
478 {
479 let key = self
480 .pending_key
481 .take()
482 .ok_or_else(|| Error::Message("map value serialized before its key".to_owned()))?;
483 match value.serialize(ValueSerializer) {
484 Ok(entry) => {
485 drop(self.entries.insert(key, entry));
486 Ok(())
487 }
488 Err(Error::NullNotRepresentable) => Ok(()),
489 Err(error) => Err(error),
490 }
491 }
492}
493
494impl SerializeMap for MapBuilder {
495 type Ok = Value;
496 type Error = Error;
497
498 fn serialize_key<T>(&mut self, key: &T) -> Result<()>
499 where
500 T: Serialize + ?Sized,
501 {
502 self.pending_key = Some(key.serialize(MapKeySerializer)?);
503 Ok(())
504 }
505
506 fn serialize_value<T>(&mut self, value: &T) -> Result<()>
507 where
508 T: Serialize + ?Sized,
509 {
510 self.insert_pending(value)
511 }
512
513 fn end(self) -> Result<Value> {
514 Ok(Value::Dictionary(self.entries))
515 }
516}
517
518impl SerializeStruct for MapBuilder {
519 type Ok = Value;
520 type Error = Error;
521
522 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
523 where
524 T: Serialize + ?Sized,
525 {
526 self.pending_key = Some(key.to_owned());
527 self.insert_pending(value)
528 }
529
530 fn end(self) -> Result<Value> {
531 Ok(Value::Dictionary(self.entries))
532 }
533}
534
535pub(crate) struct VariantMapBuilder {
538 variant: &'static str,
539 entries: MapBuilder,
540}
541
542impl SerializeStructVariant for VariantMapBuilder {
543 type Ok = Value;
544 type Error = Error;
545
546 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
547 where
548 T: Serialize + ?Sized,
549 {
550 self.entries.pending_key = Some(key.to_owned());
551 self.entries.insert_pending(value)
552 }
553
554 fn end(self) -> Result<Value> {
555 Ok(Value::Dictionary(Dictionary::from([(
556 self.variant.to_owned(),
557 Value::Dictionary(self.entries.entries),
558 )])))
559 }
560}
561
562pub(crate) struct MapKeySerializer;
565
566macro_rules! reject_key {
567 ($($method:ident($($arg:ty),*) -> $label:literal,)*) => {$(
568 fn $method(self, $(_: $arg),*) -> Result<String> {
569 Err(Error::UnknownType($label))
570 }
571 )*};
572}
573
574impl Serializer for MapKeySerializer {
575 type Ok = String;
576 type Error = Error;
577 type SerializeSeq = Impossible<String, Error>;
578 type SerializeTuple = Impossible<String, Error>;
579 type SerializeTupleStruct = Impossible<String, Error>;
580 type SerializeTupleVariant = Impossible<String, Error>;
581 type SerializeMap = Impossible<String, Error>;
582 type SerializeStruct = Impossible<String, Error>;
583 type SerializeStructVariant = Impossible<String, Error>;
584
585 reject_key! {
586 serialize_bool(bool) -> "boolean map key",
587 serialize_i8(i8) -> "integer map key",
588 serialize_i16(i16) -> "integer map key",
589 serialize_i32(i32) -> "integer map key",
590 serialize_i64(i64) -> "integer map key",
591 serialize_i128(i128) -> "integer map key",
592 serialize_u8(u8) -> "integer map key",
593 serialize_u16(u16) -> "integer map key",
594 serialize_u32(u32) -> "integer map key",
595 serialize_u64(u64) -> "integer map key",
596 serialize_u128(u128) -> "integer map key",
597 serialize_f32(f32) -> "real map key",
598 serialize_f64(f64) -> "real map key",
599 serialize_char(char) -> "char map key",
600 serialize_bytes(&[u8]) -> "data map key",
601 serialize_none() -> "optional map key",
602 serialize_unit() -> "unit map key",
603 serialize_unit_struct(&'static str) -> "unit map key",
604 }
605
606 fn serialize_str(self, value: &str) -> Result<String> {
607 Ok(value.to_owned())
608 }
609
610 fn serialize_some<T>(self, _value: &T) -> Result<String>
611 where
612 T: Serialize + ?Sized,
613 {
614 Err(Error::UnknownType("optional map key"))
615 }
616
617 fn serialize_unit_variant(
618 self,
619 _name: &'static str,
620 _variant_index: u32,
621 variant: &'static str,
622 ) -> Result<String> {
623 Ok(variant.to_owned())
624 }
625
626 fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<String>
627 where
628 T: Serialize + ?Sized,
629 {
630 match name {
631 UID_NEWTYPE => Err(Error::UnknownType("UID map key")),
632 DATE_NEWTYPE => Err(Error::UnknownType("date map key")),
633 _ => value.serialize(self),
634 }
635 }
636
637 fn serialize_newtype_variant<T>(
638 self,
639 _name: &'static str,
640 _variant_index: u32,
641 _variant: &'static str,
642 _value: &T,
643 ) -> Result<String>
644 where
645 T: Serialize + ?Sized,
646 {
647 Err(Error::UnknownType("enum map key"))
648 }
649
650 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
651 Err(Error::UnknownType("array map key"))
652 }
653
654 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
655 Err(Error::UnknownType("array map key"))
656 }
657
658 fn serialize_tuple_struct(
659 self,
660 _name: &'static str,
661 _len: usize,
662 ) -> Result<Self::SerializeTupleStruct> {
663 Err(Error::UnknownType("array map key"))
664 }
665
666 fn serialize_tuple_variant(
667 self,
668 _name: &'static str,
669 _variant_index: u32,
670 _variant: &'static str,
671 _len: usize,
672 ) -> Result<Self::SerializeTupleVariant> {
673 Err(Error::UnknownType("enum map key"))
674 }
675
676 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
677 Err(Error::UnknownType("dictionary map key"))
678 }
679
680 fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
681 Err(Error::UnknownType("dictionary map key"))
682 }
683
684 fn serialize_struct_variant(
685 self,
686 _name: &'static str,
687 _variant_index: u32,
688 _variant: &'static str,
689 _len: usize,
690 ) -> Result<Self::SerializeStructVariant> {
691 Err(Error::UnknownType("enum map key"))
692 }
693
694 fn is_human_readable(&self) -> bool {
695 true
696 }
697}
698
699impl Serialize for Value {
700 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
701 where
702 S: Serializer,
703 {
704 match self {
705 Self::Dictionary(dict) => serializer.collect_map(dict),
706 Self::Array(values) => serializer.collect_seq(values),
707 Self::String(s) => serializer.serialize_str(s),
708 Self::Integer(integer) => integer.serialize(serializer),
709 Self::Real(real) => real.serialize(serializer),
710 Self::Boolean(b) => serializer.serialize_bool(*b),
711 Self::Uid(uid) => uid.serialize(serializer),
712 Self::Data(data) => serializer.serialize_bytes(data),
713 Self::Date(date) => date.serialize(serializer),
714 }
715 }
716}
717
718impl Serialize for Integer {
719 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
720 where
721 S: Serializer,
722 {
723 match *self {
724 Self::Signed(value) => serializer.serialize_i64(value),
725 Self::Unsigned(value) => serializer.serialize_u64(value),
726 }
727 }
728}
729
730impl Serialize for Real {
731 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
732 where
733 S: Serializer,
734 {
735 if self.wide() {
736 serializer.serialize_f64(self.value())
737 } else {
738 serializer.serialize_f32(narrow_f32(*self))
739 }
740 }
741}
742
743impl Serialize for Uid {
744 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
745 where
746 S: Serializer,
747 {
748 serializer.serialize_newtype_struct(UID_NEWTYPE, &self.get())
749 }
750}
751
752impl Serialize for Date {
753 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
754 where
755 S: Serializer,
756 {
757 serializer.serialize_newtype_struct(DATE_NEWTYPE, &format_sentinel_date(*self))
758 }
759}
760
761#[cfg(test)]
762mod tests {
763 #![expect(
764 clippy::unwrap_used,
765 clippy::panic,
766 reason = "test code: unwrap/panic are the assertions"
767 )]
768
769 use serde::Serialize;
770
771 use super::*;
772
773 fn dict<const N: usize>(entries: [(&str, Value); N]) -> Value {
774 entries
775 .into_iter()
776 .map(|(key, value)| (key.to_owned(), value))
777 .collect()
778 }
779
780 fn rfc(s: &str) -> Date {
781 Date::parse_rfc3339(s).unwrap()
782 }
783
784 fn real_of(value: &Value) -> Real {
785 match value {
786 Value::Real(real) => *real,
787 other => panic!("expected a real, got {other:?}"),
788 }
789 }
790
791 #[test]
792 fn scalar_roots_map_to_their_variants() {
793 assert_eq!(to_value(&true).unwrap(), Value::Boolean(true));
794 assert_eq!(to_value("x").unwrap(), Value::from("x"));
795 assert!(matches!(
796 to_value(&-1i8).unwrap(),
797 Value::Integer(Integer::Signed(-1))
798 ));
799 assert!(matches!(
800 to_value(&u64::MAX).unwrap(),
801 Value::Integer(Integer::Unsigned(u64::MAX))
802 ));
803 assert_eq!(to_value(&1.5f64).unwrap(), Value::from(1.5));
804 assert_eq!(to_value(&[1u8, 2]).unwrap().type_name(), "array");
805 }
806
807 #[test]
808 fn all_integer_widths_widen_to_their_signedness() {
809 for value in [
810 to_value(&5i8).unwrap(),
811 to_value(&5i16).unwrap(),
812 to_value(&5i32).unwrap(),
813 to_value(&5i64).unwrap(),
814 ] {
815 assert!(matches!(value, Value::Integer(Integer::Signed(5))));
816 }
817 for value in [
818 to_value(&5u8).unwrap(),
819 to_value(&5u16).unwrap(),
820 to_value(&5u32).unwrap(),
821 to_value(&5u64).unwrap(),
822 ] {
823 assert!(matches!(value, Value::Integer(Integer::Unsigned(5))));
824 }
825 }
826
827 #[test]
828 fn real_width_follows_the_serialize_call() {
829 let narrow = to_value(&1.5f32).unwrap();
830 assert!(!real_of(&narrow).wide());
831 assert_eq!(narrow, Value::from(1.5));
832
833 let wide = to_value(&1.5f64).unwrap();
834 assert!(real_of(&wide).wide());
835 }
836
837 #[test]
838 fn char_serializes_as_a_one_char_string() {
839 assert_eq!(to_value(&'a').unwrap(), Value::from("a"));
840 assert_eq!(to_value(&'£').unwrap(), Value::from("£"));
841 }
842
843 #[test]
844 fn int128_fits_or_errors() {
845 assert!(matches!(
846 to_value(&5i128).unwrap(),
847 Value::Integer(Integer::Signed(5))
848 ));
849 assert!(matches!(
850 to_value(&-5i128).unwrap(),
851 Value::Integer(Integer::Signed(-5))
852 ));
853 assert!(matches!(
854 to_value(&i128::from(u64::MAX)).unwrap(),
855 Value::Integer(Integer::Unsigned(u64::MAX))
856 ));
857 assert!(matches!(
858 to_value(&7u128).unwrap(),
859 Value::Integer(Integer::Unsigned(7))
860 ));
861 assert!(matches!(
862 to_value(&i128::MAX),
863 Err(Error::UnknownType("i128"))
864 ));
865 assert!(matches!(
866 to_value(&i128::MIN),
867 Err(Error::UnknownType("i128"))
868 ));
869 assert!(matches!(
870 to_value(&u128::MAX),
871 Err(Error::UnknownType("u128"))
872 ));
873 }
874
875 #[test]
876 fn null_roots_error_with_no_root_element() {
877 #[derive(Serialize)]
878 struct Unit;
879
880 assert!(matches!(to_value(&None::<i32>), Err(Error::NoRootElement)));
881 assert!(matches!(to_value(&()), Err(Error::NoRootElement)));
882 assert!(matches!(to_value(&Unit), Err(Error::NoRootElement)));
883 }
884
885 #[test]
886 fn containers_drop_null_elements_and_entries() {
887 #[derive(Serialize)]
888 struct WithOption {
889 present: u8,
890 absent: Option<u8>,
891 }
892
893 let array = to_value(&vec![Some(1u8), None, Some(2u8)]).unwrap();
894 assert_eq!(array, Value::from(vec![Value::from(1u8), Value::from(2u8)]));
895
896 let value = to_value(&WithOption {
897 present: 1,
898 absent: None,
899 })
900 .unwrap();
901 assert_eq!(value, dict([("present", Value::from(1u8))]));
902
903 let mut map = BTreeMap::new();
904 assert!(map.insert("gone".to_owned(), None::<u8>).is_none());
905 assert!(map.insert("kept".to_owned(), Some(3u8)).is_none());
906 assert_eq!(to_value(&map).unwrap(), dict([("kept", Value::from(3u8))]));
907 }
908
909 #[test]
910 fn null_variant_payloads_cascade_to_the_enclosing_container() {
911 #[derive(Serialize)]
912 enum Holder {
913 Inner(Option<i32>),
914 }
915 #[derive(Serialize)]
916 struct Outer {
917 field: Option<Holder>,
918 }
919
920 let dropped = to_value(&Outer {
921 field: Some(Holder::Inner(None)),
922 })
923 .unwrap();
924 assert_eq!(dropped, dict([]));
925
926 assert!(matches!(
927 to_value(&Holder::Inner(None)),
928 Err(Error::NoRootElement)
929 ));
930 }
931
932 #[test]
933 fn map_keys_must_be_string_kinded() {
934 #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord)]
935 struct NewtypeKey(String);
936 #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord)]
937 enum VariantKey {
938 A,
939 }
940
941 let int_keys = BTreeMap::from([(1i32, "hi")]);
942 assert!(matches!(
943 to_value(&int_keys),
944 Err(Error::UnknownType("integer map key"))
945 ));
946
947 let bool_keys = BTreeMap::from([(true, 1u8)]);
948 assert!(matches!(
949 to_value(&bool_keys),
950 Err(Error::UnknownType("boolean map key"))
951 ));
952
953 let char_keys = BTreeMap::from([('a', 1u8)]);
954 assert!(matches!(
955 to_value(&char_keys),
956 Err(Error::UnknownType("char map key"))
957 ));
958
959 let string_keys = BTreeMap::from([("k".to_owned(), 1u8)]);
960 assert_eq!(
961 to_value(&string_keys).unwrap(),
962 dict([("k", Value::from(1u8))])
963 );
964
965 let newtype_keys = BTreeMap::from([(NewtypeKey("n".to_owned()), 1u8)]);
966 assert_eq!(
967 to_value(&newtype_keys).unwrap(),
968 dict([("n", Value::from(1u8))])
969 );
970
971 let variant_keys = BTreeMap::from([(VariantKey::A, 1u8)]);
972 assert_eq!(
973 to_value(&variant_keys).unwrap(),
974 dict([("A", Value::from(1u8))])
975 );
976 }
977
978 #[test]
979 fn enums_are_externally_tagged() {
980 #[derive(Serialize)]
981 enum Repr {
982 Unit,
983 New(u8),
984 Tuple(u8, u8),
985 Struct { f: bool },
986 }
987
988 assert_eq!(to_value(&Repr::Unit).unwrap(), Value::from("Unit"));
989 assert_eq!(
990 to_value(&Repr::New(1)).unwrap(),
991 dict([("New", Value::from(1u8))])
992 );
993 assert_eq!(
994 to_value(&Repr::Tuple(1, 2)).unwrap(),
995 dict([(
996 "Tuple",
997 Value::from(vec![Value::from(1u8), Value::from(2u8)])
998 )])
999 );
1000 assert_eq!(
1001 to_value(&Repr::Struct { f: true }).unwrap(),
1002 dict([("Struct", dict([("f", Value::from(true))]))])
1003 );
1004 }
1005
1006 #[test]
1007 fn byte_vectors_under_derive_are_arrays_not_data() {
1008 #[derive(Serialize)]
1009 struct Bytes {
1010 raw: Vec<u8>,
1011 }
1012 let value = to_value(&Bytes { raw: vec![1, 2] }).unwrap();
1013 assert_eq!(
1014 value,
1015 dict([("raw", Value::from(vec![Value::from(1u8), Value::from(2u8)]))])
1016 );
1017
1018 assert_eq!(
1020 to_value(&Value::Data(vec![1, 2])).unwrap(),
1021 Value::Data(vec![1, 2])
1022 );
1023 }
1024
1025 #[test]
1026 fn flatten_collisions_resolve_last_writer_wins() {
1027 #[derive(Serialize)]
1028 struct Outer {
1029 a: u8,
1030 #[serde(flatten)]
1031 rest: BTreeMap<String, u8>,
1032 }
1033
1034 let outer = Outer {
1035 a: 1,
1036 rest: BTreeMap::from([("a".to_owned(), 9u8)]),
1037 };
1038 assert_eq!(to_value(&outer).unwrap(), dict([("a", Value::from(9u8))]));
1039 }
1040
1041 #[test]
1042 fn uid_and_date_serialize_to_their_variants() {
1043 assert_eq!(
1044 to_value(&Uid::from(1024)).unwrap(),
1045 Value::Uid(Uid::from(1024))
1046 );
1047 assert_eq!(
1048 to_value(&Uid::from(u64::MAX)).unwrap(),
1049 Value::Uid(Uid::from(u64::MAX))
1050 );
1051
1052 let date = rfc("2013-11-27T00:34:00Z");
1053 assert_eq!(to_value(&date).unwrap(), Value::Date(date));
1054
1055 let fractional = rfc("2013-11-27T00:34:00.123456789Z");
1056 assert_eq!(to_value(&fractional).unwrap(), Value::Date(fractional));
1057
1058 let ancient = Date::from_apple_epoch(-1e300);
1059 assert_eq!(to_value(&ancient).unwrap(), Value::Date(ancient));
1060 }
1061
1062 #[test]
1063 fn value_trees_round_trip_structurally() {
1064 let tree = dict([
1065 (
1066 "array",
1067 Value::from(vec![Value::from(-1i64), Value::from(2u8)]),
1068 ),
1069 ("bool", Value::from(true)),
1070 ("data", Value::Data(vec![0xDE, 0xAD])),
1071 ("date", Value::Date(rfc("2013-11-27T00:34:00.5Z"))),
1072 ("narrow", Value::Real(Real::from(32.5f32))),
1073 ("nested", dict([("uid", Value::Uid(Uid::from(7)))])),
1074 ("string", Value::from("s")),
1075 ("unsigned", Value::from(u64::MAX)),
1076 ("wide", Value::from(1.5)),
1077 ]);
1078 let round_tripped = to_value(&tree).unwrap();
1079 assert_eq!(round_tripped, tree);
1080
1081 let narrow = round_tripped
1082 .as_dictionary()
1083 .and_then(|d| d.get("narrow"))
1084 .unwrap();
1085 assert!(!real_of(narrow).wide());
1086 let wide = round_tripped
1087 .as_dictionary()
1088 .and_then(|d| d.get("wide"))
1089 .unwrap();
1090 assert!(real_of(wide).wide());
1091 }
1092
1093 #[test]
1094 fn sentinel_payload_misuse_errors() {
1095 let serializer = ValueSerializer;
1096 assert!(matches!(
1097 serializer.serialize_newtype_struct(UID_NEWTYPE, "nope"),
1098 Err(Error::Message(_))
1099 ));
1100 assert!(matches!(
1101 ValueSerializer.serialize_newtype_struct(UID_NEWTYPE, &-1i32),
1102 Err(Error::Message(_))
1103 ));
1104 assert!(matches!(
1105 ValueSerializer.serialize_newtype_struct(DATE_NEWTYPE, &5u8),
1106 Err(Error::Message(_))
1107 ));
1108 assert!(matches!(
1109 ValueSerializer.serialize_newtype_struct(DATE_NEWTYPE, "not a date"),
1110 Err(Error::Message(_))
1111 ));
1112 }
1113
1114 #[test]
1115 fn sentinel_date_format_is_lossless_rfc3339() {
1116 assert_eq!(
1117 format_sentinel_date(rfc("2013-11-27T00:34:00Z")),
1118 "2013-11-27T00:34:00Z"
1119 );
1120 assert_eq!(
1121 format_sentinel_date(rfc("2013-11-27T00:34:00.5Z")),
1122 "2013-11-27T00:34:00.5Z"
1123 );
1124 assert_eq!(
1125 format_sentinel_date(rfc("2013-11-27T00:34:00.000000001Z")),
1126 "2013-11-27T00:34:00.000000001Z"
1127 );
1128
1129 for date in [
1130 rfc("2013-11-27T00:34:00Z"),
1131 rfc("2013-11-27T00:34:00.123456789Z"),
1132 rfc("0001-01-01T00:00:00Z"),
1133 Date::from_apple_epoch(-1e300),
1134 Date::from_apple_epoch(1e300),
1135 Date::from_unix(-1, 500_000_000),
1136 ] {
1137 assert_eq!(parse_sentinel_date(&format_sentinel_date(date)), Some(date));
1138 }
1139 }
1140
1141 #[test]
1142 fn sentinel_date_parse_rejects_malformed_negative_years() {
1143 for payload in [
1144 "-",
1145 "-2013-11-27T00:34:00",
1146 "-2013-11-27T00:34:00z",
1147 "-13-11-27T00:34:00Z",
1148 "-2013-13-27T00:34:00Z",
1149 "-2013-11-27T00:34:00.Z",
1150 "-2013-11-27T00:34:00.1234567890Z",
1151 "-2013-11-27T00:34:00Z ",
1152 ] {
1153 assert!(parse_sentinel_date(payload).is_none(), "{payload}");
1154 }
1155 }
1156}