use alloc::boxed::Box;
use core::any::{Any, type_name};
fn panic_type_mismatch<T>(id: &impl core::fmt::Debug) -> ! {
panic!(
"Tensor type mismatch for ID {id:?}: requested `{}`. Make sure the requested tensor rank matches the registered tensor rank.",
type_name::<T>()
)
}
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use hashbrown::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;
#[derive(Debug)]
pub struct TensorContainer<ID> {
tensors: HashMap<ID, Box<dyn Any + Send>>,
}
impl<ID> Default for TensorContainer<ID>
where
ID: core::hash::Hash + PartialEq + Eq + core::fmt::Debug,
{
fn default() -> Self {
Self::new()
}
}
impl<ID> TensorContainer<ID>
where
ID: core::hash::Hash + PartialEq + Eq + core::fmt::Debug,
{
pub fn new() -> Self {
Self {
tensors: HashMap::new(),
}
}
pub fn get<T: Clone + Send + 'static>(&self, id: &ID) -> Option<T> {
let grad = self.tensors.get(id)?;
let tensor = grad
.downcast_ref::<T>()
.unwrap_or_else(|| panic_type_mismatch::<T>(id));
Some(tensor.clone())
}
pub fn get_mut_ref<T: Clone + Send + 'static>(&mut self, id: &ID) -> Option<&mut T> {
let grad = self.tensors.get_mut(id)?;
let tensor = grad
.downcast_mut::<T>()
.unwrap_or_else(|| panic_type_mismatch::<T>(id));
Some(tensor)
}
pub fn register<T: Clone + Send + 'static>(&mut self, id: ID, value: T) {
self.tensors.insert(id, Box::new(value));
}
pub fn remove<T: Clone + Send + 'static>(&mut self, id: &ID) -> Option<T> {
self.tensors.remove(id).map(|item| {
*item
.downcast::<T>()
.unwrap_or_else(|_| panic_type_mismatch::<T>(id))
})
}
pub fn len(&self) -> usize {
self.tensors.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn ids(&self) -> Vec<&ID> {
self.tensors.keys().collect()
}
}