benzina 0.5.1

Various helper types and macros for `diesel`
Documentation
use std::fmt;

use serde_core::{
    Deserialize, Deserializer, Serialize, Serializer,
    de::{self, Unexpected, Visitor},
};

use crate::{U15, U31, U63};

macro_rules! impl_serde_numbers_visit {
    ($type:ident = [$($visit_fn:ident => $kind:ident($inner:ident) => $new_fn:ident),*]) => {
        $(
            fn $visit_fn<E: de::Error>(self, v: $inner) -> Result<Self::Value, E> {
                v.try_into()
                    .map_err(|_| de::Error::invalid_value(Unexpected::$kind(v.into()), &self))
                    .and_then(|cv| {
                        $type::$new_fn(cv)
                            .ok_or_else(|| de::Error::invalid_value(Unexpected::$kind(v.into()), &self))
                    })
            }
        )*
    }
}

macro_rules! impl_serde_numbers {
    ($($type:ident => $inner:ident, $deserialize_fn:ident),*) => {
        $(
            impl Serialize for $type {
                fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
                    self.get().serialize(serializer)
                }
            }

            impl<'de> Deserialize<'de> for $type {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
                    struct NumberVisitor;

                    impl Visitor<'_> for NumberVisitor {
                        type Value = $type;

                        fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                            f.write_str(stringify!($type))
                        }

                        impl_serde_numbers_visit! {
                            $type = [
                                visit_u8 => Unsigned(u8) => new,
                                visit_u16 => Unsigned(u16) => new,
                                visit_u32 => Unsigned(u32) => new,
                                visit_u64 => Unsigned(u64) => new,
                                visit_i8 => Signed(i8) => new_signed,
                                visit_i16 => Signed(i16) => new_signed,
                                visit_i32 => Signed(i32) => new_signed,
                                visit_i64 => Signed(i64) => new_signed
                            ]
                        }
                    }

                    deserializer.$deserialize_fn(NumberVisitor)
                }
            }
        )*
    }
}

impl_serde_numbers! {
    U15 => u16, deserialize_u16,
    U31 => u32, deserialize_u32,
    U63 => u64, deserialize_u64
}

#[cfg(test)]
mod tests {
    use serde_test::{Token, assert_de_tokens, assert_ser_tokens};

    use crate::{U15, U31, U63};

    macro_rules! int_ser_tests {
        ($($type:ident, $inner:ident, $token_type:ident, $test_name:ident),*) => {
            $(
                #[test]
                fn $test_name() {
                    const VALUE: $inner = $inner::MAX / 2;
                    let v = $type::new(VALUE).unwrap();
                    assert_ser_tokens(
                        &v,
                        &[
                            Token::$token_type(VALUE),
                        ],
                    );
                }
            )*
        }
    }

    macro_rules! int_de_tests {
        ($($type:ident, $inner:ident, $token_type:ident, $token_type_inner:ident, $test_name:ident),*) => {
            $(
                #[test]
                fn $test_name() {
                    const VALUE: $inner = if ($token_type_inner::MAX as u128) < $inner::MAX as u128 {
                        $token_type_inner::MAX as $inner
                    } else {
                        $inner::MAX
                    } / 2;
                    let v = $type::new(VALUE).unwrap();
                    assert_de_tokens(&v, &[Token::$token_type(VALUE as _)]);
                }
            )*
        }
    }

    int_ser_tests! {
        U15, u16, U16, int_ser_u15,
        U31, u32, U32, int_ser_u31,
        U63, u64, U64, int_ser_u63
    }

    int_de_tests! {
        U15, u16, U8, u8, int_de_u15_from_u8,
        U15, u16, U16, u16, int_de_u15_from_u16,
        U15, u16, U32, u32, int_de_u15_from_u32,
        U15, u16, U64, u64, int_de_u15_from_u64,
        U15, u16, I8, i8, int_de_u15_from_i8,
        U15, u16, I16, i16, int_de_u15_from_i16,
        U15, u16, I32, i32, int_de_u15_from_i32,
        U15, u16, I64, i64, int_de_u15_from_i64,
        U31, u32, U8, u8, int_de_u31_from_u8,
        U31, u32, U16, u16, int_de_u31_from_u16,
        U31, u32, U32, u32, int_de_u31_from_u32,
        U31, u32, U64, u64, int_de_u31_from_u64,
        U31, u32, I8, i8, int_de_u31_from_i8,
        U31, u32, I16, i16, int_de_u31_from_i16,
        U31, u32, I32, i32, int_de_u31_from_i32,
        U31, u32, I64, i64, int_de_u31_from_i64,
        U63, u64, U8, u8, int_de_u63_from_u8,
        U63, u64, U16, u16, int_de_u63_from_u16,
        U63, u64, U32, u32, int_de_u63_from_u32,
        U63, u64, U64, u64, int_de_u63_from_u64,
        U63, u64, I8, i8, int_de_u63_from_i8,
        U63, u64, I16, i16, int_de_u63_from_i16,
        U63, u64, I32, i32, int_de_u63_from_i32,
        U63, u64, I64, i64, int_de_u63_from_i64
    }
}