use std::{fmt::Debug, hash::Hash, marker::PhantomData, ops::Deref};
use legion::{
storage::{Archetype, Component},
world::{ComponentError, EntityLocation},
};
use num::ToPrimitive;
use crate::{
filter::{Bloom, BloomResult, BloomSize, BF},
hashed::{NodeHashs, SyntaxNodeHashs, SyntaxNodeHashsKinds},
impact::serialize::{CachedHasher, Keyed, MySerialize},
nodes::{CompressedNode, HashSize, RefContainer},
store::defaults::LabelIdentifier,
types::{
AnyType, Children, HyperType, IterableChildren, MySlice, NodeId, TypeTrait, Typed,
TypedNodeId, WithChildren, WithMetaData,
},
};
use super::compo::{self, NoSpacesCS, CS};
pub type NodeIdentifier = legion::Entity;
pub type EntryRef<'a> = legion::world::EntryRef<'a>;
#[derive(ref_cast::RefCast)]
#[repr(transparent)]
pub struct HashedNodeRef<'a, T = NodeIdentifier>(pub(super) EntryRef<'a>, PhantomData<T>);
impl<'a, T> HashedNodeRef<'a, T> {
#[doc(hidden)]
pub fn cast_type<U: NodeId>(self) -> HashedNodeRef<'a, U>
where
T: NodeId<IdN = U::IdN>,
{
HashedNodeRef(self.0, PhantomData)
}
pub(super) fn new(e: EntryRef<'a>) -> Self {
Self(e, PhantomData)
}
}
impl<'a, T> From<&'a EntryRef<'a>> for &'a HashedNodeRef<'a, T> {
fn from(value: &'a EntryRef<'a>) -> Self {
use ref_cast::RefCast;
HashedNodeRef::ref_cast(value)
}
}
impl NodeId for NodeIdentifier {
type IdN = Self;
fn as_id(&self) -> &Self::IdN {
self
}
unsafe fn from_id(id: Self::IdN) -> Self {
id
}
unsafe fn from_ref_id(id: &Self::IdN) -> &Self {
id
}
}
impl TypedNodeId for NodeIdentifier {
type Ty = crate::types::AnyType;
type TyErazed = crate::types::AnyType;
fn unerase(ty: Self::TyErazed) -> Self::Ty {
ty
}
}
pub struct HashedNode<Id: TypedNodeId<IdN = NodeIdentifier>> {
node: CompressedNode<NodeIdentifier, LabelIdentifier, Id::Ty>,
hashs: SyntaxNodeHashs<u32>,
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> PartialEq for HashedNode<Id>
where
Id::IdN: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.node == other.node
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> Eq for HashedNode<Id> where Id::IdN: Eq {}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> Hash for HashedNode<Id> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.hashs.hash(&Default::default()).hash(state)
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> crate::types::Labeled for HashedNode<Id> {
type Label = LabelIdentifier;
fn get_label_unchecked(&self) -> &LabelIdentifier {
panic!()
}
fn try_get_label(&self) -> Option<&Self::Label> {
todo!()
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> PartialEq for HashedNodeRef<'a, Id> {
fn eq(&self, other: &Self) -> bool {
self.0.location().archetype() == other.0.location().archetype()
&& self.0.location().component() == other.0.location().component()
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> Eq for HashedNodeRef<'a, Id> {}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> Hash for HashedNodeRef<'a, Id> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
crate::types::WithHashs::hash(self, &Default::default()).hash(state)
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> Debug for HashedNodeRef<'a, Id> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("HashedNodeRef")
.field(&self.0.location())
.finish()
}
}
impl<'a, Id> Deref for HashedNodeRef<'a, Id> {
type Target = EntryRef<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> HashedNodeRef<'a, Id> {
pub fn get_bytes_len(&self, _p_indent_len: u32) -> u32
where
Id::Ty: 'static + TypeTrait + Send + Sync + Debug,
{
self.0.get_component::<compo::BytesLen>().unwrap().0
}
}
impl<'a, Id: 'static + TypedNodeId<IdN = NodeIdentifier>> HashedNodeRef<'a, Id> {
pub fn try_get_bytes_len(&self, _p_indent_len: u32) -> Option<u32>
where
Id::Ty: HyperType + Copy + Send + Sync,
{
if self.get_type().is_spaces() {
self.0.get_component::<compo::BytesLen>().map(|x| x.0).ok()
} else {
self.0.get_component::<compo::BytesLen>().map(|x| x.0).ok()
}
}
pub fn is_directory(&self) -> bool
where
Id: HyperType + Copy + Send + Sync,
{
self.get_type().is_directory()
}
}
impl<'a, T, C: Component> WithMetaData<C> for HashedNodeRef<'a, T> {
fn get_metadata(&self) -> Option<&C> {
self.0.get_component::<C>().ok()
}
}
impl<'a, T> HashedNodeRef<'a, T> {
pub fn archetype(&self) -> &Archetype {
self.0.archetype()
}
pub fn location(&self) -> EntityLocation {
self.0.location()
}
pub fn into_component<C: Component>(self) -> Result<&'a C, ComponentError> {
self.0.into_component::<C>()
}
pub unsafe fn into_component_unchecked<C: Component>(
self,
) -> Result<&'a mut C, ComponentError> {
self.0.into_component_unchecked::<C>()
}
pub fn get_component<C: Component>(&self) -> Result<&C, ComponentError> {
self.0.get_component::<C>()
}
pub unsafe fn get_component_unchecked<C: Component>(&self) -> Result<&mut C, ComponentError> {
self.0.get_component_unchecked::<C>()
}
pub fn get_child_by_name(
&self,
name: &<HashedNodeRef<'a, T> as crate::types::Labeled>::Label,
) -> Option<<HashedNodeRef<'a, T> as crate::types::Stored>::TreeId> {
let labels = self
.0
.get_component::<CS<<HashedNodeRef<'a, T> as crate::types::Labeled>::Label>>()
.ok()?;
let idx = labels.0.iter().position(|x| x == name);
idx.map(|idx| self.child(&idx.to_u16().unwrap()).unwrap())
}
pub fn get_child_idx_by_name(
&self,
name: &<HashedNodeRef<'a, T> as crate::types::Labeled>::Label,
) -> Option<<HashedNodeRef<'a, T> as crate::types::WithChildren>::ChildIdx> {
let labels = self
.0
.get_component::<CS<<HashedNodeRef<'a, T> as crate::types::Labeled>::Label>>()
.ok()?;
labels
.0
.iter()
.position(|x| x == name)
.map(|x| x.to_u16().unwrap())
}
pub fn try_get_children_name(
&self,
) -> Option<&[<HashedNodeRef<'a, T> as crate::types::Labeled>::Label]> {
self.0
.get_component::<CS<<HashedNodeRef<'a, T> as crate::types::Labeled>::Label>>()
.ok()
.map(|x| &*x.0)
}
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> HashedNodeRef<'a, Id>
where
Id::Ty: 'static + Sync + Send + TypeTrait,
{
pub fn into_compressed_node(
&self,
) -> Result<CompressedNode<legion::Entity, LabelIdentifier, Id::Ty>, ComponentError> {
let kind = self.0.get_component::<Id::Ty>()?;
if kind.is_spaces() {
let spaces = self.0.get_component::<LabelIdentifier>().unwrap();
return Ok(CompressedNode::Spaces(spaces.clone()));
}
let a = self.0.get_component::<LabelIdentifier>();
let label: Option<LabelIdentifier> = a.ok().map(|x| x.clone());
let children = self.children().map(|x| {
let it = x.iter_children();
it.map(|x| x.clone()).collect()
});
Ok(CompressedNode::new(
*kind,
label,
children.unwrap_or_default(),
))
}
}
impl<'a, T> AsRef<HashedNodeRef<'a, T>> for HashedNodeRef<'a, T> {
fn as_ref(&self) -> &HashedNodeRef<'a, T> {
self
}
}
impl<'a, Id: 'static + TypedNodeId<IdN = NodeIdentifier>> crate::types::Typed
for HashedNodeRef<'a, Id>
{
type Type = Id::Ty;
fn get_type(&self) -> Id::Ty
where
Id::Ty: Copy + Send + Sync,
{
match self.0.get_component::<Id::TyErazed>() {
Ok(t) => Id::unerase(t.clone()),
e => Id::unerase(e.unwrap().clone()),
}
}
fn try_get_type(&self) -> Option<Self::Type> {
self.0.get_component::<Id::Ty>().ok().copied()
}
}
impl<'a, Id: 'static + TypedNodeId<IdN = NodeIdentifier>> crate::types::Typed
for &HashedNodeRef<'a, Id>
{
type Type = AnyType;
fn get_type(&self) -> AnyType {
match self.0.get_component::<Id::Ty>() {
Ok(t) => {
let t: &'static dyn HyperType = t.as_static();
t.into()
}
Err(e @ ComponentError::NotFound { .. }) => {
todo!("{:?}", e)
}
e => {
todo!("{:?}", e)
}
}
}
}
impl<'a, T> crate::types::WithStats for HashedNodeRef<'a, T> {
fn size(&self) -> usize {
self.0
.get_component::<compo::Size>()
.ok()
.and_then(|x| x.0.to_usize())
.unwrap_or(1)
}
fn height(&self) -> usize {
self.0
.get_component::<compo::Height>()
.ok()
.and_then(|x| x.0.to_usize())
.unwrap_or(1)
}
fn line_count(&self) -> usize {
self.0
.get_component::<compo::LineCount>()
.ok()
.and_then(|x| x.0.to_usize())
.unwrap_or(0)
}
}
impl<'a, T> HashedNodeRef<'a, T> {
pub fn size_no_spaces(&self) -> usize {
self.0
.get_component::<compo::SizeNoSpaces>()
.ok()
.and_then(|x| x.0.to_usize())
.unwrap_or(1)
}
}
impl<'a, T> crate::types::WithSerialization for HashedNodeRef<'a, T> {
fn try_bytes_len(&self) -> Option<usize> {
self.0
.get_component::<compo::BytesLen>()
.ok()
.map(|x| x.0.to_usize().unwrap())
}
}
impl<'a, T> crate::types::Labeled for HashedNodeRef<'a, T> {
type Label = LabelIdentifier;
fn get_label_unchecked(&self) -> &LabelIdentifier {
self.0
.get_component::<LabelIdentifier>()
.expect("check with self.has_label()")
}
fn try_get_label(&self) -> Option<&Self::Label> {
self.0.get_component::<LabelIdentifier>().ok()
}
}
impl<'a, T> crate::types::Node for HashedNodeRef<'a, T> {}
impl<'a, T> crate::types::Stored for HashedNodeRef<'a, T> {
type TreeId = NodeIdentifier;
}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> crate::types::Node for HashedNode<Id> {}
impl<'a, Id: TypedNodeId<IdN = NodeIdentifier>> crate::types::Stored for HashedNode<Id> {
type TreeId = NodeIdentifier;
}
impl<'a, T> HashedNodeRef<'a, T> {
pub fn cs(
&self,
) -> Result<&<Self as crate::types::WithChildren>::Children<'_>, ComponentError> {
let r = self
.0
.get_component::<CS<legion::Entity>>()
.map(|x| (*x.0).into())
.or_else(|_| {
self.0
.get_component::<compo::CS0<legion::Entity, 1>>()
.map(|x| (&x.0).into())
})
.or_else(|_| {
self.0
.get_component::<compo::CS0<legion::Entity, 2>>()
.map(|x| (&x.0).into())
});
r
}
pub fn no_spaces(
&self,
) -> Result<&<Self as crate::types::WithChildren>::Children<'_>, ComponentError> {
self.0
.get_component::<NoSpacesCS<legion::Entity>>()
.map(|x| (*x.0).into())
.or_else(|_| {
self.0
.get_component::<compo::NoSpacesCS0<legion::Entity, 1>>()
.map(|x| (&x.0).into())
})
.or_else(|_| {
self.0
.get_component::<compo::NoSpacesCS0<legion::Entity, 2>>()
.map(|x| (&x.0).into())
})
.or_else(|_| self.cs())
}
}
impl<'a, T> crate::types::WithChildren for HashedNodeRef<'a, T> {
type ChildIdx = u16;
type Children<'b>
= MySlice<Self::TreeId>
where
Self: 'b;
fn child_count(&self) -> u16 {
self.cs()
.map_or(0, |x| {
let c: u16 = x.child_count();
c
})
.to_u16()
.expect("too much children")
}
fn child(&self, idx: &Self::ChildIdx) -> Option<Self::TreeId> {
self.cs()
.unwrap_or_else(|x| {
log::error!("backtrace: {}", std::backtrace::Backtrace::force_capture());
panic!("{}", x)
})
.0
.get(idx.to_usize().unwrap())
.map(|x| *x)
}
fn child_rev(&self, idx: &Self::ChildIdx) -> Option<Self::TreeId> {
let v = self.cs().ok()?;
let c: Self::ChildIdx = v.child_count();
let c = c.checked_sub(idx.checked_add(1)?)?;
v.get(c).cloned()
}
fn children(&self) -> Option<&Self::Children<'_>> {
self.cs().ok()
}
}
impl<'a, T> crate::types::WithRoles for HashedNodeRef<'a, T> {
fn role_at<Role: 'static + Copy + std::marker::Sync + std::marker::Send>(
&self,
at: Self::ChildIdx,
) -> Option<Role> {
let ro = self.0.get_component::<compo::RoleOffsets>().ok()?;
let r = self.0.get_component::<Box<[Role]>>().ok()?;
let mut i = 0;
for &ro in ro.0.as_ref() {
if ro as u16 > at {
return None;
} else if ro as u16 == at {
return Some(r[i]);
}
i += 1;
}
None
}
}
impl<'a, T> crate::types::WithPrecompQueries for HashedNodeRef<'a, T> {
fn wont_match_given_precomputed_queries(&self, needed: u16) -> bool {
if needed == num::zero() {
return false;
}
let Ok(v) = self.get_component::<compo::Precomp<u16>>() else {
return self.get_component::<compo::PrecompFlag>().is_ok();
};
v.0 & needed != needed
}
}
impl<'a, T> crate::types::WithHashs for HashedNodeRef<'a, T> {
type HK = SyntaxNodeHashsKinds;
type HP = HashSize;
fn hash(&self, kind: &Self::HK) -> Self::HP {
self.0
.get_component::<SyntaxNodeHashs<Self::HP>>()
.unwrap()
.hash(kind)
}
}
impl<'a, Id> crate::types::ErasedHolder for HashedNodeRef<'a, Id> {
fn unerase_ref<T: 'static + Send + Sync>(&self, tid: std::any::TypeId) -> Option<&T> {
if tid == std::any::TypeId::of::<T>() {
self.get_component().ok()
} else {
None
}
}
}
impl<'a, Id: 'static + TypedNodeId<IdN = NodeIdentifier>> crate::types::Tree
for HashedNodeRef<'a, Id>
{
fn has_children(&self) -> bool {
self.cs().map(|x| !x.is_empty()).unwrap_or(false)
}
fn has_label(&self) -> bool {
self.0.get_component::<LabelIdentifier>().is_ok()
}
}
impl<'a, T> HashedNodeRef<'a, T> {}
impl<'a, T> RefContainer for HashedNodeRef<'a, T> {
type Result = BloomResult;
fn check<U: MySerialize + Keyed<usize>>(&self, rf: U) -> Self::Result {
use crate::filter::BF as _;
let Ok(e) = self.0.get_component::<BloomSize>() else {
return BloomResult::MaybeContain;
};
macro_rules! check {
( $($t:ty),* ) => {
match *e {
BloomSize::Much => {
log::trace!("[Too Much]");
BloomResult::MaybeContain
},
BloomSize::None => BloomResult::DoNotContain,
$( <$t>::SIZE => {
let x = CachedHasher::<usize,<$t as BF<[u8]>>::S, <$t as BF<[u8]>>::H>::once(rf);
let x = x.into_iter().map(|x|<$t>::check_raw(self.0.get_component::<$t>().unwrap(), x));
for x in x {
if let BloomResult::MaybeContain = x {
return BloomResult::MaybeContain
}
}
BloomResult::DoNotContain
}),*
}
};
}
check![
Bloom<&'static [u8], u16>,
Bloom<&'static [u8], u32>,
Bloom<&'static [u8], u64>,
Bloom<&'static [u8], [u64; 2]>,
Bloom<&'static [u8], [u64; 4]>,
Bloom<&'static [u8], [u64; 8]>,
Bloom<&'static [u8], [u64; 16]>,
Bloom<&'static [u8], [u64; 32]>,
Bloom<&'static [u8], [u64; 64]>
]
}
}