1#![allow(
21 clippy::doc_markdown,
22 clippy::exhaustive_enums,
23 clippy::must_use_candidate,
24 clippy::missing_errors_doc
25)]
26#![cfg_attr(
27 test,
28 allow(
29 clippy::assertions_on_result_states,
30 clippy::indexing_slicing,
31 clippy::missing_asserts_for_indexing,
32 clippy::panic,
33 clippy::unwrap_used,
34 )
35)]
36
37pub use crate::error::{Error, MoreDataNeeded, ParsingErrorKind};
38pub use crate::game_id::GameId;
39pub use crate::plugin::{plugins_metadata, ParseOptions, Plugin, PluginMetadata};
40
41mod error;
42mod game_id;
43mod group;
44mod plugin;
45mod record;
46mod record_id;
47mod subrecord;
48
49struct SliceTooSmallError;
51
52fn le_slice_to_u32(input: &[u8]) -> Result<u32, SliceTooSmallError> {
53 const ARRAY_SIZE: usize = std::mem::size_of::<u32>();
54
55 subarray::<ARRAY_SIZE>(input, 0).map(u32::from_le_bytes)
56}
57
58fn le_slice_to_f32(input: &[u8]) -> Result<f32, SliceTooSmallError> {
59 const ARRAY_SIZE: usize = std::mem::size_of::<f32>();
60
61 subarray::<ARRAY_SIZE>(input, 0).map(f32::from_le_bytes)
62}
63
64fn subarray<const SIZE: usize>(
65 bytes: &[u8],
66 start_index: usize,
67) -> Result<[u8; SIZE], SliceTooSmallError> {
68 let stop_index = start_index + SIZE;
69
70 let bytes = bytes
71 .get(start_index..stop_index)
72 .ok_or(SliceTooSmallError)?;
73
74 <[u8; SIZE]>::try_from(bytes).map_err(|_e| SliceTooSmallError)
75}
76
77#[expect(
78 clippy::as_conversions,
79 reason = "A compile-time assertion ensures that this conversion will be lossless on all relevant target platforms"
80)]
81const fn u32_to_usize(input: u32) -> usize {
82 const _: () = assert!(u32::BITS <= usize::BITS, "cannot fit a u32 into a usize!");
84 input as usize
85}