use std::borrow::Cow;
use nohash_hasher::IntSet;
use re_byte_size::SizeBytes;
use crate::{ComponentDescriptor, DeserializationResult, SerializationResult};
#[expect(unused_imports, clippy::unused_trait_names)] use crate::{Archetype, ComponentBatch, LoggableBatch};
pub trait Loggable: 'static + Send + Sync + Clone + Sized + SizeBytes {
fn arrow_datatype() -> arrow::datatypes::DataType;
#[inline]
fn arrow_empty() -> arrow::array::ArrayRef {
arrow::array::new_empty_array(&Self::arrow_datatype())
}
#[inline]
fn to_arrow<'a>(
data: impl IntoIterator<Item = impl Into<std::borrow::Cow<'a, Self>>>,
) -> SerializationResult<arrow::array::ArrayRef>
where
Self: 'a,
{
Self::to_arrow_opt(data.into_iter().map(|v| Some(v)))
}
fn to_arrow_opt<'a>(
data: impl IntoIterator<Item = Option<impl Into<std::borrow::Cow<'a, Self>>>>,
) -> SerializationResult<arrow::array::ArrayRef>
where
Self: 'a;
#[inline]
fn from_arrow(data: &dyn arrow::array::Array) -> DeserializationResult<Vec<Self>> {
Self::from_arrow_opt(data)?
.into_iter()
.map(|opt| opt.ok_or_else(crate::DeserializationError::missing_data))
.collect::<DeserializationResult<Vec<_>>>()
}
#[inline]
fn from_arrow_opt(
data: &dyn arrow::array::Array,
) -> crate::DeserializationResult<Vec<Option<Self>>> {
Self::from_arrow(data).map(|v| v.into_iter().map(Some).collect())
}
fn verify_arrow_array(data: &dyn arrow::array::Array) -> crate::DeserializationResult<()> {
Self::from_arrow(data).map(|_| ())
}
}
pub trait Component: Loggable {
fn descriptor() -> ComponentDescriptor;
#[inline]
fn name() -> ComponentName {
Self::descriptor().component_name
}
}
pub type UnorderedComponentNameSet = IntSet<ComponentName>;
pub type ComponentNameSet = std::collections::BTreeSet<ComponentName>;
re_string_interner::declare_new_type!(
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
pub struct ComponentName;
);
impl From<ComponentName> for Cow<'static, ComponentDescriptor> {
#[inline]
fn from(name: ComponentName) -> Self {
name.sanity_check();
Cow::Owned(ComponentDescriptor::new(name))
}
}
impl From<&ComponentName> for Cow<'static, ComponentDescriptor> {
#[inline]
fn from(name: &ComponentName) -> Self {
name.sanity_check();
Cow::Owned(ComponentDescriptor::new(*name))
}
}
impl ComponentName {
#[inline]
#[track_caller]
pub fn sanity_check(&self) {
let full_name = self.0.as_str();
debug_assert!(
!full_name.starts_with("rerun.components.rerun.components."),
"DEBUG ASSERT: Found component with full name {full_name:?}. Maybe some bad round-tripping?"
);
}
#[inline]
pub fn full_name(&self) -> &'static str {
self.sanity_check();
self.0.as_str()
}
#[inline]
pub fn short_name(&self) -> &'static str {
self.sanity_check();
let full_name = self.0.as_str();
if let Some(short_name) = full_name.strip_prefix("rerun.blueprint.components.") {
short_name
} else if let Some(short_name) = full_name.strip_prefix("rerun.components.") {
short_name
} else if let Some(short_name) = full_name.strip_prefix("rerun.controls.") {
short_name
} else if let Some(short_name) = full_name.strip_prefix("rerun.") {
short_name
} else {
full_name
}
}
pub fn is_indicator_component(&self) -> bool {
self.ends_with("Indicator")
}
pub fn indicator_component_archetype_short_name(&self) -> Option<String> {
self.short_name()
.strip_suffix("Indicator")
.map(|name| name.to_owned())
}
pub fn doc_url(&self) -> Option<String> {
if let Some(archetype_name_pascal_case) = self.indicator_component_archetype_short_name() {
let archetype_name_snake_case = re_case::to_snake_case(&archetype_name_pascal_case);
let base_url = "https://rerun.io/docs/reference/types/archetypes";
Some(format!("{base_url}/{archetype_name_snake_case}"))
} else if let Some(component_name_pascal_case) =
self.full_name().strip_prefix("rerun.components.")
{
let component_name_snake_case = re_case::to_snake_case(component_name_pascal_case);
let base_url = "https://rerun.io/docs/reference/types/components";
Some(format!("{base_url}/{component_name_snake_case}"))
} else {
None }
}
pub fn matches(&self, other: &str) -> bool {
self.0.as_str() == other
|| self.full_name().to_lowercase() == other.to_lowercase()
|| self.short_name().to_lowercase() == other.to_lowercase()
}
}
impl re_byte_size::SizeBytes for ComponentName {
#[inline]
fn heap_size_bytes(&self) -> u64 {
0
}
}
re_string_interner::declare_new_type!(
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
pub struct DatatypeName;
);
impl DatatypeName {
#[inline]
pub fn full_name(&self) -> &'static str {
self.0.as_str()
}
#[inline]
pub fn short_name(&self) -> &'static str {
let full_name = self.0.as_str();
if let Some(short_name) = full_name.strip_prefix("rerun.datatypes.") {
short_name
} else if let Some(short_name) = full_name.strip_prefix("rerun.") {
short_name
} else {
full_name
}
}
}
impl re_byte_size::SizeBytes for DatatypeName {
#[inline]
fn heap_size_bytes(&self) -> u64 {
0
}
}