use std::{
fmt::{self, Write},
mem::size_of,
};
use crate::variables::VariableDtype;
#[derive(Clone, Copy, Eq, Hash, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Key(pub u64);
impl Symbol for Key {}
pub trait Symbol: fmt::Debug + Into<Key> {}
pub trait TypedSymbol<V: VariableDtype>: Symbol {}
pub trait KeyFormatter {
fn fmt(f: &mut dyn Write, key: Key) -> fmt::Result;
}
const TOTAL_SIZE: usize = u64::BITS as usize;
const CHR_SIZE: usize = size_of::<char>() * 8;
const IDX_SIZE: usize = TOTAL_SIZE - CHR_SIZE;
const CHR_MASK: u64 = (char::MAX as u64) << IDX_SIZE;
const IDX_MASK: u64 = !CHR_MASK;
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DefaultSymbolHandler;
impl DefaultSymbolHandler {
pub fn sym_to_key(chr: char, idx: u32) -> Key {
Key(((chr as u64) << IDX_SIZE) | (idx as u64 & IDX_MASK))
}
pub fn key_to_sym(k: Key) -> (char, u32) {
let chr = ((k.0 & CHR_MASK) >> IDX_SIZE) as u8 as char;
let idx = (k.0 & IDX_MASK) as u32;
(chr, idx)
}
pub fn format(f: &mut dyn Write, chr: char, idx: u32) -> fmt::Result {
write!(f, "{chr}{idx}")
}
}
impl KeyFormatter for DefaultSymbolHandler {
fn fmt(f: &mut dyn Write, key: Key) -> fmt::Result {
let (chr, idx) = Self::key_to_sym(key);
Self::format(f, chr, idx)
}
}
#[macro_export]
macro_rules! assign_symbols {
($($name:ident : $($var:ident),+);* $(;)?) => {$(
assign_symbols!($name);
$(
impl $crate::containers::TypedSymbol<$var> for $name {}
)*
)*};
($($name:ident),*) => {
$(
#[derive(Clone, Copy)]
pub struct $name(pub u32);
impl From<$name> for $crate::containers::Key {
fn from(key: $name) -> $crate::containers::Key {
let chr = stringify!($name).chars().next().unwrap();
let idx = key.0;
$crate::containers::DefaultSymbolHandler::sym_to_key(chr, idx)
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let chr = stringify!($name).chars().next().unwrap();
let idx = self.0;
$crate::containers::DefaultSymbolHandler::format(f, chr, idx)
}
}
impl $crate::containers::Symbol for $name {}
)*
};
}