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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! This module contains the implementations of [`TryFrom`] and [`From`] to convert between
//! [`Message`], [`PeerRequest`] and [`PeerResponse`].

use cuprate_wire::{Message, ProtocolMessage, RequestMessage, ResponseMessage};

use super::{PeerRequest, PeerResponse};

#[derive(Debug)]
pub struct MessageConversionError;

macro_rules! match_body {
    (match $value: ident {$($body:tt)*} ($left:pat => $right_ty:expr) $($todo:tt)*) => {
        match_body!( match $value {
            $left => $right_ty,
            $($body)*
        } $($todo)* )
    };
    (match $value: ident {$($body:tt)*}) => {
         match $value {
            $($body)*
        }
    };
}

macro_rules! from {
    ($left_ty:ident, $right_ty:ident, {$($left:ident $(($val: ident))? = $right:ident $(($vall: ident))?,)+}) => {
        impl From<$left_ty> for $right_ty {
            fn from(value: $left_ty) -> Self {
                 match_body!( match value {}
                    $(($left_ty::$left$(($val))? => $right_ty::$right$(($vall))?))+
                )
            }
        }
    };
}

macro_rules! try_from {
    ($left_ty:ident, $right_ty:ident, {$($left:ident $(($val: ident))? = $right:ident $(($vall: ident))?,)+}) => {
        impl TryFrom<$left_ty> for $right_ty {
            type Error = MessageConversionError;

            fn try_from(value: $left_ty) -> Result<Self, Self::Error> {
                 Ok(match_body!( match value {
                        _ => return Err(MessageConversionError)
                    }
                    $(($left_ty::$left$(($val))? => $right_ty::$right$(($vall))?))+
                ))
            }
        }
    };
}

macro_rules! from_try_from {
    ($left_ty:ident, $right_ty:ident, {$($left:ident $(($val: ident))? = $right:ident $(($vall: ident))?,)+}) => {
        try_from!($left_ty, $right_ty, {$($left $(($val))? = $right $(($vall))?,)+});
        from!($right_ty, $left_ty, {$($right $(($val))? = $left $(($vall))?,)+});
    };
}

macro_rules! try_from_try_from {
    ($left_ty:ident, $right_ty:ident, {$($left:ident $(($val: ident))? = $right:ident $(($vall: ident))?,)+}) => {
        try_from!($left_ty, $right_ty, {$($left $(($val))? = $right $(($vall))?,)+});
        try_from!($right_ty, $left_ty, {$($right $(($val))? = $left $(($val))?,)+});
    };
}

from_try_from!(PeerRequest, RequestMessage,{
    Handshake(val) = Handshake(val),
    Ping = Ping,
    SupportFlags = SupportFlags,
    TimedSync(val) = TimedSync(val),
});

try_from_try_from!(PeerRequest, ProtocolMessage,{
    NewBlock(val) = NewBlock(val),
    NewFluffyBlock(val) = NewFluffyBlock(val),
    GetObjects(val) = GetObjectsRequest(val),
    GetChain(val) = ChainRequest(val),
    NewTransactions(val) = NewTransactions(val),
    FluffyMissingTxs(val) = FluffyMissingTransactionsRequest(val),
    GetTxPoolCompliment(val) = GetTxPoolCompliment(val),
});

impl TryFrom<Message> for PeerRequest {
    type Error = MessageConversionError;

    fn try_from(value: Message) -> Result<Self, Self::Error> {
        match value {
            Message::Request(req) => Ok(req.into()),
            Message::Protocol(pro) => pro.try_into(),
            _ => Err(MessageConversionError),
        }
    }
}

impl From<PeerRequest> for Message {
    fn from(value: PeerRequest) -> Self {
        match value {
            PeerRequest::Handshake(val) => Message::Request(RequestMessage::Handshake(val)),
            PeerRequest::Ping => Message::Request(RequestMessage::Ping),
            PeerRequest::SupportFlags => Message::Request(RequestMessage::SupportFlags),
            PeerRequest::TimedSync(val) => Message::Request(RequestMessage::TimedSync(val)),

            PeerRequest::NewBlock(val) => Message::Protocol(ProtocolMessage::NewBlock(val)),
            PeerRequest::NewFluffyBlock(val) => {
                Message::Protocol(ProtocolMessage::NewFluffyBlock(val))
            }
            PeerRequest::GetObjects(val) => {
                Message::Protocol(ProtocolMessage::GetObjectsRequest(val))
            }
            PeerRequest::GetChain(val) => Message::Protocol(ProtocolMessage::ChainRequest(val)),
            PeerRequest::NewTransactions(val) => {
                Message::Protocol(ProtocolMessage::NewTransactions(val))
            }
            PeerRequest::FluffyMissingTxs(val) => {
                Message::Protocol(ProtocolMessage::FluffyMissingTransactionsRequest(val))
            }
            PeerRequest::GetTxPoolCompliment(val) => {
                Message::Protocol(ProtocolMessage::GetTxPoolCompliment(val))
            }
        }
    }
}

from_try_from!(PeerResponse, ResponseMessage,{
    Handshake(val) = Handshake(val),
    Ping(val) = Ping(val),
    SupportFlags(val) = SupportFlags(val),
    TimedSync(val) = TimedSync(val),
});

try_from_try_from!(PeerResponse, ProtocolMessage,{
    NewFluffyBlock(val) = NewFluffyBlock(val),
    GetObjects(val) = GetObjectsResponse(val),
    GetChain(val) = ChainEntryResponse(val),
    NewTransactions(val) = NewTransactions(val),

});

impl TryFrom<Message> for PeerResponse {
    type Error = MessageConversionError;

    fn try_from(value: Message) -> Result<Self, Self::Error> {
        match value {
            Message::Response(res) => Ok(res.into()),
            Message::Protocol(pro) => pro.try_into(),
            _ => Err(MessageConversionError),
        }
    }
}

impl TryFrom<PeerResponse> for Message {
    type Error = MessageConversionError;

    fn try_from(value: PeerResponse) -> Result<Self, Self::Error> {
        Ok(match value {
            PeerResponse::Handshake(val) => Message::Response(ResponseMessage::Handshake(val)),
            PeerResponse::Ping(val) => Message::Response(ResponseMessage::Ping(val)),
            PeerResponse::SupportFlags(val) => {
                Message::Response(ResponseMessage::SupportFlags(val))
            }
            PeerResponse::TimedSync(val) => Message::Response(ResponseMessage::TimedSync(val)),

            PeerResponse::NewFluffyBlock(val) => {
                Message::Protocol(ProtocolMessage::NewFluffyBlock(val))
            }
            PeerResponse::GetObjects(val) => {
                Message::Protocol(ProtocolMessage::GetObjectsResponse(val))
            }
            PeerResponse::GetChain(val) => {
                Message::Protocol(ProtocolMessage::ChainEntryResponse(val))
            }
            PeerResponse::NewTransactions(val) => {
                Message::Protocol(ProtocolMessage::NewTransactions(val))
            }

            PeerResponse::NA => return Err(MessageConversionError),
        })
    }
}