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
//! Core definitions

use crate::error::DeltaResult;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;

/// Defines an associated Delta type. This is used by the other core traits
/// to agree on a common Delta definition for each implementing type.
pub trait Core {
    type Delta: Sized + Clone + Debug + PartialEq
        + for<'de> Deserialize<'de>
        + Serialize;
}

pub trait Apply: Core + Clone + Debug + PartialEq {
    /// Calculate a new instance of `Self` based on `self` and `delta`
    /// i.e. calculate `self --[delta]--> other`.
    ///                                   ^^^^^
    fn apply(&self, delta: Self::Delta) -> DeltaResult<Self>;
}

pub trait Delta: Core + Clone + Debug + PartialEq {
    /// Calculate `self --[delta]--> other`.
    ///                    ^^^^^
    fn delta(&self, other: &Self) -> DeltaResult<Self::Delta>;
}

/// Conversion from type *Delta to type *
pub trait FromDelta: Core + Sized {
    /// Convert `Self::Delta` to `Self`.
    fn from_delta(delta: Self::Delta) -> DeltaResult<Self>;
}

/// Conversion from type * to type *Delta
pub trait IntoDelta: Core {
    /// Convert `Self` to `Self::Delta`.
    fn into_delta(self) -> DeltaResult<Self::Delta>;
}


macro_rules! impl_delta_trait_for_primitive_types {
    ( $($type:ty => $delta:ident $(: $($traits:ident),+)?);* $(;)? ) => {
        $(
            $( #[derive( $($traits),+ )] )?
            #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
            pub struct $delta(#[doc(hidden)] pub Option<$type>);

            impl Core for $type {
                type Delta = $delta;
            }

            impl Apply for $type {
                #[inline(always)]
                fn apply(&self, delta: Self::Delta) -> DeltaResult<Self> {
                    Self::from_delta(delta)
                }
            }

            impl Delta for $type {
                #[inline(always)]
                fn delta(&self, rhs: &Self) -> DeltaResult<Self::Delta> {
                    rhs.clone().into_delta()
                }
            }

            impl FromDelta for $type {
                #[inline(always)]
                fn from_delta(delta: Self::Delta) -> DeltaResult<Self> {
                    // TODO: perhaps turn the option to choose either returning
                    //       an error or a `Default` value into a policy?
                    // match delta.0 {
                    //     Some(value) => Ok(value),
                    //     None => Ok(Self::default()),
                    // }
                    delta.0.ok_or_else(|| ExpectedValue!(stringify!($delta)))
                }
            }

            impl IntoDelta for $type {
                #[inline(always)]
                fn into_delta(self) -> DeltaResult<Self::Delta> {
                    Ok($delta(Some(self)))
                }
            }

            impl std::fmt::Debug for $delta {
                fn fmt(&self, f: &mut std::fmt::Formatter)
                       -> Result<(), std::fmt::Error>
                {
                    match self.0 {
                        None =>
                            write!(f, "{}(None)", stringify!($delta)),
                        Some(prim) =>
                            write!(f, "{}({:#?})", stringify!($delta), prim),
                    }
                }
            }
        )*
    };
}

impl_delta_trait_for_primitive_types! {
    i8    => I8Delta:    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    i16   => I16Delta:   Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    i32   => I32Delta:   Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    i64   => I64Delta:   Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    i128  => I128Delta:  Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    isize => IsizeDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;

    u8    => U8Delta:    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    u16   => U16Delta:   Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    u32   => U32Delta:   Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    u64   => U64Delta:   Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    u128  => U128Delta:  Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    usize => UsizeDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;

    f32   => F32Delta:   Clone, Copy, PartialEq,     PartialOrd           ;
    f64   => F64Delta:   Clone, Copy, PartialEq,     PartialOrd           ;
    bool  => BoolDelta:  Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    char  => CharDelta:  Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
    ()    => UnitDelta:  Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash;
}