f1_api/
packet.rs

1//! Packets that are sent by modern F1 games
2//!
3//! This library implements a single packet format for all the F1 games it supports. The API
4//! specification has been slowly evolving from game to game, but without such significant changes
5//! that it would require a different packet format.
6
7use std::io::{Cursor, Error, ErrorKind};
8
9use bytes::{Buf, BytesMut};
10
11pub mod event;
12pub mod header;
13pub mod lap;
14pub mod motion;
15pub mod participants;
16pub mod session;
17pub mod setup;
18pub mod status;
19pub mod telemetry;
20
21/// A packet published by an F1 game.
22///
23/// The F1 games publish different packets with different data at different intervals. Each of these
24/// packets is decoded from UDP to their respective representation in this Rust crate. The `Packet`
25/// enum lists all packets that can be expected, and that a client should handle.
26#[derive(Debug, PartialEq, Clone, PartialOrd)]
27pub enum Packet {
28    /// The F1 games send event packets whenever certain events occur in a session. Some event
29    /// packets carry a payload with more information about the event.
30    Event(event::EventPacket),
31
32    /// Lap data packets provide information about each car in a session, and are sent at an
33    /// interval that can be configured in the game.
34    Lap(lap::LapPacket),
35
36    /// The motion data packet describes the movement and position of each car in the session, with
37    /// additional details being provided for the player's car.
38    Motion(motion::MotionPacket),
39
40    /// Packet with information on all participants in the session, for example their name, team,
41    /// and nationality.
42    Participants(participants::ParticipantsPacket),
43
44    /// The F1 games provide information about the current session on a regular basis.
45    Session(session::SessionPacket),
46
47    /// Car setup packets publish the setup of each car in the session. In multiplayer sessions, the
48    /// setups of other player's cars are redacted to enable a fair competition.
49    Setup(setup::CarSetupPacket),
50
51    /// The F1 games send packets with data about the status of each car in a session at a
52    /// configurable interval.
53    Status(status::CarStatusPacket),
54
55    /// Telemetry data is provided for all cars in the session.
56    Telemetry(telemetry::TelemetryPacket),
57}
58
59/// Ensure a packet has the expected size
60///
61/// Modern F1 games send their packets over UDP. Depending on their size, these packets might be
62/// split into multiple UDP fragments. The decoder collects these fragments, and asks the codec if
63/// enough data has been received to decode a packet.
64///
65/// The sizes of the packets sent by F1 games are part of the API specification, and can be used to
66/// determine if a full packet has ben received. This function takes a cursor to the raw data and
67/// the expected size of the packet, and returns an error if not enough data is ready to decode the
68/// complete packet.
69pub(crate) fn ensure_packet_size(
70    expected_size: usize,
71    cursor: &mut Cursor<&mut BytesMut>,
72) -> Result<(), Error> {
73    if cursor.remaining() < expected_size {
74        Err(Error::new(
75            ErrorKind::UnexpectedEof,
76            format!(
77                "Packet is expected to have a size of {} bytes, but was {}.",
78                expected_size,
79                cursor.remaining()
80            ),
81        ))
82    } else {
83        Ok(())
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use std::io::{Cursor, Error};
90
91    use bytes::{Buf, BufMut, BytesMut};
92
93    use crate::packet::ensure_packet_size;
94
95    struct Packet {
96        counter: u8,
97    }
98
99    const PACKET_SIZE: usize = 1;
100
101    fn decode_packet(cursor: &mut Cursor<&mut BytesMut>) -> Result<Packet, Error> {
102        ensure_packet_size(PACKET_SIZE, cursor)?;
103
104        Ok(Packet {
105            counter: cursor.get_u8(),
106        })
107    }
108
109    #[test]
110    fn ensure_packet_size_correctly() {
111        let mut bytes = BytesMut::with_capacity(1);
112        bytes.put_u8(0);
113
114        let mut cursor = Cursor::new(&mut bytes);
115
116        let packet = decode_packet(&mut cursor).unwrap();
117        assert_eq!(0, packet.counter);
118    }
119
120    #[test]
121    fn ensure_packet_size_with_error() {
122        let mut bytes = BytesMut::with_capacity(0);
123        let mut cursor = Cursor::new(&mut bytes);
124
125        let packet = decode_packet(&mut cursor);
126        assert!(packet.is_err());
127    }
128}