diff options
| -rw-r--r-- | common/object/src/inspect.rs | 38 | ||||
| -rw-r--r-- | common/object/src/lib.rs | 3 | ||||
| -rw-r--r-- | common/object/src/registry.rs | 32 | ||||
| -rw-r--r-- | common/object/src/tests.rs | 25 | ||||
| -rw-r--r-- | common/src/lib.rs | 21 |
5 files changed, 94 insertions, 25 deletions
diff --git a/common/object/src/inspect.rs b/common/object/src/inspect.rs new file mode 100644 index 0000000..871fae8 --- /dev/null +++ b/common/object/src/inspect.rs @@ -0,0 +1,38 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2026 metamuffin <metamuffin.org> +*/ + +use crate::{Object, Registry, types::*}; +use std::fmt::Debug; + +pub struct ObjectInpector<'a>(pub &'a Registry, pub Object<'a>); +impl Debug for ObjectInpector<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut s = f.debug_struct("Object"); + let mut nonexhaustive = false; + for (i, k) in self.1.keys().enumerate() { + let Some(info) = self.0.info(k) else { + nonexhaustive = true; + continue; + }; + let Some(ty) = info.r#type else { + nonexhaustive = true; + continue; + }; + match ty { + x if x == STR => s.field(info.name, &self.1.get_typed::<&str>(i).unwrap()), + x if x == OBJECT => s.field(info.name, &self.1.get_typed::<Object>(i).unwrap()), + x if x == U32 => s.field(info.name, &self.1.get_typed::<u32>(i).unwrap()), + x if x == U64 => s.field(info.name, &self.1.get_typed::<u64>(i).unwrap()), + _ => &mut s, + }; + } + if nonexhaustive { + s.finish_non_exhaustive() + } else { + s.finish() + } + } +} diff --git a/common/object/src/lib.rs b/common/object/src/lib.rs index 540ce1c..0f059b0 100644 --- a/common/object/src/lib.rs +++ b/common/object/src/lib.rs @@ -6,6 +6,7 @@ #![feature(iter_array_chunks)] mod buffer; +pub mod inspect; mod registry; #[cfg(test)] mod tests; @@ -93,7 +94,7 @@ impl<'a> Object<'a> { pub fn get<'b: 'a, T: Value<'b>>(&'b self, tag: TypedTag<T>) -> Option<T> { self.get_typed(self.find_field(tag.0)?) } - pub fn keys<'b: 'a, T>(&'b self) -> ObjectIter<'b> { + pub fn keys<'b: 'a>(&'b self) -> ObjectIter<'b> { ObjectIter { object: self, index: 0, diff --git a/common/object/src/registry.rs b/common/object/src/registry.rs index 7148efd..4727600 100644 --- a/common/object/src/registry.rs +++ b/common/object/src/registry.rs @@ -8,6 +8,16 @@ use crate::Tag; use log::error; use std::{any::TypeId, collections::BTreeMap}; +pub mod types { + use crate::Object; + use std::any::TypeId; + + pub const OBJECT: TypeId = TypeId::of::<Object>(); + pub const STR: TypeId = TypeId::of::<&str>(); + pub const U32: TypeId = TypeId::of::<u32>(); + pub const U64: TypeId = TypeId::of::<u64>(); +} + #[derive(Default)] pub struct Registry { tags: BTreeMap<Tag, TagInfo>, @@ -19,9 +29,31 @@ impl Registry { } self.tags.insert(tag, info); } + pub fn info(&self, tag: Tag) -> Option<&TagInfo> { + self.tags.get(&tag) + } } pub struct TagInfo { pub name: &'static str, pub r#type: Option<TypeId>, } + +#[macro_export] +macro_rules! fields { + ($($id:ident: $type:ty = $tag:literal $name:literal;)*) => { + $(pub const $id: $crate::TypedTag<$type> = $crate::TypedTag($crate::Tag($tag), std::marker::PhantomData);)* + fn register_fields(reg: &mut $crate::Registry) { + $(reg.add($crate::Tag($tag), $crate::TagInfo { name: $name, r#type: Some(std::any::TypeId::of::<$type>()) });)* + } + }; +} +#[macro_export] +macro_rules! enums { + ($($id:ident = $tag:literal $name:literal;)*) => { + $(pub const $id: $crate::Tag = $crate::Tag($tag);)* + fn register_enums(reg: &mut $crate::Registry) { + $(reg.add($crate::Tag($tag), $crate::TagInfo { name: $name, r#type: None });)* + } + }; +} diff --git a/common/object/src/tests.rs b/common/object/src/tests.rs index 181b46f..86c0287 100644 --- a/common/object/src/tests.rs +++ b/common/object/src/tests.rs @@ -3,12 +3,20 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{ObjectBuffer, Tag, TypedTag}; -use std::marker::PhantomData; -const NAME: TypedTag<&str> = TypedTag(Tag(15), PhantomData); -const AGE: TypedTag<u32> = TypedTag(Tag(13), PhantomData); -const FRIEND: TypedTag<&str> = TypedTag(Tag(54321), PhantomData); +use crate::{ObjectBuffer, Registry, fields, inspect::ObjectInpector}; +use std::sync::LazyLock; + +pub static TAGREG: LazyLock<Registry> = LazyLock::new(|| { + let mut reg = Registry::default(); + register_fields(&mut reg); + reg +}); +fields! { + NAME: &str = 15 "name"; + AGE: u32 = 13 "age"; + FRIEND: &str = 54321 "friend"; +} fn test_object() -> ObjectBuffer { ObjectBuffer::new(&mut [ @@ -59,3 +67,10 @@ fn insert() { eprintln!("{edward:#?}"); assert_eq!(edward.get(NAME), Some("Edward")); } + +#[test] +fn inspect() { + let bob = test_object(); + eprintln!("{:#?}", ObjectInpector(&TAGREG, bob.as_object())); + // panic!() +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 1359c73..2cbbfce 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -5,9 +5,9 @@ */ #![feature(array_try_map)] pub mod routes; -use jellyobject::{Object, Registry, Tag, TagInfo, TypedTag}; +use jellyobject::{Object, Registry, Tag, enums, fields}; pub use jellystream_types as stream; -use std::{any::TypeId, marker::PhantomData, sync::LazyLock}; +use std::sync::LazyLock; pub use jellyobject; @@ -18,23 +18,6 @@ pub static TAGREG: LazyLock<Registry> = LazyLock::new(|| { reg }); -macro_rules! fields { - ($($id:ident: $type:ty = $tag:literal $name:literal;)*) => { - $(pub const $id: TypedTag<$type> = TypedTag(Tag($tag), PhantomData);)* - fn register_fields(reg: &mut Registry) { - $(reg.add(Tag($tag), TagInfo { name: $name, r#type: Some(TypeId::of::<$type>()) });)* - } - }; -} -macro_rules! enums { - ($($id:ident = $tag:literal $name:literal;)*) => { - $(pub const $id: Tag = Tag($tag);)* - fn register_enums(reg: &mut Registry) { - $(reg.add(Tag($tag), TagInfo { name: $name, r#type: None });)* - } - }; -} - fields! { // Tag counter: 36 |