1#![warn(clippy::all, rust_2018_idioms)]
5
6include!(concat!(env!("OUT_DIR"), "/id_map_meta.rs"));
7
8#[repr(C)]
9struct Data {
10 pub game_ids: [u32; COUNT],
11 pub ghids: [u32; COUNT],
12 pub title_offsets: [u32; COUNT + 1],
13 pub titles: [u8; TITLES_LEN],
14}
15
16#[cfg(not(feature = "compress"))]
17static DATA: Data = {
18 let bytes = *include_bytes!(concat!(env!("OUT_DIR"), "/id_map.bin"));
19 unsafe { std::mem::transmute(bytes) }
20};
21
22#[cfg(feature = "compress")]
23static DATA: std::sync::LazyLock<Box<Data>> = std::sync::LazyLock::new(|| {
24 let compressed = include_bytes!(concat!(env!("OUT_DIR"), "/id_map.bin"));
25
26 let mut buf = Box::<Data>::new_uninit();
27
28 let ptr = buf.as_mut_ptr().cast::<u8>();
30 let slice = unsafe { std::slice::from_raw_parts_mut(ptr, std::mem::size_of::<Data>()) };
31 let it = std::iter::once(compressed.as_slice());
32 miniz_oxide::inflate::decompress_slice_iter_to_slice(slice, it, false, true).unwrap();
33
34 unsafe { buf.assume_init() }
35});
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38#[repr(transparent)]
39pub struct GameEntry(usize);
40
41impl GameEntry {
42 #[inline]
43 pub fn lookup(id: impl AsRef<str>) -> Option<Self> {
44 let base36 = u32::from_str_radix(id.as_ref(), 36).ok()?;
45 DATA.game_ids.binary_search(&base36).ok().map(Self)
46 }
47
48 #[inline]
49 pub fn ghid(&self) -> Option<u32> {
50 let ghid = unsafe { *DATA.ghids.get_unchecked(self.0) };
51 (ghid > 0).then_some(ghid)
52 }
53
54 #[inline]
55 pub fn title(&self) -> &'static str {
56 let start = unsafe { *DATA.title_offsets.get_unchecked(self.0) } as usize;
57 let end = unsafe { *DATA.title_offsets.get_unchecked(self.0 + 1) } as usize;
58 let slice = unsafe { DATA.titles.get_unchecked(start..end) };
59 unsafe { std::str::from_utf8_unchecked(slice) }
60 }
61}