1use std::io::{Cursor, Error, ErrorKind};
7use std::time::Duration;
8
9use bytes::{Buf, BytesMut};
10
11use crate::nineteen::flag::decode_flag;
12use crate::nineteen::header::decode_header;
13use crate::packet::ensure_packet_size;
14use crate::packet::session::{
15 Formula, MarshalZone, SafetyCar, Session, SessionPacket, Track, Weather,
16};
17
18pub const PACKET_SIZE: usize = 149;
20
21pub fn decode_session(cursor: &mut Cursor<&mut BytesMut>) -> Result<SessionPacket, Error> {
26 ensure_packet_size(PACKET_SIZE, cursor)?;
27
28 let header = decode_header(cursor)?;
29
30 let weather = decode_weather(cursor)?;
31 let track_temperature = cursor.get_i8();
32 let air_temperature = cursor.get_i8();
33 let total_laps = cursor.get_u8();
34 let track_length = cursor.get_u16_le();
35 let session_type = decode_session_type(cursor)?;
36 let track = decode_track(cursor)?;
37 let formula = decode_formula(cursor)?;
38 let time_left = Duration::from_secs(cursor.get_u16_le() as u64);
39 let duration = Duration::from_secs(cursor.get_u16_le() as u64);
40 let pit_speed_limit = cursor.get_u8();
41 let game_paused = cursor.get_u8() > 0;
42 let is_spectating = cursor.get_u8() > 0;
43 let spectator_car_index = cursor.get_u8();
44 let sli_pro_support = cursor.get_u8() > 0;
45
46 let marshal_zone_count = cursor.get_u8();
47 let mut marshal_zones = Vec::with_capacity(marshal_zone_count as usize);
48
49 for _ in 0..marshal_zone_count {
50 marshal_zones.push(MarshalZone::new(cursor.get_f32_le(), decode_flag(cursor)?));
51 }
52
53 let safety_car = decode_safety_car(cursor)?;
54 let network_session = cursor.get_u8() > 0;
55
56 Ok(SessionPacket::new(
57 header,
58 weather,
59 track_temperature,
60 air_temperature,
61 total_laps,
62 track_length,
63 session_type,
64 track,
65 formula,
66 time_left,
67 duration,
68 pit_speed_limit,
69 game_paused,
70 is_spectating,
71 spectator_car_index,
72 sli_pro_support,
73 marshal_zones,
74 safety_car,
75 network_session,
76 ))
77}
78
79fn decode_weather(cursor: &mut Cursor<&mut BytesMut>) -> Result<Weather, Error> {
80 let value = cursor.get_u8();
81
82 match value {
83 0 => Ok(Weather::Clear),
84 1 => Ok(Weather::LightCloud),
85 2 => Ok(Weather::Overcast),
86 3 => Ok(Weather::LightRain),
87 4 => Ok(Weather::HeavyRain),
88 5 => Ok(Weather::Storm),
89 _ => Err(Error::new(
90 ErrorKind::InvalidData,
91 "Failed to decode weather.",
92 )),
93 }
94}
95
96fn decode_session_type(cursor: &mut Cursor<&mut BytesMut>) -> Result<Session, Error> {
97 let value = cursor.get_u8();
98
99 match value {
100 0 => Ok(Session::Unknown),
101 1 => Ok(Session::P1),
102 2 => Ok(Session::P2),
103 3 => Ok(Session::P3),
104 4 => Ok(Session::ShortPractice),
105 5 => Ok(Session::Q1),
106 6 => Ok(Session::Q2),
107 7 => Ok(Session::Q3),
108 8 => Ok(Session::ShortQualifying),
109 9 => Ok(Session::OneShotQualifying),
110 10 => Ok(Session::Race),
111 11 => Ok(Session::Race2),
112 12 => Ok(Session::TimeTrial),
113 _ => Err(Error::new(
114 ErrorKind::InvalidData,
115 "Failed to decode session.",
116 )),
117 }
118}
119
120fn decode_track(cursor: &mut Cursor<&mut BytesMut>) -> Result<Track, Error> {
121 let value = cursor.get_i8();
122
123 match value {
124 -1 => Ok(Track::Unknown),
125 0 => Ok(Track::Melbourne),
126 1 => Ok(Track::PaulRicard),
127 2 => Ok(Track::Shanghai),
128 3 => Ok(Track::Bahrain),
129 4 => Ok(Track::Catalunya),
130 5 => Ok(Track::Monaco),
131 6 => Ok(Track::Montreal),
132 7 => Ok(Track::Silverstone),
133 8 => Ok(Track::Hockenheim),
134 9 => Ok(Track::Hungaroring),
135 10 => Ok(Track::Spa),
136 11 => Ok(Track::Monza),
137 12 => Ok(Track::Singapore),
138 13 => Ok(Track::Suzuka),
139 14 => Ok(Track::AbuDhabi),
140 15 => Ok(Track::Texas),
141 16 => Ok(Track::Brazil),
142 17 => Ok(Track::Austria),
143 18 => Ok(Track::Sochi),
144 19 => Ok(Track::Mexico),
145 20 => Ok(Track::Azerbaijan),
146 21 => Ok(Track::BahrainShort),
147 22 => Ok(Track::SilverstoneShort),
148 23 => Ok(Track::TexasShort),
149 24 => Ok(Track::SuzukaShort),
150 _ => Err(Error::new(
151 ErrorKind::InvalidData,
152 "Failed to decode track.",
153 )),
154 }
155}
156
157fn decode_formula(cursor: &mut Cursor<&mut BytesMut>) -> Result<Formula, Error> {
158 let value = cursor.get_u8();
159
160 match value {
161 0 => Ok(Formula::ModernF1),
162 1 => Ok(Formula::ClassicF1),
163 2 => Ok(Formula::F2),
164 3 => Ok(Formula::GenericF1),
165 _ => Err(Error::new(
166 ErrorKind::InvalidData,
167 "Failed to decode formula.",
168 )),
169 }
170}
171
172fn decode_safety_car(cursor: &mut Cursor<&mut BytesMut>) -> Result<SafetyCar, Error> {
173 let value = cursor.get_u8();
174
175 match value {
176 0 => Ok(SafetyCar::None),
177 1 => Ok(SafetyCar::Full),
178 2 => Ok(SafetyCar::Virtual),
179 _ => Err(Error::new(
180 ErrorKind::InvalidData,
181 "Failed to decode safety car.",
182 )),
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use std::io::Cursor;
189
190 use bytes::{BufMut, BytesMut};
191
192 use crate::nineteen::session::{decode_session, PACKET_SIZE};
193 use crate::packet::session::{Formula, SafetyCar, Session, Track, Weather};
194
195 fn put_packet_header(mut bytes: BytesMut) -> BytesMut {
196 bytes.put_u16_le(2019);
197 bytes.put_u8(1);
198 bytes.put_u8(2);
199 bytes.put_u8(3);
200 bytes.put_u8(1);
201 bytes.put_u64_le(u64::max_value());
202 bytes.put_f32_le(1.0);
203 bytes.put_u32_le(u32::max_value());
204 bytes.put_u8(0);
205
206 bytes
207 }
208
209 #[test]
210 fn decode_session_with_error() {
211 let mut bytes = BytesMut::with_capacity(0);
212 let mut cursor = Cursor::new(&mut bytes);
213
214 let packet = decode_session(&mut cursor);
215 assert!(packet.is_err());
216 }
217
218 #[test]
219 fn decode_session_with_success() {
220 let mut bytes = BytesMut::with_capacity(PACKET_SIZE);
221 bytes = put_packet_header(bytes);
222
223 bytes.put_u8(1);
224 bytes.put_i8(2);
225 bytes.put_i8(3);
226 bytes.put_u8(4);
227 bytes.put_u16_le(5);
228 bytes.put_u8(6);
229 bytes.put_i8(7);
230 bytes.put_u8(2);
231 bytes.put_u16_le(9);
232 bytes.put_u16_le(10);
233 bytes.put_u8(11);
234 bytes.put_u8(1);
235 bytes.put_u8(1);
236 bytes.put_u8(14);
237 bytes.put_u8(1);
238 bytes.put_u8(21);
239
240 for i in 0..21 {
241 bytes.put_f32_le(i as f32);
242 bytes.put_i8((i % 6) - 1);
243 }
244
245 bytes.put_u8(1);
246 bytes.put_u8(1);
247
248 let mut cursor = Cursor::new(&mut bytes);
249
250 let packet = decode_session(&mut cursor).unwrap();
251
252 assert_eq!(Weather::LightCloud, packet.weather());
253 assert_eq!(2, packet.track_temperature());
254 assert_eq!(3, packet.air_temperature());
255 assert_eq!(4, packet.total_laps());
256 assert_eq!(5, packet.track_length());
257 assert_eq!(Session::Q2, packet.session_type());
258 assert_eq!(Track::Silverstone, packet.track());
259 assert_eq!(Formula::F2, packet.formula());
260 assert_eq!(9, packet.time_left().as_secs());
261 assert_eq!(10, packet.duration().as_secs());
262 assert_eq!(11, packet.pit_speed_limit());
263 assert!(packet.game_paused());
264 assert!(packet.is_spectating());
265 assert_eq!(14, packet.spectator_car_index());
266 assert!(packet.sli_pro_support());
267 assert_eq!(21, packet.marshal_zones().len());
268 assert_eq!(SafetyCar::Full, packet.safety_car());
269 assert!(packet.network_session());
270 }
271}