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
#![allow(non_snake_case)]

use crate::prelude::*;

// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/
macro_rules! expr {
    ($x:expr) => {
        $x
    };
} // HACK
macro_rules! tuple_index {
    ($tuple:expr, $idx:tt) => {
        expr!($tuple.$idx)
    };
}

macro_rules! impl_tuple {
    ($count:expr, $trid:expr, $taid:expr, $($ts:ident, $ti:tt,)+) => {
        #[cfg(feature = "write")]
        impl <'a, $($ts: Writable<'a>),+> Writable<'a> for ($($ts),+) {
            type WriterArray=($($ts::WriterArray),+);
            fn write_root<'b: 'a>(value: &'b Self, bytes: &mut Vec<u8>, lens: &mut Vec<usize>) -> RootTypeId {
                $(
                    let type_index = bytes.len();
                    bytes.push(0);
                    let type_id = $ts::write_root(&tuple_index!(value, $ti), bytes, lens);
                    bytes[type_index] = type_id.into();
                )+
                $trid
            }
        }

        #[cfg(feature = "write")]
        impl<'a, $($ts: WriterArray<'a>),+> WriterArray<'a> for ($($ts),+) {
            type Write=($($ts::Write),+);
            fn buffer<'b: 'a>(&mut self, value: &'b Self::Write) {
                $(
                    tuple_index!(self, $ti).buffer(&tuple_index!(value, $ti));
                )+
            }
            fn flush(self, bytes: &mut Vec<u8>, lens: &mut Vec<usize>) -> ArrayTypeId {
                let ($($ts,)+) = self;
                $(
                    let type_index = bytes.len();
                    bytes.push(0);
                    let type_id = $ts.flush(bytes, lens);
                    bytes[type_index] = type_id.into();
                )+
                $taid
            }
        }

        #[cfg(feature = "read")]
        impl <$($ts: Readable),+> Readable for ($($ts),+) {
            type ReaderArray=($($ts::ReaderArray),+);
            fn read(sticks: DynRootBranch<'_>) -> ReadResult<Self> {
                match sticks {
                    DynRootBranch::Tuple { mut children } => {
                        // See also abb368f2-6c99-4c44-8f9f-4b00868adaaf
                        if children.len() != $count {
                            return Err(ReadError::SchemaMismatch)
                        }
                        let mut children = children.drain(..);
                        Ok((
                            // This unwrap is ok because we verified the len already. See alsoa abb368f2-6c99-4c44-8f9f-4b00868adaaf
                            $($ts::read(children.next().unwrap())?),+
                        ))
                    },
                    _ => Err(ReadError::SchemaMismatch),
                }
            }
        }

        #[cfg(feature = "read")]
        impl <$($ts: ReaderArray),+> ReaderArray for ($($ts),+) {
            type Read=($($ts::Read),+);
            fn new(sticks: DynArrayBranch<'_>) -> ReadResult<Self> {
                match sticks {
                    DynArrayBranch::Tuple { mut children } => {
                        // See also abb368f2-6c99-4c44-8f9f-4b00868adaaf
                        if children.len() != $count {
                            return Err(ReadError::SchemaMismatch)
                        }
                        let mut children = children.drain(..);
                        Ok((
                            // This unwrap is ok because we verified the len already. See alsoa abb368f2-6c99-4c44-8f9f-4b00868adaaf
                            $($ts::new(children.next().unwrap())?),+
                        ))
                    },
                    _ => Err(ReadError::SchemaMismatch)
                }
            }
            fn read_next(&mut self) -> ReadResult<Self::Read> {
                Ok(($(
                    tuple_index!(self, $ti).read_next()?,
                )+))
            }
        }
    };
}

// TODO: Consider 0 and 1 sized tuples.
// These should probably be no serialization at all,
// and pass-through serialization respectively and just
// not use the tuple construct. The tuple construct isn't invalid
// though, which opens considerations for matching either for a schema
// which may not be trivial - like a recursive descent parser.
impl_tuple!(2, RootTypeId::Tuple2, ArrayTypeId::Tuple2, T0, 0, T1, 1,);
impl_tuple!(3, RootTypeId::Tuple3, ArrayTypeId::Tuple3, T0, 0, T1, 1, T2, 2,);
impl_tuple!(4, RootTypeId::Tuple4, ArrayTypeId::Tuple4, T0, 0, T1, 1, T2, 2, T3, 3,);
impl_tuple!(5, RootTypeId::Tuple5, ArrayTypeId::Tuple5, T0, 0, T1, 1, T2, 2, T3, 3, T4, 4,);
impl_tuple!(6, RootTypeId::Tuple6, ArrayTypeId::Tuple6, T0, 0, T1, 1, T2, 2, T3, 3, T4, 4, T5, 5,);

// TODO: Support tuple structs in the macro