Tempoary (!!!) workaround for incorrect key combination description in frontend
This workaround fixes the incorrect string while preserving translations and the 1.0.0 string freeze.
Remember to revert this commit and fix the string in binds.cpp after the 1.0.0 release!
use fpnum::FPNum;
use std::{
collections::BinaryHeap,
num::NonZeroU16,
ops::{Add, Index, IndexMut},
};
pub type GearId = NonZeroU16;
pub trait GearData {}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Millis(u32);
impl Millis {
#[inline]
pub fn new(value: u32) -> Self {
Self(value)
}
#[inline]
pub fn get(self) -> u32 {
self.0
}
#[inline]
pub fn to_fixed(self) -> FPNum {
FPNum::new(self.0 as i32, 1000)
}
}
impl Add for Millis {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
pub trait GearDataProcessor<T: GearData> {
fn add(&mut self, gear_id: GearId, gear_data: T);
fn remove(&mut self, gear_id: GearId);
fn get(&mut self, gear_id: GearId) -> Option<T>;
}
pub trait GearDataAggregator<T: GearData> {
fn find_processor(&mut self) -> &mut GearDataProcessor<T>;
}
pub struct GearAllocator {
max_id: u16,
free_ids: BinaryHeap<GearId>,
}
impl GearAllocator {
pub fn new() -> Self {
Self {
max_id: 0,
free_ids: BinaryHeap::with_capacity(1024),
}
}
pub fn alloc(&mut self) -> Option<GearId> {
self.free_ids.pop().or_else(|| {
self.max_id.checked_add(1).and_then(|new_max_id| {
self.max_id = new_max_id;
NonZeroU16::new(new_max_id)
})
})
}
pub fn free(&mut self, gear_id: GearId) {
self.free_ids.push(gear_id)
}
}
#[derive(Clone, Copy, Default)]
pub struct LookupEntry<T> {
index: Option<NonZeroU16>,
value: T,
}
impl<T> LookupEntry<T> {
#[inline]
pub fn index(&self) -> u16 {
self.index.map(|i| i.get()).unwrap_or(0) - 1
}
#[inline]
pub fn set_index(&mut self, index: u16) {
self.index = unsafe { Some(NonZeroU16::new_unchecked(index.saturating_add(1))) };
}
#[inline]
pub fn value(&self) -> &T {
&self.value
}
#[inline]
pub fn value_mut(&mut self) -> &mut T {
&mut self.value
}
#[inline]
pub fn set_value(&mut self, value: T) {
self.value = value;
}
}
pub struct GearDataLookup<T> {
lookup: Box<[LookupEntry<T>]>,
}
impl<T: Default + Copy> GearDataLookup<T> {
pub fn new() -> Self {
Self {
lookup: vec![LookupEntry::default(); u16::max_value() as usize].into_boxed_slice(),
}
}
}
impl<T> GearDataLookup<T> {
pub fn add(&mut self, gear_id: GearId, index: u16, value: T) {
// All possible Gear IDs are valid indices
let entry = unsafe { self.lookup.get_unchecked_mut(gear_id.get() as usize - 1) };
entry.set_index(index);
entry.set_value(value);
}
pub fn get(&self, gear_id: GearId) -> Option<&LookupEntry<T>> {
// All possible Gear IDs are valid indices
let entry = unsafe { self.lookup.get_unchecked(gear_id.get() as usize - 1) };
if let Some(index) = entry.index {
Some(entry)
} else {
None
}
}
pub fn get_mut(&mut self, gear_id: GearId) -> Option<&mut LookupEntry<T>> {
// All possible Gear IDs are valid indices
let entry = unsafe { self.lookup.get_unchecked_mut(gear_id.get() as usize - 1) };
if let Some(index) = entry.index {
Some(entry)
} else {
None
}
}
}
impl<T> Index<GearId> for GearDataLookup<T> {
type Output = LookupEntry<T>;
fn index(&self, index: GearId) -> &Self::Output {
self.get(index).unwrap()
}
}
impl<T> IndexMut<GearId> for GearDataLookup<T> {
fn index_mut(&mut self, index: GearId) -> &mut Self::Output {
self.get_mut(index).unwrap()
}
}