merde/
lib.rs

1#![deny(missing_docs)]
2#![deny(rustdoc::broken_intra_doc_links)]
3#![doc = include_str!("../README.md")]
4
5#[cfg(feature = "json")]
6pub use merde_json as json;
7
8#[cfg(feature = "yaml")]
9pub use merde_yaml as yaml;
10
11#[cfg(feature = "core")]
12pub use merde_core::*;
13
14#[doc(hidden)]
15#[cfg(feature = "deserialize")]
16#[macro_export]
17macro_rules! impl_deserialize {
18    // owned tuple struct (transparent)
19    (struct $struct_name:ident transparent) => {
20        #[automatically_derived]
21        impl<'s> $crate::Deserialize<'s> for $struct_name {
22            #[inline(always)]
23            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<'s>) -> Result<Self, $crate::MerdeError<'s>> {
24                use $crate::DynDeserializerExt;
25
26                Ok(Self($crate::DynDeserializerExt::t(__de).await?))
27            }
28        }
29    };
30
31    // lifetimed tuple struct (transparent)
32    (struct $struct_name:ident <$s:lifetime> transparent) => {
33        #[automatically_derived]
34        impl<$s> $crate::Deserialize<$s> for $struct_name<$s> {
35            #[inline(always)]
36            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<'s>) -> Result<Self, $crate::MerdeError<'s>> {
37                Ok(Self($crate::DynDeserializerExt::t(__de).await?))
38            }
39        }
40    };
41
42    // owned struct
43    (struct $struct_name:ident { $($field:ident),* }) => {
44        $crate::impl_deserialize! {
45            struct $struct_name { $($field),* } via $crate::DefaultDeserOpinions
46        }
47    };
48    (struct $struct_name:ident { $($field:ident),* } via $opinions:expr) => {
49        #[automatically_derived]
50        impl<'s> $crate::Deserialize<'s> for $struct_name {
51            #[inline(always)]
52            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<'s>) -> Result<Self, $crate::MerdeError<'s>> {
53                #![allow(unreachable_code)]
54                use $crate::{DynDeserializerExt, DeserOpinions};
55
56                let __opinions = $opinions;
57                __de.next().await?.into_map_start()?;
58
59                $(
60                    let mut $field = $crate::none_of(|i: $struct_name| i.$field);
61                )*
62
63                loop {
64                    match __de.next().await? {
65                        $crate::Event::MapEnd => break,
66                        $crate::Event::Str(__key) => {
67                            let __key = __opinions.map_key_name(__key);
68                            match __key.as_ref() {
69                                $(stringify!($field) => {
70                                    $field = Some($crate::DynDeserializerExt::t(__de).await?);
71                                })*
72                                _ => {
73                                    if __opinions.deny_unknown_fields() {
74                                        return Err($crate::MerdeError::UnknownProperty(__key).into());
75                                    }
76                                }
77                            }
78                        }
79                        ev => {
80                            return Err($crate::MerdeError::UnexpectedEvent {
81                                got: $crate::EventType::from(&ev),
82                                expected: &[$crate::EventType::Str, $crate::EventType::MapEnd],
83                                help: Some(format!("While deserializing {}", stringify!($struct_name))),
84                            }
85                            .into())
86                        }
87                    }
88                }
89
90                Ok($struct_name {
91                    $($field: {
92                        if $field.is_none() {
93                            let __slot = $crate::FieldSlot::new(&mut $field);
94                            __opinions.default_field_value(stringify!($field), __slot);
95                        }
96                        $crate::Deserialize::from_option($field, stringify!($field).into())?
97                    },)*
98                })
99            }
100        }
101    };
102
103    // lifetimed struct
104    (struct $struct_name:ident <$lifetime:lifetime> { $($field:ident),* }) => {
105        $crate::impl_deserialize! {
106            struct $struct_name <$lifetime> { $($field),* } via $crate::DefaultDeserOpinions
107        }
108    };
109    (struct $struct_name:ident <$s:lifetime> { $($field:ident),* } via $opinions:expr) => {
110        #[automatically_derived]
111        impl<$s> $crate::Deserialize<$s> for $struct_name<$s> {
112            #[inline(always)]
113            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<$s>) -> Result<Self, $crate::MerdeError<$s>> {
114                #![allow(unreachable_code)]
115                use $crate::DeserOpinions;
116
117                let __opinions = $opinions;
118                __de.next().await?.into_map_start()?;
119
120                $(
121                    let mut $field = $crate::none_of(|i: $struct_name<$s>| i.$field);
122                )+
123
124                loop {
125                    match __de.next().await? {
126                        $crate::Event::MapEnd => break,
127                        $crate::Event::Str(__key) => {
128                            let __key = __opinions.map_key_name(__key);
129                            match __key.as_ref() {
130                                $(stringify!($field) => {
131                                    $field = Some($crate::DynDeserializerExt::t(__de).await?);
132                                })*
133                                _ => {
134                                    if __opinions.deny_unknown_fields() {
135                                        return Err($crate::MerdeError::UnknownProperty(__key).into());
136                                    }
137                                }
138                            }
139                        }
140                        ev => {
141                            return Err($crate::MerdeError::UnexpectedEvent {
142                                got: $crate::EventType::from(&ev),
143                                expected: &[$crate::EventType::Str, $crate::EventType::MapEnd],
144                                help: Some(format!("While deserializing {}", stringify!($struct_name))),
145                            }
146                            .into())
147                        }
148                    }
149                }
150
151                Ok($struct_name {
152                    $($field: {
153                        if $field.is_none() {
154                            let __slot = $crate::FieldSlot::new(&mut $field);
155                            __opinions.default_field_value(stringify!($field), __slot);
156                        }
157                        $crate::Deserialize::from_option($field, stringify!($field).into())?
158                    },)+
159                })
160            }
161        }
162    };
163
164    // owned enum (externally tagged)
165    (enum $enum_name:ident externally_tagged {
166        $($variant_str:literal => $variant:ident),* $(,)?
167    }) => {
168        #[automatically_derived]
169        impl<'s> $crate::Deserialize<'s> for $enum_name {
170            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<'s>) -> Result<Self, $crate::MerdeError<'s>> {
171                #[allow(unused_imports)]
172                use $crate::MerdeError;
173
174                __de.next().await?.into_map_start()?;
175                let key = __de.next().await?.into_str()?;
176                match key.as_ref() {
177                    $($variant_str => {
178                        let value = $crate::DynDeserializerExt::t(__de).await?;
179                        __de.next().await?.into_map_end()?;
180                        Ok($enum_name::$variant(value))
181                    },)*
182                    _ => Err(MerdeError::UnknownProperty(key).into()),
183                }
184            }
185        }
186    };
187
188    // lifetimed enum (externally tagged)
189    (enum $enum_name:ident <$lifetime:lifetime> externally_tagged {
190        $($variant_str:literal => $variant:ident),* $(,)?
191    }) => {
192        #[automatically_derived]
193        impl<$lifetime> $crate::Deserialize<$lifetime> for $enum_name<$lifetime> {
194            #[inline(always)]
195            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<$lifetime>) -> Result<Self, $crate::MerdeError<$lifetime>> {
196                #[allow(unused_imports)]
197                use $crate::{MerdeError, DynDeserializerExt};
198
199                __de.next().await?.into_map_start()?;
200                let key = __de.next().await?.into_str()?;
201                match key.as_ref() {
202                    $($variant_str => {
203                        let value = $crate::DynDeserializerExt::t(__de).await?;
204                        __de.next().await?.into_map_end()?;
205                        Ok($enum_name::$variant(value))
206                    },)*
207                    _ => Err(MerdeError::UnknownProperty(key).into()),
208                }
209            }
210        }
211    };
212
213    // owned enum (externally tagged, string-like)
214    (enum $enum_name:ident string_like {
215        $($variant_str:literal => $variant:ident),* $(,)?
216    }) => {
217        #[automatically_derived]
218        impl<'s> $crate::Deserialize<'s> for $enum_name {
219            async fn deserialize(__de: &mut dyn $crate::DynDeserializer<'s>) -> Result<Self, $crate::MerdeError<'s>> {
220                #[allow(unused_imports)]
221                use $crate::MerdeError;
222                use $crate::DynDeserializerExt;
223
224                let s = __de.next().await?.into_str()?;
225                match s.as_ref() {
226                    $($variant_str => Ok($enum_name::$variant),)*
227                    _ => Err(MerdeError::UnknownProperty(s).into()),
228                }
229            }
230        }
231    };
232}
233
234#[doc(hidden)]
235#[cfg(not(feature = "deserialize"))]
236#[macro_export]
237macro_rules! impl_deserialize {
238    ($($tt:tt)*) => {};
239}
240
241#[doc(hidden)]
242#[macro_export]
243#[cfg(feature = "core")]
244macro_rules! impl_into_static {
245    // owned tuple struct (transparent)
246    (struct $struct_name:ident transparent) => {
247        #[automatically_derived]
248        impl $crate::IntoStatic for $struct_name {
249            type Output = $struct_name;
250
251            #[inline(always)]
252            fn into_static(self) -> Self::Output {
253                self
254            }
255        }
256    };
257
258    // lifetimed tuple struct (transparent)
259    (struct $struct_name:ident <$lifetime:lifetime> transparent) => {
260        #[automatically_derived]
261        impl<$lifetime> $crate::IntoStatic for $struct_name<$lifetime> {
262            type Output = $struct_name<'static>;
263
264            #[inline(always)]
265            fn into_static(self) -> Self::Output {
266                $struct_name($crate::IntoStatic::into_static(self.0))
267            }
268        }
269    };
270
271    // owned struct
272    (struct $struct_name:ident { $($field:ident),* } $($rest:tt)*) => {
273        #[automatically_derived]
274        impl $crate::IntoStatic for $struct_name {
275            type Output = $struct_name;
276
277            #[inline(always)]
278            fn into_static(self) -> Self::Output {
279                self
280            }
281        }
282    };
283
284    // lifetimed struct
285    (struct $struct_name:ident <$lifetime:lifetime> { $($field:ident),* } $($rest:tt)*) => {
286        #[automatically_derived]
287        impl<$lifetime> $crate::IntoStatic for $struct_name<$lifetime> {
288            type Output = $struct_name<'static>;
289
290            fn into_static(self) -> Self::Output {
291                #[allow(unused_imports)]
292                use $crate::IntoStatic;
293
294                $struct_name {
295                    $($field: $crate::IntoStatic::into_static(self.$field),)+
296                }
297            }
298        }
299    };
300
301    // owned enum (externally tagged)
302    (enum $enum_name:ident externally_tagged {
303        $($variant_str:literal => $variant:ident),* $(,)?
304    }) => {
305        #[automatically_derived]
306        impl $crate::IntoStatic for $enum_name {
307            type Output = $enum_name;
308
309            #[inline(always)]
310            fn into_static(self) -> Self::Output {
311                self
312            }
313        }
314    };
315
316    // lifetimed enum (externally tagged)
317    (enum $enum_name:ident <$lifetime:lifetime> externally_tagged {
318        $($variant_str:literal => $variant:ident),* $(,)?
319    }) => {
320        #[automatically_derived]
321        impl<$lifetime> $crate::IntoStatic for $enum_name<$lifetime> {
322            type Output = $enum_name<'static>;
323
324            #[inline(always)]
325            fn into_static(self) -> Self::Output {
326                match self {
327                    $(
328                        Self::$variant(value) => $enum_name::$variant(value.into_static()),
329                    )+
330                }
331            }
332        }
333    };
334
335    // owned enum (string-like)
336    (enum $enum_name:ident string_like {
337        $($variant_str:literal => $variant:ident),* $(,)?
338    }) => {
339        #[automatically_derived]
340        impl $crate::IntoStatic for $enum_name {
341            type Output = $enum_name;
342
343            #[inline(always)]
344            fn into_static(self) -> Self::Output {
345                self
346            }
347        }
348    };
349}
350
351#[doc(hidden)]
352#[macro_export]
353#[cfg(not(feature = "core"))]
354macro_rules! impl_into_static {
355    ($($tt:tt)*) => {};
356}
357
358#[doc(hidden)]
359#[macro_export]
360#[cfg(feature = "core")]
361macro_rules! impl_with_lifetime {
362    // owned tuple struct (transparent)
363    (struct $struct_name:ident transparent) => {
364        #[automatically_derived]
365        impl<'s> $crate::WithLifetime<'s> for $struct_name {
366            type Lifetimed = $struct_name;
367        }
368    };
369
370    // lifetimed tuple struct (transparent)
371    (struct $struct_name:ident <$lifetime:lifetime> transparent) => {
372        #[automatically_derived]
373        impl<'s> $crate::WithLifetime<'s> for $struct_name<$lifetime> {
374            type Lifetimed = $struct_name<$lifetime>;
375        }
376    };
377
378    // owned struct
379    (struct $struct_name:ident { $($field:ident),* } $($rest:tt)*) => {
380        #[automatically_derived]
381        impl<'s> $crate::WithLifetime<'s> for $struct_name {
382            type Lifetimed = $struct_name;
383        }
384    };
385
386    // lifetimed struct
387    (struct $struct_name:ident <$lifetime:lifetime> { $($field:ident),* } $($rest:tt)*) => {
388        #[automatically_derived]
389        impl<$lifetime, 'instantiated_lifetime> $crate::WithLifetime<'instantiated_lifetime>
390            for $struct_name<$lifetime>
391        {
392            type Lifetimed = $struct_name<'instantiated_lifetime>;
393        }
394    };
395
396    // owned enum (externally tagged)
397    (enum $enum_name:ident externally_tagged {
398        $($variant_str:literal => $variant:ident),* $(,)?
399    }) => {
400        #[automatically_derived]
401        impl<'s> $crate::WithLifetime<'s> for $enum_name {
402            type Lifetimed = $enum_name;
403        }
404    };
405
406    // lifetimed enum (externally tagged)
407    (enum $enum_name:ident <$lifetime:lifetime> externally_tagged {
408        $($variant_str:literal => $variant:ident),* $(,)?
409    }) => {
410        #[automatically_derived]
411        impl<$lifetime, 'instantiated_lifetime> $crate::WithLifetime<'instantiated_lifetime>
412            for $enum_name<$lifetime>
413        {
414            type Lifetimed = $enum_name<'instantiated_lifetime>;
415        }
416    };
417
418    // owned enum (string-like)
419    (enum $enum_name:ident string_like {
420        $($variant_str:literal => $variant:ident),* $(,)?
421    }) => {
422        #[automatically_derived]
423        impl<'s> $crate::WithLifetime<'s> for $enum_name {
424            type Lifetimed = $enum_name;
425        }
426    };
427}
428
429#[doc(hidden)]
430#[macro_export]
431#[cfg(not(feature = "core"))]
432macro_rules! impl_with_lifetime {
433    ($($tt:tt)*) => {};
434}
435
436#[doc(hidden)]
437#[macro_export]
438#[cfg(feature = "core")]
439macro_rules! impl_serialize {
440    // owned tuple struct (transparent)
441    (struct $struct_name:ident transparent) => {
442        #[automatically_derived]
443        impl $crate::Serialize for $struct_name {
444            #[allow(clippy::manual_async_fn)]
445            fn serialize<'fut>(
446                &'fut self,
447                serializer: &'fut mut dyn $crate::DynSerializer,
448            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
449                async move {
450                    $crate::Serialize::serialize(&self.0, serializer).await
451                }
452            }
453        }
454    };
455
456    // lifetimed tuple struct (transparent)
457    (struct $struct_name:ident <$lifetime:lifetime> transparent) => {
458        #[automatically_derived]
459        impl<$lifetime> $crate::Serialize for $struct_name<$lifetime> {
460            #[allow(clippy::manual_async_fn)]
461            fn serialize<'fut>(
462                &'fut self,
463                serializer: &'fut mut dyn $crate::DynSerializer,
464            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
465                async move {
466                    $crate::Serialize::serialize(&self.0, serializer).await
467                }
468            }
469        }
470    };
471
472    // lifetimed struct
473    (struct $struct_name:ident < $lifetime:lifetime > { $($field:ident),* }) => {
474        #[automatically_derived]
475        impl<$lifetime> $crate::Serialize for $struct_name<$lifetime> {
476            #[allow(clippy::manual_async_fn)]
477            fn serialize<'fut>(
478                &'fut self,
479                serializer: &'fut mut dyn $crate::DynSerializer,
480            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
481                async move {
482                    serializer
483                        .write($crate::Event::MapStart($crate::MapStart {
484                            size_hint: Some($crate::count_ident_tokens!($($field)*)),
485                        }))
486                        .await?;
487                    $(
488                        serializer.write($crate::Event::Str($crate::CowStr::Borrowed(stringify!($field)))).await?;
489                        $crate::Serialize::serialize(&self.$field, serializer).await?;
490                    )+
491                    serializer.write($crate::Event::MapEnd).await
492                }
493            }
494        }
495    };
496
497    // owned struct
498    (struct $struct_name:ident { $($field:ident),* }) => {
499        #[automatically_derived]
500        impl $crate::Serialize for $struct_name {
501            #[allow(clippy::manual_async_fn)]
502            fn serialize<'fut>(
503                &'fut self,
504                serializer: &'fut mut dyn $crate::DynSerializer,
505            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
506                async move {
507                    serializer
508                        .write($crate::Event::MapStart($crate::MapStart {
509                            size_hint: Some($crate::count_ident_tokens!($($field)*)),
510                        }))
511                        .await?;
512                    $(
513                        serializer.write($crate::Event::Str($crate::CowStr::Borrowed(stringify!($field)))).await?;
514                        $crate::Serialize::serialize(&self.$field, serializer).await?;
515                    )*
516                    serializer.write($crate::Event::MapEnd).await
517                }
518            }
519        }
520    };
521
522    // owned enum (externally tagged)
523    (enum $enum_name:ident externally_tagged {
524        $($variant_str:literal => $variant:ident),* $(,)?
525    }) => {
526        #[automatically_derived]
527        impl $crate::Serialize for $enum_name {
528            #[allow(clippy::manual_async_fn)]
529            fn serialize<'fut>(
530                &'fut self,
531                serializer: &'fut mut dyn $crate::DynSerializer,
532            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
533                async move {
534                    serializer
535                        .write($crate::Event::MapStart($crate::MapStart {
536                            size_hint: Some(1),
537                        }))
538                        .await?;
539
540                    match self {
541                        $(
542                            Self::$variant(value) => {
543                                serializer.write($crate::Event::Str($crate::CowStr::Borrowed($variant_str))).await?;
544                                $crate::Serialize::serialize(value, serializer).await?;
545                            }
546                        )*
547                    }
548
549                    serializer.write($crate::Event::MapEnd).await
550                }
551            }
552        }
553    };
554
555    // lifetimed enum (externally tagged)
556    (enum $enum_name:ident <$lifetime:lifetime> externally_tagged {
557        $($variant_str:literal => $variant:ident),* $(,)?
558    }) => {
559        #[automatically_derived]
560        impl<$lifetime> $crate::Serialize for $enum_name<$lifetime> {
561            #[allow(clippy::manual_async_fn)]
562            fn serialize<'fut>(
563                &'fut self,
564                serializer: &'fut mut dyn $crate::DynSerializer,
565            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
566                async move {
567                    serializer
568                        .write($crate::Event::MapStart($crate::MapStart {
569                            size_hint: Some(1),
570                        }))
571                        .await?;
572
573                    match self {
574                        $(
575                            Self::$variant(value) => {
576                                serializer.write($crate::Event::Str($crate::CowStr::Borrowed($variant_str))).await?;
577                                $crate::Serialize::serialize(value, serializer).await?;
578                            }
579                        )+
580                    }
581
582                    serializer.write($crate::Event::MapEnd).await
583                }
584            }
585        }
586    };
587
588    // owned enum (string-like)
589    (enum $enum_name:ident string_like {
590        $($variant_str:literal => $variant:ident),* $(,)?
591    }) => {
592        #[automatically_derived]
593        impl $crate::Serialize for $enum_name {
594            #[allow(clippy::manual_async_fn)]
595            fn serialize<'fut>(
596                &'fut self,
597                serializer: &'fut mut dyn $crate::DynSerializer,
598            ) -> impl ::std::future::Future<Output = Result<(), $crate::MerdeError<'static>>> + 'fut {
599                async move {
600                    match self {
601                        $(
602                            Self::$variant => {
603                                serializer.write($crate::Event::Str($crate::CowStr::Borrowed($variant_str))).await
604                            }
605                        )+
606                    }
607                }
608            }
609        }
610    };
611}
612
613#[doc(hidden)]
614#[macro_export]
615#[cfg(not(feature = "core"))]
616macro_rules! impl_serialize {
617    ($($rest:tt)*) => {};
618}
619
620#[doc(hidden)]
621#[macro_export]
622macro_rules! impl_trait {
623    // generic
624    (Deserialize for $($rest:tt)*) => {
625        $crate::impl_deserialize!($($rest)*);
626        $crate::impl_into_static!($($rest)*);
627        $crate::impl_with_lifetime!($($rest)*);
628    };
629
630    (Serialize for $($rest:tt)*) => {
631        $crate::impl_serialize!($($rest)*);
632    };
633}
634
635/// Derives the specified traits for a struct.
636///
637/// This macro can be used to generate implementations of [`Serialize`] and [`Deserialize`],
638/// traits for a given struct.
639///
640/// # Usage
641///
642/// ```rust
643/// struct MyStruct<'s> {
644///     a: merde::CowStr<'s>,
645///     b: i32,
646///     c: bool,
647/// }
648///
649/// merde::derive! {
650///     impl (Serialize, Deserialize) for struct MyStruct<'s> { a, b, c }
651/// }
652/// ```
653///
654/// In this example, both traits are derived, of course you can omit the ones you don't need.
655///
656/// Structs without lifetime parameters are also allowed: the macro can tell the difference
657/// from the fact that the lifetime parameter is not present in the invocation:
658///
659/// ```rust
660/// struct MyStruct {
661///     a: String,
662///     b: i32,
663///     c: bool,
664/// }
665///
666/// merde::derive! {
667///     //                          no lifetime param here 👇
668///     impl (Serialize, Deserialize) for struct MyStruct { a, b, c }
669/// }
670/// ```
671///
672/// 1-tuple structs (newtypes) are supported, only in the "transparent" style: serializing
673/// a `String` or a `MyStruct` will give `"foobar"` all the same, as if the newtype wrapper
674/// was stripped, or, well, transparent:
675///
676/// ```rust
677/// struct MyStruct(String);
678///
679/// merde::derive! {
680///     impl (Serialize, Deserialize) for struct MyStruct transparent
681/// }
682///
683/// assert_eq!(
684///   merde::json::to_string(&MyStruct("foobar".into())).unwrap(),
685///   r#""foobar""#
686/// );
687/// ```
688///
689/// Externally tagged enums are also supported. For both owned and lifetimed variants:
690///
691/// ```rust
692/// enum MyEnum {
693///     Variant1(String),
694///     Variant2(i32),
695/// }
696///
697/// merde::derive! {
698///     impl (Serialize, Deserialize) for enum MyEnum
699///     externally_tagged {
700///         "variant1" => Variant1,
701///         "variant2" => Variant2,
702///     }
703/// }
704///
705/// enum MyLifetimedEnum<'a> {
706///     Variant1(merde::CowStr<'a>),
707///     Variant2(i32),
708/// }
709///
710/// merde::derive! {
711///     impl (Serialize, Deserialize) for enum MyLifetimedEnum<'wot>
712///     externally_tagged {
713///         "variant1" => Variant1,
714///         "variant2" => Variant2,
715///     }
716/// }
717/// ```
718///
719/// This will serialize `MyEnum::Variant1("hello".into())` as `{"variant1":"hello"}`,
720/// and `MyEnum::Variant2(42)` as `{"variant2":42}`.
721#[macro_export]
722macro_rules! derive {
723    // generic
724    (impl ($first_trait:ident, $($rest_traits:ident),*) for $($rest:tt)*) => {
725        $crate::impl_trait!($first_trait for $($rest)*);
726        $crate::derive!(impl ($($rest_traits),*) for $($rest)*);
727    };
728    (impl ($first_trait:ident) for $($rest:tt)*) => {
729        $crate::impl_trait!($first_trait for $($rest)*);
730    };
731    (impl () for $($rest:tt)*) => {};
732}
733
734/// Returns an `Option<T>` from a closure that returns a `T` (which
735/// is never called) — this is a type inference trick used when deserializing
736/// struct fields
737#[doc(hidden)]
738pub fn none_of<I, T>(_f: impl FnOnce(I) -> T) -> Option<T> {
739    None
740}
741
742#[doc(hidden)]
743#[macro_export]
744macro_rules! count_ident_tokens {
745    () => { 0 };
746    ($first:ident) => { 1 };
747    ($first:ident $($rest:ident)*) => {
748        1 + $crate::count_ident_tokens!($($rest)*)
749    };
750}
751#[cfg(test)]
752#[cfg(feature = "json")]
753mod json_tests {
754    use std::collections::HashMap;
755
756    use super::*;
757    use crate::json::from_str;
758
759    #[test]
760    fn test_complex_structs() {
761        use std::borrow::Cow;
762        use std::collections::HashMap;
763
764        #[derive(Debug, PartialEq)]
765        struct SecondStruct<'s> {
766            string_field: Cow<'s, str>,
767            int_field: i32,
768        }
769
770        derive! {
771            impl (Serialize, Deserialize) for struct SecondStruct<'s> {
772                string_field,
773                int_field
774            }
775        }
776
777        #[derive(Debug, PartialEq)]
778        struct ComplexStruct<'s> {
779            string_field: Cow<'s, str>,
780            u8_field: u8,
781            u16_field: u16,
782            u32_field: u32,
783            u64_field: u64,
784            i8_field: i8,
785            i16_field: i16,
786            i32_field: i32,
787            i64_field: i64,
788            usize_field: usize,
789            bool_field: bool,
790            option_field: Option<i32>,
791            vec_field: Vec<i32>,
792            hashmap_field: HashMap<String, i32>,
793            second_struct_field: SecondStruct<'s>,
794        }
795
796        derive! {
797            impl (Serialize, Deserialize) for struct ComplexStruct<'s> {
798                string_field,
799                u8_field,
800                u16_field,
801                u32_field,
802                u64_field,
803                i8_field,
804                i16_field,
805                i32_field,
806                i64_field,
807                usize_field,
808                bool_field,
809                option_field,
810                vec_field,
811                hashmap_field,
812                second_struct_field
813            }
814        }
815
816        let mut hashmap = HashMap::new();
817        hashmap.insert("key".to_string(), 42);
818
819        let original = ComplexStruct {
820            string_field: Cow::Borrowed("test string"),
821            u8_field: 8,
822            u16_field: 16,
823            u32_field: 32,
824            u64_field: 64,
825            i8_field: -8,
826            i16_field: -16,
827            i32_field: -32,
828            i64_field: -64,
829            usize_field: 100,
830            bool_field: true,
831            option_field: Some(42),
832            vec_field: vec![1, 2, 3],
833            hashmap_field: hashmap,
834            second_struct_field: SecondStruct {
835                string_field: Cow::Borrowed("nested string"),
836                int_field: 100,
837            },
838        };
839
840        let serialized = crate::json::to_string(&original).unwrap();
841        let deserialized: ComplexStruct = from_str(&serialized).unwrap();
842
843        assert_eq!(original, deserialized);
844    }
845
846    #[test]
847    fn test_u8_zero() {
848        let original: u8 = 0;
849        let serialized = crate::json::to_string(&original).unwrap();
850        let deserialized: u8 = from_str(&serialized).unwrap();
851        assert_eq!(original, deserialized);
852    }
853
854    #[test]
855    fn test_u8_max() {
856        let original: u8 = u8::MAX;
857        let serialized = crate::json::to_string(&original).unwrap();
858        let deserialized: u8 = from_str(&serialized).unwrap();
859        assert_eq!(original, deserialized);
860    }
861
862    #[test]
863    fn test_i8_min() {
864        let original: i8 = i8::MIN;
865        let serialized = crate::json::to_string(&original).unwrap();
866        let deserialized: i8 = from_str(&serialized).unwrap();
867        assert_eq!(original, deserialized);
868    }
869
870    #[test]
871    fn test_i8_max() {
872        let original: i8 = i8::MAX;
873        let serialized = crate::json::to_string(&original).unwrap();
874        let deserialized: i8 = from_str(&serialized).unwrap();
875        assert_eq!(original, deserialized);
876    }
877
878    #[test]
879    fn test_i64_min() {
880        let original: i64 = i64::MIN;
881        let serialized = crate::json::to_string(&original).unwrap();
882        let deserialized: i64 = from_str(&serialized).unwrap();
883        assert_eq!(original, deserialized);
884    }
885
886    #[test]
887    fn test_i64_max() {
888        let original: i64 = i64::MAX;
889        let serialized = crate::json::to_string(&original).unwrap();
890        let deserialized: i64 = from_str(&serialized).unwrap();
891        assert_eq!(original, deserialized);
892    }
893
894    #[test]
895    fn test_string_owned() {
896        let original = String::from("Hello, World!");
897        let serialized = crate::json::to_string(&original).unwrap();
898        let deserialized: String = from_str(&serialized).unwrap();
899        assert_eq!(original, deserialized);
900    }
901
902    #[test]
903    fn test_string_borrowed() {
904        let original: &str = "Hello, World!";
905        let serialized = crate::json::to_string(&original).unwrap();
906        let deserialized: String = from_str(&serialized).unwrap();
907        assert_eq!(original, deserialized);
908    }
909
910    #[test]
911    fn test_vec_empty() {
912        let original: Vec<i32> = Vec::new();
913        let serialized = crate::json::to_string(&original).unwrap();
914        let deserialized: Vec<i32> = from_str(&serialized).unwrap();
915        assert_eq!(original, deserialized);
916    }
917
918    #[test]
919    fn test_vec_non_empty() {
920        let original = vec![1, 2, 3, 4, 5];
921        let serialized = crate::json::to_string(&original).unwrap();
922        let deserialized: Vec<i32> = from_str(&serialized).unwrap();
923        assert_eq!(original, deserialized);
924    }
925
926    #[test]
927    fn test_hashmap_empty() {
928        let original: HashMap<String, i32> = HashMap::new();
929        let serialized = crate::json::to_string(&original).unwrap();
930        let deserialized: HashMap<String, i32> = from_str(&serialized).unwrap();
931        assert_eq!(original, deserialized);
932    }
933
934    #[test]
935    fn test_hashmap_non_empty() {
936        let mut original = HashMap::new();
937        original.insert("key1".to_string(), 42);
938        original.insert("key2".to_string(), -10);
939        let serialized = crate::json::to_string(&original).unwrap();
940        let deserialized: HashMap<String, i32> = from_str(&serialized).unwrap();
941        assert_eq!(original, deserialized);
942    }
943
944    #[test]
945    fn test_option_some() {
946        let original: Option<i32> = Some(42);
947        let serialized = crate::json::to_string(&original).unwrap();
948        let deserialized: Option<i32> = from_str(&serialized).unwrap();
949        assert_eq!(original, deserialized);
950    }
951
952    #[test]
953    fn test_option_none() {
954        let original: Option<i32> = None;
955        let serialized = crate::json::to_string(&original).unwrap();
956        let deserialized: Option<i32> = from_str(&serialized).unwrap();
957        assert_eq!(original, deserialized);
958    }
959
960    #[test]
961    fn test_bool_true() {
962        let original = true;
963        let serialized = crate::json::to_string(&original).unwrap();
964        let deserialized: bool = from_str(&serialized).unwrap();
965        assert_eq!(original, deserialized);
966    }
967
968    #[test]
969    fn test_bool_false() {
970        let original = false;
971        let serialized = crate::json::to_string(&original).unwrap();
972        let deserialized: bool = from_str(&serialized).unwrap();
973        assert_eq!(original, deserialized);
974    }
975}
976
977// used to test out doc-tests
978mod doctest_playground {
979
980    #[allow(unused_imports)]
981    use crate as merde;
982
983    ////////////////////////////////////////////////////////////////////////////////
984
985    // (insert doctest here for testing, with `#[test]` above fn main())
986
987    ////////////////////////////////////////////////////////////////////////////////
988}