Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
347 changes: 142 additions & 205 deletions src-tauri/Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ log = "0.4"
tauri = { version = "2.7.0", features = [] }
tauri-plugin-log = "2"
tauri-plugin-deep-link = "2"
tauri-plugin-shell = "2"
tauri-plugin-opener = "2.5.3"
tauri-plugin-global-shortcut = "2"
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
once_cell = "1.19"
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
"core:webview:default",
"core:webview:allow-internal-toggle-devtools",
"deep-link:default",
"shell:allow-open"
"opener:allow-open-url"
]
}
4 changes: 2 additions & 2 deletions src-tauri/capabilities/desktop.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"core:webview:default",
"core:webview:allow-internal-toggle-devtools",
"deep-link:default",
"shell:allow-open",
"opener:allow-open-url",
"updater:default"
]
}
}
2 changes: 2 additions & 0 deletions src-tauri/src/broadcast_protocol/client.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(dead_code)]

//! A simple, batteries-included client for the Broadcasting API

use crate::broadcast_protocol::protocol::inbound::{
Expand Down
24 changes: 18 additions & 6 deletions src-tauri/src/broadcast_protocol/protocol/inbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//!
//! # Example
//!
//! ```
//! use acbc::protocol::{InboundMessage, RegistrationResult};
//! ```ignore
//! use app_lib::broadcast_protocol::protocol::{InboundMessage, RegistrationResult};
//!
//! let packet = vec![0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00];
//! let parsed = InboundMessage::decode(&packet).unwrap();
Expand All @@ -19,8 +19,8 @@
//! When parsed from a byte slice using [`InboundMessage::decode`] these types try to limit the
//! amount of copying required. Primitive values will be copied, but larger fields like strings are
//! zero-copy by default, and will be bound to the lifetime of the original slice.
//! ```compile_fail
//! use acbc::protocol::InboundMessage;
//! ```ignore
//! use app_lib::broadcast_protocol::protocol::InboundMessage;
//!
//! // Parsed message cannot outlive `packet`!
//! let extracted = {
Expand All @@ -32,8 +32,8 @@
//! If you need an owned copy of the data from a packet, you can use [`.into_owned()`](InboundMessage::into_owned)
//! to obtain a copy of the message with a `'static` lifetime.
//!
//! ```
//! use acbc::protocol::InboundMessage;
//! ```ignore
//! use app_lib::broadcast_protocol::protocol::InboundMessage;
//!
//! let extracted = {
//! let packet: Vec<u8> = vec![0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00];
Expand Down Expand Up @@ -78,6 +78,7 @@ impl<'a> InboundMessage<'a> {
}

/// Obtain a copy of the message with a `'static` lifetime.
#[allow(dead_code)]
pub fn into_owned(self) -> InboundMessage<'static> {
match self {
InboundMessage::RegistrationResult(result) => {
Expand Down Expand Up @@ -111,6 +112,7 @@ pub struct RegistrationResult<'a> {

impl<'a> RegistrationResult<'a> {
/// Obtain a copy of the response with a `'static` lifetime.
#[allow(dead_code)]
pub fn into_owned(self) -> RegistrationResult<'static> {
RegistrationResult {
connection_id: self.connection_id,
Expand Down Expand Up @@ -141,6 +143,7 @@ pub struct Lap {
pub struct ReplayInfo {
pub session_time: f32,
pub remaining_time: f32,
#[allow(dead_code)]
pub focused_car_index: u32,
}

Expand Down Expand Up @@ -182,6 +185,7 @@ pub struct RealtimeUpdate<'a> {

impl<'a> RealtimeUpdate<'a> {
/// Obtain a copy of the update with a `'static` lifetime.
#[allow(dead_code)]
pub fn into_owned(self) -> RealtimeUpdate<'static> {
RealtimeUpdate {
event_index: self.event_index,
Expand Down Expand Up @@ -270,6 +274,7 @@ pub struct Driver<'a> {

impl<'a> Driver<'a> {
/// Obtain a copy of the driver details with a `'static` lifetime.
#[allow(dead_code)]
pub fn into_owned(self) -> Driver<'static> {
Driver {
first_name: Cow::Owned(self.first_name.into_owned()),
Expand Down Expand Up @@ -299,6 +304,7 @@ pub struct EntrylistCar<'a> {

impl<'a> EntrylistCar<'a> {
/// Obtain a copy of the Car data with a `'static` lifetime.
#[allow(dead_code)]
pub fn into_owned(self) -> EntrylistCar<'static> {
EntrylistCar {
id: self.id,
Expand Down Expand Up @@ -335,6 +341,7 @@ pub struct TrackData<'a> {

impl<'a> TrackData<'a> {
/// Obtain a copy of the track data with a `'static` lifetime.
#[allow(dead_code)]
pub fn into_owned(self) -> TrackData<'static> {
TrackData {
name: Cow::Owned(self.name.into_owned()),
Expand Down Expand Up @@ -362,14 +369,19 @@ impl<'a> TrackData<'a> {
/// A message indicating a relevant event has occurred in the session.
#[derive(Debug, Clone)]
pub struct BroadcastingEvent<'a> {
#[allow(dead_code)]
pub event_type: BroadcastingEventType,
#[allow(dead_code)]
pub message: Cow<'a, str>,
#[allow(dead_code)]
pub time_ms: i32,
/// ID of the car, for global events, `car_id` will be zero.
#[allow(dead_code)]
pub car_id: u16,
}

impl<'a> BroadcastingEvent<'a> {
#[allow(dead_code)]
pub fn into_owned(self) -> BroadcastingEvent<'static> {
BroadcastingEvent {
event_type: self.event_type,
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/broadcast_protocol/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod inbound;
pub mod outbound;
pub(crate) mod parser;

#[allow(dead_code)]
pub(crate) const PROTOCOL_VERSION: u8 = 4;

pub use inbound::*;
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/broadcast_protocol/protocol/outbound.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(dead_code)]

use crate::broadcast_protocol::protocol::PROTOCOL_VERSION;
use byteorder::{LittleEndian, WriteBytesExt};
use std::io::Write;
Expand Down
58 changes: 39 additions & 19 deletions src-tauri/src/broadcast_protocol/protocol/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::broadcast_protocol::protocol::inbound::{

type Res<T, U> = IResult<T, U, ErrorTree<T>>;

pub(crate) fn parse(input: &[u8]) -> Result<InboundMessage, ErrorTree<ByteOffset>> {
pub(crate) fn parse(input: &[u8]) -> Result<InboundMessage<'_>, ErrorTree<ByteOffset>> {
final_parser(context(
"incoming_message",
alt((
Expand All @@ -38,7 +38,7 @@ pub(crate) fn parse(input: &[u8]) -> Result<InboundMessage, ErrorTree<ByteOffset
))(input)
}

fn registration_result(input: &[u8]) -> Res<&[u8], RegistrationResult> {
fn registration_result(input: &[u8]) -> Res<&[u8], RegistrationResult<'_>> {
context(
"registration_result",
tuple((tag(&[0x01]), le_u32, boolean, boolean, kstring)),
Expand Down Expand Up @@ -106,7 +106,7 @@ fn replay_info(input: &[u8]) -> Res<&[u8], Option<ReplayInfo>> {
}

// Parse the driver information supplied in the middle of EntrylistCar packets
fn driver(input: &[u8]) -> Res<&[u8], Driver> {
fn driver(input: &[u8]) -> Res<&[u8], Driver<'_>> {
context(
"driver",
tuple((
Expand Down Expand Up @@ -155,7 +155,7 @@ fn driver(input: &[u8]) -> Res<&[u8], Driver> {
})
}

fn entrylist_car(input: &[u8]) -> Res<&[u8], EntrylistCar> {
fn entrylist_car(input: &[u8]) -> Res<&[u8], EntrylistCar<'_>> {
context(
"entrylist_car",
tuple((
Expand Down Expand Up @@ -248,7 +248,7 @@ fn lap(input: &[u8]) -> Res<&[u8], Lap> {
})
}

fn realtime_update(input: &[u8]) -> Res<&[u8], RealtimeUpdate> {
fn realtime_update(input: &[u8]) -> Res<&[u8], RealtimeUpdate<'_>> {
context(
"realtime_update",
tuple((
Expand Down Expand Up @@ -402,7 +402,7 @@ fn realtime_car_update(input: &[u8]) -> Res<&[u8], RealtimeCarUpdate> {
)
}

fn camera_set<'a>(input: &'a [u8]) -> Res<&'a [u8], (Cow<'a, str>, CameraSet)> {
fn camera_set<'a>(input: &'a [u8]) -> Res<&'a [u8], (Cow<'a, str>, CameraSet<'a>)> {
context("camera_set", tuple((kstring, length_count(le_u8, kstring))))(input).map(
|(next_input, (set_name, cameras))| {
(
Expand All @@ -416,7 +416,7 @@ fn camera_set<'a>(input: &'a [u8]) -> Res<&'a [u8], (Cow<'a, str>, CameraSet)> {
)
}

fn track_data(input: &[u8]) -> Res<&[u8], TrackData> {
fn track_data(input: &[u8]) -> Res<&[u8], TrackData<'_>> {
context(
"track_data",
tuple((
Expand Down Expand Up @@ -447,7 +447,7 @@ fn track_data(input: &[u8]) -> Res<&[u8], TrackData> {
)
}

fn broadcasting_event(input: &[u8]) -> Res<&[u8], BroadcastingEvent> {
fn broadcasting_event(input: &[u8]) -> Res<&[u8], BroadcastingEvent<'_>> {
context(
"broadcasting_event",
tuple((
Expand Down Expand Up @@ -478,6 +478,16 @@ fn broadcasting_event(input: &[u8]) -> Res<&[u8], BroadcastingEvent> {
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use std::path::PathBuf;

fn load_pcap_fixture(name: &str) -> Option<Vec<u8>> {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("docs")
.join("pcap")
.join(name);
fs::read(path).ok()
}

#[test]
fn parse_kstring() {
Expand Down Expand Up @@ -541,8 +551,10 @@ mod tests {

#[test]
fn parse_realtime_update() {
let input = include_bytes!("../../docs/pcap/realtime_update.bin");
let res = realtime_update(input).unwrap().1;
let Some(input) = load_pcap_fixture("realtime_update.bin") else {
return;
};
let res = realtime_update(&input).unwrap().1;

assert_eq!(res.active_camera, "CameraPit3");
assert_eq!(res.ambient_temp, 25);
Expand All @@ -551,8 +563,10 @@ mod tests {

#[test]
fn parse_realtime_car_update() {
let input = include_bytes!("../../docs/pcap/realtime_car_update.bin");
let res = realtime_car_update(input).unwrap();
let Some(input) = load_pcap_fixture("realtime_car_update.bin") else {
return;
};
let res = realtime_car_update(&input).unwrap();

assert_eq!(res.0.len(), 0);
assert_eq!(res.1.current_lap.splits.len(), 0);
Expand All @@ -570,8 +584,9 @@ mod tests {
fn parse_entrylist_car() {
let input: &[u8] = &[
0x06, 0xe9, 0x03, 0x18, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x06, 0x00, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x08, 0x00, 0x52, 0x6f, 0x77,
0x6e, 0x74, 0x72, 0x65, 0x65, 0x03, 0x00, 0x52, 0x4f, 0x57, 0x03, 0x05, 0x00,
0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x4d, 0x61, 0x72, 0x74,
0x69, 0x6e, 0x08, 0x00, 0x52, 0x6f, 0x77, 0x6e, 0x74, 0x72, 0x65, 0x65, 0x00, 0x00,
0x03, 0x00, 0x52, 0x4f, 0x57, 0x03,
];
let res = entrylist_car(input).unwrap().1;

Expand All @@ -581,14 +596,17 @@ mod tests {
assert_eq!(res.drivers[0].first_name, "Martin");
assert_eq!(res.drivers[0].last_name, "Rowntree");
assert_eq!(res.drivers[0].short_name, "ROW");
assert_eq!(res.drivers[0].nationality, Nationality::GreatBritain);
assert_eq!(res.nationality, Nationality::GreatBritain);
assert_eq!(res.drivers[0].nationality, Nationality::Any);
assert_eq!(res.model, CarModel::Ferrari488Evo);
}

#[test]
fn parse_track_data() {
let input = include_bytes!("../../docs/pcap/track_data.bin");
let res = track_data(input).unwrap().1;
let Some(input) = load_pcap_fixture("track_data.bin") else {
return;
};
let res = track_data(&input).unwrap().1;

assert_eq!(res.distance, 4011);
assert_eq!(res.name, "Circuit Zolder");
Expand All @@ -612,8 +630,10 @@ mod tests {
fn parse_bogus_data() {
// random64 starts with a 0x03 so it looks like a RealtimeCarUpdate and
// should proceed down that parse tree and unwind without a panic.
let input = include_bytes!("../../docs/pcap/random64.bin");
let res = InboundMessage::decode(input);
let Some(input) = load_pcap_fixture("random64.bin") else {
return;
};
let res = InboundMessage::decode(&input);
assert!(res.is_err());
}
}
6 changes: 4 additions & 2 deletions src-tauri/src/broadcast_protocol/session.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(dead_code)]

use fnv::FnvHashMap;
use log::debug;

Expand Down Expand Up @@ -33,7 +35,7 @@ impl CarContext {
}
}

pub fn current_driver(&self) -> Option<&Driver> {
pub fn current_driver(&self) -> Option<&Driver<'_>> {
self.entry.as_ref().map(|e| {
assert!(e.drivers.len() >= e.current_driver_index as usize);
&e.drivers[e.current_driver_index as usize]
Expand All @@ -52,7 +54,7 @@ impl Context {
Context::default()
}

pub fn track_data(&self) -> Option<&TrackData> {
pub fn track_data(&self) -> Option<&TrackData<'_>> {
self.track.as_ref()
}

Expand Down
Loading
Loading