/* 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) 2025 metamuffin */ mod value; pub use value::*; use std::marker::PhantomData; #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Tag(pub u32); pub struct TypedTag(pub Tag, pub PhantomData); pub struct ObjectBuffer(pub Vec); impl ObjectBuffer { pub fn new() -> Self { Self(vec![0]) } pub fn as_object<'a>(&'a self) -> Object<'a> { Object::load(&self.0).unwrap() } } pub struct Object<'a> { tags: &'a [u32], offsets: &'a [u32], values: &'a [u32], } impl<'a> Object<'a> { pub fn load(buf: &'a [u32]) -> Option { let nf = *buf.get(0)? as usize; Some(Self { tags: &buf[1..1 + nf], offsets: &buf[1 + nf..1 + nf + nf], values: &buf[1 + nf + nf..], }) } pub fn get_aligned(&self, tag: Tag) -> Option<&[u32]> { let index = self.tags.binary_search(&tag.0).ok()?; let start_raw = *self.offsets.get(index)?; let end_raw = self .offsets .get(index) .copied() .unwrap_or((self.values.len() as u32) << 2); let start = start_raw >> 2; let end = end_raw >> 2; Some(&self.values[start as usize..end as usize]) } pub fn get_unaligned(&self, tag: Tag) -> Option<&[u8]> { let index = self.tags.binary_search(&tag.0).ok()?; let start_raw = *self.offsets.get(index)?; let end_raw = self .offsets .get(index) .copied() .unwrap_or((self.values.len() as u32) << 2); let start = (start_raw >> 2) * 4; let padding = start_raw & 0b11; let end = (end_raw >> 2) * 4 - padding; let values_u8: &[u8] = bytemuck::cast_slice(self.values); Some(&values_u8[start as usize..end as usize]) } pub fn get_str(&self, tag: Tag) -> Option<&str> { self.get_unaligned(tag).and_then(|b| str::from_utf8(b).ok()) } pub fn get<'b: 'a, T: Value<'b>>(&'b self, tag: TypedTag) -> Option { if T::ALIGNED { T::load_aligned(self.get_aligned(tag.0)?) } else { T::load_unaligned(self.get_unaligned(tag.0)?) } } }