diff options
Diffstat (limited to 'common/object/src/lib.rs')
| -rw-r--r-- | common/object/src/lib.rs | 276 |
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 } |