Skip to main content

ygopro_data/message/
utils.rs

1//! Message traits and shared types.
2//!
3//! Provides the [`PureMessage`] / [`Message`] traits, the [`HostInfo`] struct, and the
4//! message [`Error`] type.
5
6use std::fmt::Debug;
7use binrw::BinRead;
8use binrw::BinWrite;
9
10use crate::constants::MasterRule;
11use crate::constants::Rule;
12
13pub trait PureMessage: 'static {}
14
15pub trait Message: PureMessage + Debug {
16    fn message_type() -> crate::message::all::MessageType where Self: Sized;
17}
18
19#[derive(BinRead, BinWrite, Clone, Debug)]
20#[repr(C)]
21pub struct HostInfo {
22    pub lflist: u32,
23    pub rule: Rule,
24    pub mode: crate::constants::Mode,
25    pub duel_rule: crate::constants::MasterRule,
26    #[br(map=|v:u8| v>0)]
27    #[bw(map=|v| if *v {1u8} else {0u8})]
28    pub no_check_deck: bool,
29    #[br(map=|v:u8| v>0)]
30    #[bw(map=|v| if *v {1u8} else {0u8})]
31    #[brw(pad_after=3)]
32    pub no_shuffle_deck: bool,
33    pub start_lp: u32,
34    pub start_hand: u8,
35    pub draw_count: u8,
36    pub time_limit: u16
37}
38
39impl Default for HostInfo {
40    fn default() -> Self {
41        Self { 
42            lflist: 0, 
43            rule: Rule::OCG,
44            mode: crate::constants::Mode::Match, 
45            duel_rule: MasterRule::MasterRule2020,
46            no_check_deck: false, 
47            no_shuffle_deck: false, 
48            start_lp: 8000,
49            start_hand: 5, 
50            draw_count: 1, 
51            time_limit: 180
52        }
53    }
54}
55
56#[derive(thiserror::Error, Debug)]
57pub enum Error {
58    #[error("Something wrong when io")]
59    IO(std::io::Error),
60    #[error("Custom error")]
61    Custom(String),
62    #[error("Try to serialize a component over its design size")]
63    Oversize,
64    #[error("Deserialize finished, but remain some bytes")]
65    Remain(Vec<u8>),
66    #[error("Try to deserialize a seq without limit.")]
67    Unlimited,
68    #[error("Some error happened when unwrap the writer.")]
69    UnwrapWriter,
70    #[error("Try to deserialize to a wrong type.")]
71    WrongType,
72    #[error("Try to deserialize an unknown type message.")]
73    UnknownType,
74    #[error("Try to change full message to wrong status.")]
75    WrongStatus,
76}
77
78#[macro_export]
79macro_rules! generate_enum {
80    ($($message_name:ident=$message_flag:literal),*) => {
81        #[derive(binrw::BinRead, binrw::BinWrite, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
82        #[brw(repr=u8)]
83        #[repr(u8)]
84        pub enum MessageType {
85            Unknown(u8),
86            $($message_name=$message_flag),*
87        }
88        
89        impl std::convert::From<u8> for MessageType {
90            fn from(value: u8) -> Self {
91                match value {
92                    $($message_flag => Self::$message_name,)*
93                    _ => Self::Unknown(value)
94                }
95            }
96        }
97
98        impl std::convert::From<MessageType> for u8 {
99            fn from(value: MessageType) -> Self {
100                match value {
101                    $(MessageType::$message_name => $message_flag,)*
102                    MessageType::Unknown(v) => v
103                }
104            }
105        }
106
107        impl std::convert::From<&MessageType> for u8 {
108            fn from(value: &MessageType) -> Self {
109                match *value {
110                    $(MessageType::$message_name => $message_flag,)*
111                    MessageType::Unknown(v) => v
112                }
113            }
114        }
115
116        #[derive(binrw::BinRead, binrw::BinWrite, Clone, Debug)]
117        pub enum Message {
118            $(#[brw(magic($message_flag))]
119            $message_name($message_name)),*
120        }
121
122        impl crate::message::PureMessage for Message {}
123
124        impl From<&Message> for MessageType {
125            fn from(value: &Message) -> Self {
126                match value {
127                    $(Message::$message_name(_) => MessageType::$message_name),*
128                }
129            }
130        }
131
132        $(
133            impl TryFrom<Message> for $message_name {
134                type Error = crate::message::Error;
135
136                fn try_from(value: Message) -> Result<Self, Self::Error> {
137                    match value {
138                        Message::$message_name(v) => Ok(v),
139                        _ => Err(crate::message::Error::WrongType)
140                    }
141                }
142            }
143
144            impl<'m> TryFrom<&'m Message> for &'m $message_name {
145                type Error = crate::message::Error;
146
147                fn try_from(value: &'m Message) -> Result<Self, Self::Error> {
148                    match value {
149                        Message::$message_name(v) => Ok(v),
150                        _ => Err(crate::message::Error::WrongType)
151                    }
152                }
153            }
154            
155            impl From<$message_name> for Message {
156                fn from(value: $message_name) -> Self {
157                    Message::$message_name(value)
158                }
159            }
160
161            impl $message_name {
162                pub fn into_message(self) -> Message { 
163                    self.into() 
164                } 
165            }
166        )*
167    };
168}
169
170mod test {
171    #![allow(unused_imports)]
172
173    use std::io::Cursor;
174    use binrw::BinRead;
175    use binrw::BinWrite;
176
177    use crate::message::client_to_server::HandResult;
178    use crate::message::client_to_server::JoinGame;
179    use crate::message::client_to_server::MessageType;
180    use crate::message::client_to_server::Message;
181    
182    #[test]
183    fn test_message_type_basic() {
184        let message_type = MessageType::CreateGame;
185        let mut vec = Cursor::new(Vec::<u8>::new());
186        message_type.write_le(&mut vec).unwrap();
187        assert_eq!(vec.into_inner(), [17]);
188
189        let mut vec = Cursor::new(vec![127]);
190        let message_type = MessageType::read_le(&mut vec).unwrap();
191        assert_eq!(message_type, MessageType::Unknown(127));
192    }
193
194    #[test]
195    fn test_message_enum_basic() {
196        let message_enum = Message::HandResult(HandResult {
197            res: crate::constants::Hand::Paper
198        });
199        let mut vec = Cursor::new(Vec::<u8>::new());
200        message_enum.write_le(&mut vec).unwrap(); 
201        println!("{:?}", vec.into_inner());
202    }
203}