1#![warn(clippy::all, rust_2018_idioms)]
5
6include!(concat!(env!("OUT_DIR"), "/id_map_meta.rs"));
7
8use std::num::NonZeroU32;
9
10#[repr(align(4))]
11struct Data([u8; DATA_LEN]);
12
13impl Data {
14 #[inline]
15 fn game_ids(&self) -> &[u32] {
16 let ptr = self.0.as_ptr().cast::<u32>();
17 unsafe { std::slice::from_raw_parts(ptr, COUNT) }
18 }
19
20 #[inline]
21 fn ghids(&self) -> &[u32] {
22 let ptr = self.0.as_ptr().cast::<u32>();
23 unsafe { std::slice::from_raw_parts(ptr.add(COUNT), COUNT) }
24 }
25
26 #[inline]
27 fn title_offsets(&self) -> &[u32] {
28 let ptr = self.0.as_ptr().cast::<u32>();
29 unsafe { std::slice::from_raw_parts(ptr.add(COUNT * 2), COUNT + 1) }
30 }
31
32 #[inline]
33 fn titles(&self) -> &str {
34 let slice = unsafe { self.0.get_unchecked(COUNT * 12 + 4..DATA_LEN) };
35 unsafe { std::str::from_utf8_unchecked(slice) }
36 }
37}
38
39static DATA: Data = Data(*include_bytes!(concat!(env!("OUT_DIR"), "/id_map.bin")));
40
41#[derive(Debug, Clone, Copy)]
42#[repr(transparent)]
43pub struct GameEntry(usize);
44
45impl GameEntry {
46 #[inline]
47 pub fn lookup(id: impl AsRef<str>) -> Option<Self> {
48 let base36 = u32::from_str_radix(id.as_ref(), 36).ok()?;
49 DATA.game_ids().binary_search(&base36).ok().map(Self)
50 }
51
52 #[inline]
53 pub fn ghid(&self) -> Option<NonZeroU32> {
54 let ghid = unsafe { *DATA.ghids().get_unchecked(self.0) };
55 NonZeroU32::new(ghid)
56 }
57
58 #[inline]
59 pub fn title(&self) -> &'static str {
60 let start = unsafe { *DATA.title_offsets().get_unchecked(self.0) } as usize;
61 let end = unsafe { *DATA.title_offsets().get_unchecked(self.0 + 1) } as usize;
62 unsafe { DATA.titles().get_unchecked(start..end) }
63 }
64}