use super::Sysno;
use crate::SysnoSet;
use crate::set::SysnoSetIter;
use core::fmt;
use core::mem::MaybeUninit;
type DataArray<T> = [MaybeUninit<T>; Sysno::table_size()];
pub struct SysnoMap<T> {
is_set: SysnoSet,
data: DataArray<T>,
}
#[inline]
const fn get_idx(sysno: Sysno) -> usize {
(sysno.id() as usize) - (Sysno::first().id() as usize)
}
impl<T> Default for SysnoMap<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> SysnoMap<T> {
pub const fn new() -> Self {
Self {
is_set: SysnoSet::empty(),
data: unsafe { MaybeUninit::uninit().assume_init() },
}
}
pub const fn contains_key(&self, sysno: Sysno) -> bool {
self.is_set.contains(sysno)
}
pub fn clear(&mut self) {
for sysno in &self.is_set {
unsafe { self.data[get_idx(sysno)].assume_init_drop() }
}
self.is_set.clear();
}
pub fn is_empty(&self) -> bool {
self.is_set.is_empty()
}
pub fn count(&self) -> usize {
self.is_set.count()
}
pub fn insert(&mut self, sysno: Sysno, value: T) -> Option<T> {
let uninit = &mut self.data[get_idx(sysno)];
if self.is_set.insert(sysno) {
uninit.write(value);
None
} else {
let old = core::mem::replace(uninit, MaybeUninit::new(value));
Some(unsafe { old.assume_init() })
}
}
pub fn remove(&mut self, sysno: Sysno) -> Option<T> {
if self.is_set.remove(sysno) {
let old = core::mem::replace(
&mut self.data[get_idx(sysno)],
MaybeUninit::uninit(),
);
Some(unsafe { old.assume_init() })
} else {
None
}
}
pub fn get(&self, sysno: Sysno) -> Option<&T> {
if self.is_set.contains(sysno) {
Some(unsafe { self.data[get_idx(sysno)].assume_init_ref() })
} else {
None
}
}
pub fn get_mut(&mut self, sysno: Sysno) -> Option<&mut T> {
if self.is_set.contains(sysno) {
Some(unsafe { self.data[get_idx(sysno)].assume_init_mut() })
} else {
None
}
}
pub fn iter(&self) -> SysnoMapIter<'_, T> {
SysnoMapIter {
iter: self.is_set.iter(),
data: &self.data,
}
}
pub fn values(&self) -> SysnoMapValues<'_, T> {
SysnoMapValues(self.is_set.iter(), &self.data)
}
}
impl<T: Copy> SysnoMap<T> {
pub const fn from_slice(slice: &[(Sysno, T)]) -> Self {
let mut data: DataArray<T> =
unsafe { MaybeUninit::uninit().assume_init() };
let mut is_set = SysnoSet::empty();
let mut i = 0;
while i < slice.len() {
let sysno = slice[i].0;
let (idx, mask) = SysnoSet::get_idx_mask(sysno);
is_set.data[idx] |= mask;
data[get_idx(sysno)] = MaybeUninit::new(slice[i].1);
i += 1;
}
Self { is_set, data }
}
}
impl<T: Clone> SysnoMap<T> {
pub fn init_all(default: &T) -> Self {
SysnoSet::all()
.iter()
.map(|v| (v, default.clone()))
.collect()
}
}
impl<T> Drop for SysnoMap<T> {
fn drop(&mut self) {
self.clear();
}
}
pub struct SysnoMapIter<'a, T> {
iter: SysnoSetIter<'a>,
data: &'a DataArray<T>,
}
impl<'a, T> Iterator for SysnoMapIter<'a, T> {
type Item = (Sysno, &'a T);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|sysno| {
let value = unsafe { self.data[get_idx(sysno)].assume_init_ref() };
(sysno, value)
})
}
}
pub struct SysnoMapValues<'a, T>(SysnoSetIter<'a>, &'a DataArray<T>);
impl<'a, T> Iterator for SysnoMapValues<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0
.next()
.map(|sysno| unsafe { self.1[get_idx(sysno)].assume_init_ref() })
}
}
impl<T: fmt::Debug> fmt::Debug for SysnoMap<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
impl<T> Extend<(Sysno, T)> for SysnoMap<T> {
fn extend<I: IntoIterator<Item = (Sysno, T)>>(&mut self, iter: I) {
for (sysno, value) in iter {
self.insert(sysno, value);
}
}
}
impl<T> FromIterator<(Sysno, T)> for SysnoMap<T> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (Sysno, T)>,
{
let mut map = SysnoMap::new();
map.extend(iter);
map
}
}
impl<'a, T> IntoIterator for &'a SysnoMap<T> {
type Item = (Sysno, &'a T);
type IntoIter = SysnoMapIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T> core::ops::Index<Sysno> for SysnoMap<T> {
type Output = T;
fn index(&self, sysno: Sysno) -> &T {
self.get(sysno).expect("no entry found for key")
}
}
impl<T> core::ops::IndexMut<Sysno> for SysnoMap<T> {
fn index_mut(&mut self, sysno: Sysno) -> &mut T {
self.get_mut(sysno).expect("no entry found for key")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
assert_eq!(SysnoMap::<u8>::new().count(), 0);
}
#[test]
fn test_is_empty() {
let mut map = SysnoMap::new();
assert!(map.is_empty());
assert_eq!(map.insert(Sysno::openat, 42), None);
assert!(!map.is_empty());
assert_eq!(map.get(Sysno::openat), Some(&42));
map.remove(Sysno::openat);
assert!(map.is_empty());
assert_eq!(map.get(Sysno::openat), None);
}
#[test]
fn test_count() {
let mut map = SysnoMap::new();
assert_eq!(map.count(), 0);
assert_eq!(map.insert(Sysno::openat, 42), None);
assert_eq!(map.count(), 1);
assert_eq!(map.insert(Sysno::first(), 4), None);
assert_eq!(map.count(), 2);
assert_eq!(map.insert(Sysno::last(), 5), None);
assert_eq!(map.count(), 3);
assert_eq!(map.values().sum::<u8>(), 51);
}
#[test]
fn test_fn() {
let mut map = SysnoMap::<fn() -> i32>::new();
map.insert(Sysno::openat, || 1);
map.insert(Sysno::close, || -1);
assert_eq!(map.get(Sysno::openat).unwrap()(), 1);
assert_eq!(map.get(Sysno::close).unwrap()(), -1);
}
#[test]
fn test_fn_macro() {
type Handler = fn() -> i32;
let map = SysnoMap::from_iter([
(Sysno::openat, (|| 1) as Handler),
(Sysno::close, (|| -1) as Handler),
]);
assert_eq!(map.get(Sysno::openat).unwrap()(), 1);
assert_eq!(map.get(Sysno::close).unwrap()(), -1);
}
#[test]
fn test_insert_remove() {
let mut map = SysnoMap::new();
assert_eq!(map.insert(Sysno::openat, 42), None);
assert!(map.contains_key(Sysno::openat));
assert_eq!(map.count(), 1);
assert_eq!(map.insert(Sysno::openat, 4), Some(42));
assert!(map.contains_key(Sysno::openat));
assert_eq!(map.count(), 1);
assert_eq!(map.remove(Sysno::openat), Some(4));
assert!(!map.contains_key(Sysno::openat));
assert_eq!(map.count(), 0);
assert_eq!(map.remove(Sysno::openat), None);
}
#[cfg(feature = "std")]
#[test]
fn test_debug() {
let map = SysnoMap::from_iter([(Sysno::read, 42), (Sysno::openat, 10)]);
let result = format!("{:?}", map);
assert_eq!(result.len(), "{read: 42, openat: 10}".len());
assert!(result.starts_with('{'));
assert!(result.ends_with('}'));
assert!(result.contains(", "));
assert!(result.contains("read: 42"));
assert!(result.contains("openat: 10"));
}
#[cfg(feature = "std")]
#[test]
fn test_iter() {
let map = SysnoMap::from_iter([(Sysno::read, 42), (Sysno::openat, 10)]);
assert_eq!(map.iter().collect::<Vec<_>>().len(), 2);
}
#[test]
fn test_into_iter() {
let map = SysnoMap::from_iter([(Sysno::read, 42), (Sysno::openat, 10)]);
assert_eq!((&map).into_iter().count(), 2);
}
#[test]
fn test_init_all() {
let map = SysnoMap::init_all(&42);
assert_eq!(map.get(Sysno::openat), Some(&42));
assert_eq!(map.get(Sysno::close), Some(&42));
}
}