livesplit-core 0.13.0

livesplit-core is a library that provides a lot of functionality for creating a speedrun timer.
Documentation
use core::mem;

use crate::{
    platform::prelude::*,
    util::byte_parsing::{big_endian::U16, pod, slice},
};
use bytemuck::{Pod, Zeroable};

#[derive(Debug, Copy, Clone, Pod, Zeroable)]
#[repr(C)]
struct Header {
    version: U16,
    count: U16,
    storage_offset: U16,
}

#[derive(Debug, Copy, Clone, Pod, Zeroable)]
#[repr(C)]
pub struct NameRecord {
    platform_id: U16,
    encoding_id: U16,
    language_id: U16,
    name_id: U16,
    length: U16,
    string_offset: U16,
}

impl NameRecord {
    fn get_name(&self, storage: &[u8]) -> Option<String> {
        let name = storage
            .get(self.string_offset.usize()..)?
            .get(..self.length.usize())?;

        let mut buf = Vec::new();
        let slice: &[[u8; 2]] = bytemuck::try_cast_slice(name).ok()?;
        for &c in slice {
            buf.push(u16::from_be_bytes(c));
        }

        String::from_utf16(&buf).ok()
    }
}

const fn is_unicode_encoding(platform_id: u16, encoding_id: u16) -> bool {
    match platform_id {
        0 => true,
        3 => matches!(encoding_id, 0 | 1),
        _ => false,
    }
}

pub fn look_up_family_name(table: &[u8]) -> Option<String> {
    let header = pod::<Header>(table)?;
    let records =
        slice::<NameRecord>(table.get(mem::size_of::<Header>()..)?, header.count.usize())?;

    let font_family = 1u16.to_be_bytes();
    let typographic_family = 16u16.to_be_bytes();

    let record = records
        .iter()
        .filter(|r| r.name_id.0 == font_family || r.name_id.0 == typographic_family)
        .filter(|r| is_unicode_encoding(r.platform_id.get(), r.encoding_id.get()))
        .filter(|r| match r.platform_id.get() {
            0 => true,
            1 => r.language_id.get() == 0,
            3 => r.language_id.get() & 0xFF == 0x09,
            _ => false,
        })
        .max_by_key(|r| (r.name_id.0, !r.platform_id.get()))?;

    let storage = table.get(header.storage_offset.usize()..)?;
    record.get_name(storage)
}