1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/// This macro is the primary way to make serializers. See the [top level docs](index.html) for an
/// example.
///
/// This macro expands into a function the implements [`Serializer`](trait.Serializer.html). This
/// is because [`Serializer<T>`](trait.Serializer.html) is automatically implemented for functions
/// with the signature `Fn(&T, &mut Builder)`.
///
/// ## Customization
///
/// The macro also lets you set separate JSON keys and field names. That is done by adding an
/// additional first argument to `attr`, `has_one`, or `has_many` which will be the key.
///
/// Example:
///
/// ```
/// #[macro_use]
/// extern crate serializers;
///
/// use serializers::*;
///
/// struct User {
///     id: u64,
///     country: Country,
///     friends: Vec<User>,
/// }
///
/// #[derive(Clone)]
/// struct Country {
///     id: u64,
/// }
///
/// serializer! {
///     serialize_user: User {
///         attr(identifier, id)
///         has_one(homeland, country, serialize_country)
///         has_many(buddies, friends, serialize_user)
///     }
/// }
///
/// serializer! {
///     serialize_country: Country {
///         attr(code, id)
///     }
/// }
///
/// fn main() {
///     let denmark = Country {
///         id: 1,
///     };
///
///     let bob = User {
///         id: 1,
///         country: denmark.clone(),
///         friends: vec![
///             User {
///                 id: 2,
///                 country: denmark.clone(),
///                 friends: vec![],
///             }
///         ],
///     };
///
///     let json = serialize_user.serialize(&bob);
///
///     assert_eq!(
///         json,
///         "{\"buddies\":[{\"buddies\":[],\"homeland\":{\"code\":1},\"identifier\":2}],\"homeland\":{\"code\":1},\"identifier\":1}"
///     );
/// }
/// ```
#[macro_export]
macro_rules! serializer {
    {
        $name:ident: $type:ty { $($rest:tt)* }
    } => {
        fn $name(v: &$type, b: &mut Builder) {
            serializer! { [b, v] $($rest)* }
        }
    };

    // base case
    { [$b:expr, $v:expr] } => {};

    // attr
    {
        [$b:expr, $v:expr] attr($attr:ident) $($rest:tt)*
    } => {
        serializer! { [$b, $v] attr($attr, $attr) $($rest)* }
    };

    {
        [$b:expr, $v:expr] attr($key:ident, $field:ident) $($rest:tt)*
    } => {
        $b.attr(stringify!($key), &$v.$field);
        serializer! { [$b, $v] $($rest)* }
    };

    // has_one
    {
        [$b:expr, $v:expr] has_one($key:ident, $has_one_ser:ident) $($rest:tt)*
    } => {
        serializer! { [$b, $v] has_one($key, $key, $has_one_ser) $($rest)* }
    };

    {
        [$b:expr, $v:expr] has_one($key:ident, $field:ident, $has_one_ser:ident) $($rest:tt)*
    } => {
        $b.has_one(stringify!($key), &$v.$field, &$has_one_ser);
        serializer! { [$b, $v] $($rest)* }
    };

    // has_many
    {
        [$b:expr, $v:expr] has_many($key:ident, $has_one_ser:ident) $($rest:tt)*
    } => {
        serializer! { [$b, $v] has_many($key, $key, $has_one_ser) $($rest)* }
    };

    {
        [$b:expr, $v:expr] has_many($key:ident, $field:ident, $has_one_ser:ident) $($rest:tt)*
    } => {
        $b.has_many(stringify!($key), &$v.$field, &$has_one_ser);
        serializer! { [$b, $v] $($rest)* }
    };
}