serde_builder 0.2.0

serde extension to build de/serialization algorithms for types using a builder pattern
Documentation
use std::marker::PhantomData;

use serde::{ser::SerializeStruct, Serialize, Serializer};

pub trait FieldAccessor<T, FT> {
    fn get_field(self, parent: &T) -> &FT;
}

impl<T, FT, FN> FieldAccessor<T, FT> for FN
where
    FN: FnOnce(&T) -> &FT,
{
    fn get_field(self, parent: &T) -> &FT {
        self(parent)
    }
}

pub struct Field<T, FT, FA> {
    name: &'static str,
    accessor: FA,
    target_phantom: PhantomData<T>,
    field_phantom: PhantomData<FT>,
}

impl<T, FT, FA> Field<T, FT, FA> {
    fn new(name: &'static str, field_accessor: FA) -> Self {
        Self {
            name,
            accessor: field_accessor,
            target_phantom: PhantomData::default(),
            field_phantom: PhantomData::default(),
        }
    }
}

pub struct StructSerializer<T, FIELDS = (), const FN: usize = 0> {
    target_phantom: PhantomData<T>,
    fields: FIELDS,
}

impl<T> Default for StructSerializer<T> {
    fn default() -> Self {
        Self {
            target_phantom: PhantomData::default(),
            fields: (),
        }
    }
}

impl<T> StructSerializer<T> {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn field<FT, FA: FnOnce(&T) -> &FT>(
        self,
        name: &'static str,
        field_accessor: FA,
    ) -> StructSerializer<T, (Field<T, FT, FA>,), 1> {
        let StructSerializer {
            target_phantom,
            fields: _,
        } = self;
        StructSerializer {
            target_phantom,
            fields: (Field::new(name, field_accessor),),
        }
    }
}

macro_rules! add_field_impl {
    ($($len:expr => ($($n:tt $fname:ident $faname:ident),+) $fname2:ident $faname2:ident)+) => {
        $(
            impl<T, $($fname, $faname),+> StructSerializer<T, ($(Field<T, $fname, $faname>,)+), $len>
            where
                $($faname: FieldAccessor<T, $fname>,)+
            {
                pub fn field<$fname2, $faname2: FnOnce(&T) -> &$fname2>(self, name: &'static str, field_accessor: $faname2) ->
                    StructSerializer<T, ($(Field<T, $fname, $faname>,)+ Field<T, $fname2, $faname2>,), {$len + 1}>
                {
                    let StructSerializer {
                        target_phantom,
                        fields,
                    } = self;
                    StructSerializer {
                        target_phantom,
                        fields: ($(fields.$n,)+ Field::new(name, field_accessor)),
                    }
                }
            }
        )+
    };
}

add_field_impl! {
    1 => (0 F0 F0A) F1 F1A
    2 => (0 F0 F0A, 1 F1 F1A) F2 F2A
    3 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A) F3 F3A
    4 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A) F4 F4A
    5 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A) F5 F5A
    6 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A) F6 F6A
    7 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A) F7 F7A
    8 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A) F8 F8A
    9 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A) F9 F9A
    10 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A, 9 F9 F9A) F10 F10A
    11 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A, 9 F9 F9A, 10 F10 F10A) F11 F11A
    12 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A, 9 F9 F9A, 10 F10 F10A, 11 F11 F11A) F12 F12A
    13 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A, 9 F9 F9A, 10 F10 F10A, 11 F11 F11A, 12 F12 F12A) F13 F13A
    14 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A, 9 F9 F9A, 10 F10 F10A, 11 F11 F11A, 12 F12 F12A, 13 F13 F13A) F14 F14A
    15 => (0 F0 F0A, 1 F1 F1A, 2 F2 F2A, 3 F3 F3A, 4 F4 F4A, 5 F5 F5A, 6 F6 F6A, 7 F7 F7A, 8 F8 F8A, 9 F9 F9A, 10 F10 F10A, 11 F11 F11A, 12 F12 F12A, 13 F13 F13A, 14 F14 F14A) F15 F15A
}

macro_rules! ser_impl {
    ($($len:expr => $($ftname:ident $faname:ident $fvname:ident),+)+) => {
        $(
            impl<T, $($ftname, $faname),+> StructSerializer<T, ($(Field<T, $ftname, $faname>,)+), $len>
            where
                $(
                $ftname: Serialize,
                $faname: FieldAccessor<T, $ftname>,
                )+
            {
                pub fn serialize<S: Serializer>(self, value: &T, ser: S) -> Result<S::Ok, S::Error> {
                    let mut struct_ser_state = ser.serialize_struct(std::any::type_name::<T>(), $len)?;
                    let ($($fvname,)+) = self.fields;
                    $(
                        struct_ser_state.serialize_field($fvname.name, $fvname.accessor.get_field(value))?;
                    )+
                    struct_ser_state.end()
                }
            }
        )+
    }
}

ser_impl! {
    1 => F0 F0A f0
    2 => F0 F0A f0, F1 F1A f1
    3 => F0 F0A f0, F1 F1A f1, F2 F2A f2
    4 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3
    5 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4
    6 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5
    7 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6
    8 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7
    9 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8
    10 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9
    11 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9, F10 F10A f10
    12 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9, F10 F10A f10, F11 F11A f11
    13 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9, F10 F10A f10, F11 F11A f11, F12 F12A f12
    14 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9, F10 F10A f10, F11 F11A f11, F12 F12A f12, F13 F13A f13
    15 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9, F10 F10A f10, F11 F11A f11, F12 F12A f12, F13 F13A f13, F14 F14A f14
    16 => F0 F0A f0, F1 F1A f1, F2 F2A f2, F3 F3A f3, F4 F4A f4, F5 F5A f5, F6 F6A f6, F7 F7A f7, F8 F8A f8, F9 F9A f9, F10 F10A f10, F11 F11A f11, F12 F12A f12, F13 F13A f13, F14 F14A f14, F15 F15A f15
}