use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, OnceLock};
use crate::RenderContext;
use crate::renderer::{Renderer, RendererExt};
#[derive(thiserror::Error, Clone, Debug, PartialEq, Eq)]
pub enum RendererRegistrationError {
#[error("Renderer type {renderer_name} was not registered")]
NotRegistered { renderer_name: &'static str },
#[error("Renderer type {renderer_name} did not match its registry entry")]
TypeMismatch { renderer_name: &'static str },
}
impl RendererRegistrationError {
fn not_registered<R: Renderer + 'static>() -> Self {
Self::NotRegistered {
renderer_name: std::any::type_name::<R>(),
}
}
fn type_mismatch<R: Renderer + 'static>() -> Self {
Self::TypeMismatch {
renderer_name: std::any::type_name::<R>(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct RendererTypeId(u8);
impl RendererTypeId {
#[inline]
pub const fn bits(&self) -> u8 {
self.0
}
#[inline]
pub const fn from_bits(bits: u8) -> Self {
Self(bits)
}
}
struct RendererEntry {
renderer: OnceLock<Box<dyn RendererExt>>,
key: RendererTypeId,
name: &'static str,
}
#[derive(Default)]
pub struct Renderers {
renderer_entries: HashMap<TypeId, Arc<RendererEntry>>,
renderer_entries_by_key: Vec<Arc<RendererEntry>>,
}
impl Renderers {
pub fn register<R: Renderer + Send + Sync + 'static>(&mut self) {
let type_id = TypeId::of::<R>();
if self.renderer_entries.contains_key(&type_id) {
return;
}
let Ok(key) = self.renderer_entries_by_key.len().try_into() else {
re_log::error!("Supporting at most 256 distinct renderer types.");
return;
};
let key = RendererTypeId(key);
let entry = Arc::new(RendererEntry {
renderer: OnceLock::new(),
key,
name: std::any::type_name::<R>(),
});
let previous = self.renderer_entries.insert(type_id, entry.clone());
re_log::debug_assert!(previous.is_none());
self.renderer_entries_by_key.push(entry);
}
pub fn get<R: Renderer + Send + Sync + 'static>(
&self,
ctx: &RenderContext,
) -> Result<&R, RendererRegistrationError> {
let entry = self
.renderer_entries
.get(&TypeId::of::<R>())
.ok_or_else(RendererRegistrationError::not_registered::<R>)?;
let renderer = entry.renderer.get_or_init(|| {
re_tracing::profile_scope!("create_renderer", std::any::type_name::<R>());
Box::new(R::create_renderer(ctx))
});
(renderer.as_ref() as &dyn Any)
.downcast_ref::<R>()
.ok_or_else(RendererRegistrationError::type_mismatch::<R>)
}
pub fn get_key<R: Renderer + Send + Sync + 'static>(
&self,
) -> Result<RendererTypeId, RendererRegistrationError> {
self.renderer_entries
.get(&TypeId::of::<R>())
.map(|entry| entry.key)
.ok_or_else(RendererRegistrationError::not_registered::<R>)
}
pub fn get_by_key(&self, key: RendererTypeId) -> Option<(&'static str, &dyn RendererExt)> {
let entry = self.renderer_entries_by_key.get(key.0 as usize)?;
let renderer = entry.renderer.get()?;
Some((entry.name, renderer.as_ref()))
}
pub(crate) fn name_sort_remap(&self) -> [u8; 256] {
let mut remap = [0u8; 256];
let mut pairs: smallvec::SmallVec<[(&'static str, u8); 16]> = self
.renderer_entries_by_key
.iter()
.enumerate()
.map(|(key, entry)| (entry.name, key as u8))
.collect();
pairs.sort_by_key(|&(name, _)| name);
for (rank, (_name, key)) in pairs.into_iter().enumerate() {
remap[key as usize] = rank as u8;
}
remap
}
}