use std::{hash::Hash, str::FromStr};
use re_log_types::{DataPath, EntityPath, EntityPathHash, PathParseError, RowId};
use re_types::components::InstanceKey;
use crate::{store_db::EntityDb, VersionedInstancePath, VersionedInstancePathHash};
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct InstancePath {
pub entity_path: EntityPath,
pub instance_key: InstanceKey,
}
impl From<EntityPath> for InstancePath {
#[inline]
fn from(entity_path: EntityPath) -> Self {
Self::entity_splat(entity_path)
}
}
impl InstancePath {
#[inline]
pub fn entity_splat(entity_path: EntityPath) -> Self {
Self {
entity_path,
instance_key: InstanceKey::SPLAT,
}
}
#[inline]
pub fn instance(entity_path: EntityPath, instance_key: InstanceKey) -> Self {
Self {
entity_path,
instance_key,
}
}
#[inline]
pub fn is_splat(&self) -> bool {
self.instance_key.is_splat()
}
#[inline]
pub fn versioned(&self, row_id: RowId) -> VersionedInstancePath {
VersionedInstancePath {
instance_path: self.clone(),
row_id,
}
}
#[inline]
pub fn hash(&self) -> InstancePathHash {
InstancePathHash {
entity_path_hash: self.entity_path.hash(),
instance_key: self.instance_key,
}
}
}
impl std::fmt::Display for InstancePath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.instance_key.is_splat() {
self.entity_path.fmt(f)
} else {
format!("{}[{}]", self.entity_path, self.instance_key).fmt(f)
}
}
}
impl FromStr for InstancePath {
type Err = PathParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let DataPath {
entity_path,
instance_key,
component_name,
} = DataPath::from_str(s)?;
if let Some(component_name) = component_name {
return Err(PathParseError::UnexpectedComponentName(component_name));
}
let instance_key = instance_key.unwrap_or(InstanceKey::SPLAT);
Ok(InstancePath {
entity_path,
instance_key,
})
}
}
#[test]
fn test_parse_instance_path() {
assert_eq!(
InstancePath::from_str("world/points[#123]"),
Ok(InstancePath {
entity_path: EntityPath::from("world/points"),
instance_key: InstanceKey(123)
})
);
}
#[derive(Clone, Copy, Debug, Eq)]
pub struct InstancePathHash {
pub entity_path_hash: EntityPathHash,
pub instance_key: InstanceKey,
}
impl std::hash::Hash for InstancePathHash {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let Self {
entity_path_hash,
instance_key,
} = self;
state.write_u64(entity_path_hash.hash64());
state.write_u64(instance_key.0);
}
}
impl std::cmp::PartialEq for InstancePathHash {
#[inline]
fn eq(&self, other: &Self) -> bool {
let Self {
entity_path_hash,
instance_key,
} = self;
entity_path_hash == &other.entity_path_hash && instance_key == &other.instance_key
}
}
impl InstancePathHash {
pub const NONE: Self = Self {
entity_path_hash: EntityPathHash::NONE,
instance_key: InstanceKey::SPLAT,
};
#[inline]
pub fn entity_splat(entity_path: &EntityPath) -> Self {
Self {
entity_path_hash: entity_path.hash(),
instance_key: InstanceKey::SPLAT,
}
}
#[inline]
pub fn instance(entity_path: &EntityPath, instance_key: InstanceKey) -> Self {
Self {
entity_path_hash: entity_path.hash(),
instance_key,
}
}
#[inline]
pub fn is_some(&self) -> bool {
self.entity_path_hash.is_some()
}
#[inline]
pub fn is_none(&self) -> bool {
self.entity_path_hash.is_none()
}
#[inline]
pub fn versioned(&self, row_id: RowId) -> VersionedInstancePathHash {
VersionedInstancePathHash {
instance_path_hash: *self,
row_id,
}
}
pub fn resolve(&self, entity_db: &EntityDb) -> Option<InstancePath> {
let entity_path = entity_db
.entity_path_from_hash(&self.entity_path_hash)
.cloned()?;
let instance_key = self.instance_key;
Some(InstancePath {
entity_path,
instance_key,
})
}
}
impl Default for InstancePathHash {
fn default() -> Self {
Self::NONE
}
}