aboutsummaryrefslogtreecommitdiff
path: root/common/object/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'common/object/src/lib.rs')
-rw-r--r--common/object/src/lib.rs276
1 files changed, 124 insertions, 152 deletions
diff --git a/common/object/src/lib.rs b/common/object/src/lib.rs
index ae8d1cd..783871b 100644
--- a/common/object/src/lib.rs
+++ b/common/object/src/lib.rs
@@ -3,102 +3,66 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-#![feature(iter_array_chunks, strip_circumfix)]
+#![feature(iter_array_chunks, strip_circumfix, phantom_variance_markers)]
mod buffer;
pub mod debug;
#[cfg(feature = "json")]
pub mod json;
mod path;
-mod registry;
+pub mod tag;
#[cfg(test)]
mod tests;
mod value;
pub use buffer::*;
pub use path::*;
-pub use registry::*;
+pub use tag::*;
pub use value::*;
-use std::{collections::BTreeSet, fmt::Display, hash::Hash, marker::PhantomData};
+use core::{marker::Sized, todo};
+use std::{collections::BTreeSet, hash::Hash, marker::PhantomData};
+#[derive(Hash, PartialEq, Eq)]
#[repr(transparent)]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Tag(pub u32);
+pub struct Object([u32]);
-impl Default for Tag {
- fn default() -> Self {
- Self::new(b"1111")
- }
-}
-impl Tag {
- pub const fn new(fourcc: &[u8; 4]) -> Self {
- Self(u32::from_le_bytes(*fourcc))
- }
-}
-impl Display for Tag {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(str::from_utf8(&self.0.to_le_bytes()).unwrap())
+impl ToOwned for Object {
+ type Owned = Box<Object>;
+ fn to_owned(&self) -> Self::Owned {
+ vec_to_ob(self.0.to_vec())
}
}
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-pub struct TypedTag<T>(pub Tag, pub PhantomData<T>);
-impl<T> Display for TypedTag<T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.0.fmt(f)
- }
-}
+pub const EMPTY: &'static Object = slice_to_ob(&[0]);
-impl<T> Clone for TypedTag<T> {
- fn clone(&self) -> Self {
- Self(self.0, PhantomData)
+impl Object {
+ #[inline]
+ fn len(&self) -> usize {
+ self.0[0] as usize
}
-}
-impl<T> Copy for TypedTag<T> {}
-
-#[derive(Clone, Copy, Hash, PartialEq, Eq)]
-pub struct Object<'a> {
- tags: &'a [u32],
- offsets: &'a [u32],
- values: &'a [u32],
-}
-
-impl<'a> Default for Object<'a> {
- fn default() -> Self {
- Self::EMPTY
+ #[inline]
+ fn tags(&self) -> &[u32] {
+ &self.0[1..1 + self.len()]
}
-}
-impl<'a> Object<'a> {
- pub const EMPTY: Object<'static> = Object {
- offsets: &[],
- tags: &[],
- values: &[],
- };
-
- pub fn load(buf: &'a [u32]) -> Option<Self> {
- let nf = *buf.get(0)? as usize;
- if buf.len() < 1 + nf * 2 {
- return None;
- }
- Some(Self {
- tags: &buf[1..1 + nf],
- offsets: &buf[1 + nf..1 + nf + nf],
- values: &buf[1 + nf + nf..],
- })
+ #[inline]
+ fn offsets(&self) -> &[u32] {
+ let nf = self.len();
+ &self.0[1 + nf..1 + nf + nf]
}
- pub fn dump(&self) -> ObjectBuffer {
- let mut out = Vec::new();
- out.push(self.tags.len() as u32);
- out.extend(self.tags);
- out.extend(self.offsets);
- out.extend(self.values);
- ObjectBuffer(out)
+ #[inline]
+ fn values(&self) -> &[u32] {
+ let nf = self.len();
+ &self.0[1 + nf + nf..]
}
+ pub fn export(&self) -> &[u32] {
+ &self.0
+ }
+
pub fn find_field(&self, tag: Tag) -> Option<usize> {
// using partition as binary search for the first field (instead of regular binary_search that returns any)
- let first = self.tags.partition_point(|&x| x < tag.0);
- self.tags
+ let first = self.tags().partition_point(|&x| x < tag.0);
+ self.tags()
.get(first)
.is_some_and(|&x| x == tag.0)
.then_some(first)
@@ -108,94 +72,97 @@ impl<'a> Object<'a> {
}
#[inline]
fn offset(&self, i: usize) -> usize {
- self.offsets
+ self.offsets()
.get(i)
.map(|&v| v >> 5)
- .unwrap_or(self.values.len() as u32) as usize
+ .unwrap_or(self.values().len() as u32) as usize
}
fn offset_type(&self, i: usize) -> ValueType {
- let raw = (self.offsets[i] >> 2) & 0b111;
+ let raw = (self.offsets()[i] >> 2) & 0b111;
ValueType::from_num(raw)
}
fn size(&self, i: usize) -> u32 {
- let start_raw = self.offsets[i];
+ let start_raw = self.offsets()[i];
let end_raw = self
- .offsets
+ .offsets()
.get(i + 1)
.copied()
- .unwrap_or((self.values.len() as u32) << 5);
+ .unwrap_or((self.values().len() as u32) << 5);
let u32_len = (end_raw >> 5) - (start_raw >> 5);
let padding = start_raw & 0b11;
u32_len * 4 - padding
}
- fn get_aligned(&self, index: usize) -> Option<&'a [u32]> {
- let start_raw = self.offsets[index];
+ fn get_aligned<'a>(&'a self, index: usize) -> Option<&'a [u32]> {
+ let start_raw = self.offsets()[index];
let end_raw = self
- .offsets
+ .offsets()
.get(index + 1)
.copied()
- .unwrap_or((self.values.len() as u32) << 5);
+ .unwrap_or((self.values().len() as u32) << 5);
let start = start_raw >> 5;
let end = end_raw >> 5;
- Some(&self.values[start as usize..end as usize])
+ Some(&self.values()[start as usize..end as usize])
}
- fn get_unaligned(&self, index: usize) -> Option<&'a [u8]> {
- let start_raw = self.offsets[index];
+ fn get_unaligned<'a>(&'a self, index: usize) -> Option<&'a [u8]> {
+ let start_raw = self.offsets()[index];
let end_raw = self
- .offsets
+ .offsets()
.get(index + 1)
.copied()
- .unwrap_or((self.values.len() as u32) << 5);
+ .unwrap_or((self.values().len() as u32) << 5);
let start = (start_raw >> 5) * 4;
let padding = start_raw & 0b11;
let end = (end_raw >> 5) * 4 - padding;
- let values_u8: &[u8] = bytemuck::cast_slice(self.values);
+ let values_u8: &[u8] = bytemuck::cast_slice(self.values());
Some(&values_u8[start as usize..end as usize])
}
#[inline]
- pub fn get_typed<T: ValueLoad<'a>>(&self, index: usize) -> Option<T> {
- if T::TYPE.is_aligned() {
- T::load_aligned(self.get_aligned(index)?)
+ pub fn get_typed<'a, T: ValueMarker<'a> + ?Sized>(&'a self, index: usize) -> Option<T::Inner> {
+ if T::Inner::TYPE.is_aligned() {
+ T::Inner::load_aligned(self.get_aligned(index)?)
} else {
- T::load_unaligned(self.get_unaligned(index)?)
+ T::Inner::load_unaligned(self.get_unaligned(index)?)
}
}
- pub fn get<T: ValueLoad<'a>>(&self, tag: TypedTag<T>) -> Option<T> {
- self.get_typed(self.find_field(tag.0)?)
+ pub fn get<'a, T: ValueMarker<'a> + ?Sized>(&'a self, tag: TypedTag<T>) -> Option<T::Inner> {
+ self.get_typed::<T>(self.find_field(tag.0)?)
}
- pub fn keys(&self) -> KeysIter<'a> {
+ pub fn keys<'a>(&'a self) -> KeysIter<'a> {
KeysIter {
- object: *self,
+ object: self,
index: 0,
}
}
- pub fn entries<T>(&self) -> EntriesIter<'a, T> {
+ pub fn entries<'a, T: ?Sized>(&'a self) -> EntriesIter<'a, T> {
EntriesIter {
- object: *self,
+ object: self,
index: 0,
ty: PhantomData,
}
}
- pub fn iter<T>(&self, tag: TypedTag<T>) -> FieldIter<'a, T> {
+ pub fn iter<'a, T: ?Sized>(&'a self, tag: TypedTag<T>) -> FieldIter<'a, T> {
FieldIter {
- object: *self,
- index: self.tags.partition_point(|&x| x < tag.0.0),
+ object: self,
+ index: self.tags().partition_point(|&x| x < tag.0.0),
tag: tag.0.0,
ty: PhantomData,
}
}
#[must_use]
- pub fn extend<T: ValueLoad<'a> + Eq + Ord>(
- &self,
+ pub fn extend<'a, T: ValueMarker<'a> + ?Sized>(
+ &'a self,
tag: TypedTag<T>,
- values: impl IntoIterator<Item = T>,
- ) -> ObjectBuffer {
+ values: impl IntoIterator<Item = T::Inner>,
+ ) -> Box<Object>
+ where
+ T::Inner: Eq + Ord,
+ {
self.insert_multi(
tag,
&self
@@ -209,71 +176,75 @@ impl<'a> Object<'a> {
#[must_use]
pub fn extend_object(
&self,
- tag: TypedTag<Object<'static>>,
+ tag: TypedTag<Object>,
ident: Tag,
- values: impl IntoIterator<Item = ObjectBuffer>,
- ) -> ObjectBuffer {
- let ident = TypedTag(ident, PhantomData::<&[u8]>);
+ values: &[Box<Object>],
+ ) -> Box<Object> {
+ let ident = TypedTag::<[u8]>::new(ident);
let mut new_vals = Vec::new();
for ob in self.iter(tag) {
- new_vals.push(ob.dump());
+ new_vals.push(ob);
}
let mut any_new = false;
for val in values {
- if new_vals
- .iter()
- .all(|rhs| rhs.as_object().get(ident) != val.as_object().get(ident))
- {
+ if new_vals.iter().all(|rhs| rhs.get(ident) != val.get(ident)) {
any_new = true;
- new_vals.push(val);
+ new_vals.push(&val);
}
}
if any_new {
- self.insert_multi(TypedTag(tag.0, PhantomData), &new_vals)
+ self.insert_multi(TypedTag::<Object>::new(tag.0), &new_vals)
} else {
- self.dump()
+ todo!()
}
}
#[must_use]
#[inline]
- pub fn insert<T: ValueStore>(&self, tag: TypedTag<T>, value: T) -> ObjectBuffer {
+ pub fn insert<'a, T: ValueMarker<'a> + ?Sized>(
+ &'a self,
+ tag: TypedTag<T>,
+ value: T::Inner,
+ ) -> Box<Object> {
self.insert_multi(tag, &[value])
}
#[must_use]
#[inline]
- pub fn remove<T: ValueStore>(&self, tag: TypedTag<T>) -> ObjectBuffer {
+ pub fn remove<'a, T: ValueMarker<'a>>(&'a self, tag: TypedTag<T>) -> Box<Object> {
self.insert_multi(tag, &[])
}
#[must_use]
- pub fn insert_multi<T: ValueStore>(&self, tag: TypedTag<T>, values: &[T]) -> ObjectBuffer {
- let prefix = self.tags.partition_point(|&x| x < tag.0.0);
- let suffix = self.tags.partition_point(|&x| x <= tag.0.0);
+ pub fn insert_multi<'a, T: ValueMarker<'a> + ?Sized>(
+ &'a self,
+ tag: TypedTag<T>,
+ values: &[T::Inner],
+ ) -> Box<Object> {
+ let prefix = self.tags().partition_point(|&x| x < tag.0.0);
+ let suffix = self.tags().partition_point(|&x| x <= tag.0.0);
let values_prefix = self.offset(prefix);
let values_suffix = self.offset(suffix);
let mut buf = Vec::new();
let cut_size = suffix - prefix;
- buf.push((self.tags.len() - cut_size + values.len()) as u32);
+ buf.push((self.tags().len() - cut_size + values.len()) as u32);
- buf.extend(&self.tags[..prefix]);
+ buf.extend(&self.tags()[..prefix]);
buf.extend(values.iter().map(|_| tag.0.0));
- buf.extend(&self.tags[suffix..]);
+ buf.extend(&self.tags()[suffix..]);
- buf.extend(&self.offsets[..prefix]);
+ buf.extend(&self.offsets()[..prefix]);
let new_offs = buf.len();
buf.extend(values.iter().map(|_| 0)); // placeholder
let suffix_offs = buf.len();
- buf.extend(&self.offsets[suffix..]); // need offsetting later
+ buf.extend(&self.offsets()[suffix..]); // need offsetting later
let suffix_end = buf.len();
let values_start = buf.len() as u32;
- buf.extend(&self.values[..values_prefix]);
+ buf.extend(&self.values()[..values_prefix]);
let mut temp = Vec::new();
let values_new = buf.len();
for (i, val) in values.iter().enumerate() {
- let ty = val.get_type();
- let off = (buf.len() as u32 - values_start) << 5 | (ty as u32) << 2;
- if ty.is_aligned() {
+ let off = (buf.len() as u32 - values_start) << 5 | (T::Inner::TYPE as u32) << 2;
+ if T::Inner::TYPE.is_aligned() {
buf[new_offs + i] = off;
val.store_aligned(&mut buf);
} else {
@@ -292,77 +263,78 @@ impl<'a> Object<'a> {
.iter_mut()
.for_each(|e| *e = e.strict_add_signed(suffix_offset));
}
- buf.extend(&self.values[values_suffix..]);
+ buf.extend(&self.values()[values_suffix..]);
- ObjectBuffer(buf)
+ vec_to_ob(buf)
}
#[must_use]
pub fn update(
&self,
- tag: TypedTag<Object<'static>>,
- update: impl FnOnce(Object<'a>) -> ObjectBuffer,
- ) -> ObjectBuffer {
- self.insert(tag, update(self.get(tag).unwrap_or_default()).as_object())
+ tag: TypedTag<Object>,
+ update: impl FnOnce(&Object) -> Box<Object>,
+ ) -> Box<Object> {
+ let ob = update(self.get(tag).unwrap_or(EMPTY));
+ self.insert(tag, &ob)
}
}
pub struct KeysIter<'a> {
- object: Object<'a>,
+ object: &'a Object,
index: usize,
}
impl Iterator for KeysIter<'_> {
type Item = Tag;
fn next(&mut self) -> Option<Self::Item> {
- if self.index >= self.object.tags.len() {
+ if self.index >= self.object.tags().len() {
return None;
} else {
self.index += 1;
- Some(Tag(self.object.tags[self.index - 1]))
+ Some(Tag(self.object.tags()[self.index - 1]))
}
}
}
-pub struct EntriesIter<'a, T> {
- object: Object<'a>,
+pub struct EntriesIter<'a, T: ?Sized> {
+ object: &'a Object,
index: usize,
ty: PhantomData<T>,
}
-impl<'a, T: ValueLoad<'a>> Iterator for EntriesIter<'a, T> {
- type Item = (Tag, T);
+impl<'a, T: ValueMarker<'a> + ?Sized> Iterator for EntriesIter<'a, T> {
+ type Item = (Tag, T::Inner);
fn next(&mut self) -> Option<Self::Item> {
loop {
- if self.index >= self.object.tags.len() {
+ if self.index >= self.object.tags().len() {
return None;
}
- if T::TYPE != self.object.offset_type(self.index) {
+ if T::Inner::TYPE != self.object.offset_type(self.index) {
self.index += 1;
continue;
}
- let value = self.object.get_typed(self.index)?;
- let tag = self.object.tags[self.index];
+ let value = self.object.get_typed::<T>(self.index)?;
+ let tag = self.object.tags()[self.index];
self.index += 1;
return Some((Tag(tag), value));
}
}
}
-pub struct FieldIter<'a, T> {
- object: Object<'a>,
+pub struct FieldIter<'a, T: ?Sized> {
+ object: &'a Object,
index: usize,
tag: u32,
ty: PhantomData<T>,
}
-impl<'a, T: ValueLoad<'a>> Iterator for FieldIter<'a, T> {
- type Item = T;
+impl<'a, T: ValueMarker<'a> + ?Sized> Iterator for FieldIter<'a, T> {
+ type Item = T::Inner;
fn next(&mut self) -> Option<Self::Item> {
- if self.index >= self.object.tags.len() {
+ if self.index >= self.object.tags().len() {
return None;
}
- if self.object.tags[self.index] != self.tag {
+ if self.object.tags()[self.index] != self.tag {
return None;
}
- let val = self.object.get_typed(self.index);
+ let val = self.object.get_typed::<T>(self.index);
self.index += 1;
val
}