aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-01-06 23:43:05 +0100
committermetamuffin <metamuffin@disroot.org>2026-01-06 23:43:05 +0100
commitf932d4de439c6472d34ed4bbf530fca13b84d73a (patch)
treeb64f28fc6bdf40a38ed6e08cc7ce4602d3a4c537
parentffa6b5c4ae2cdd3e07426ed0330f3f66e90ee57b (diff)
downloadjellything-f932d4de439c6472d34ed4bbf530fca13b84d73a.tar
jellything-f932d4de439c6472d34ed4bbf530fca13b84d73a.tar.bz2
jellything-f932d4de439c6472d34ed4bbf530fca13b84d73a.tar.zst
object insert
-rw-r--r--common/object/src/buffer.rs15
-rw-r--r--common/object/src/lib.rs78
-rw-r--r--common/object/src/tests.rs10
-rw-r--r--database/src/table.rs11
4 files changed, 106 insertions, 8 deletions
diff --git a/common/object/src/buffer.rs b/common/object/src/buffer.rs
index dbde833..2f9d066 100644
--- a/common/object/src/buffer.rs
+++ b/common/object/src/buffer.rs
@@ -24,8 +24,9 @@ impl ObjectBuffer {
let mut temp = Vec::new();
for (tag, val) in fields {
tags.push(tag.0);
+ let off = (values.len() as u32) << 2;
if val.is_aligned() {
- offsets.push((values.len() as u32) << 2);
+ offsets.push(off);
val.store_aligned(&mut values);
} else {
temp.clear();
@@ -35,7 +36,7 @@ impl ObjectBuffer {
pad += 1;
temp.push(0);
}
- offsets.push(((values.len() as u32) << 2) | pad);
+ offsets.push(off | pad);
values.extend(bytemuck::cast_slice(&temp)); // ok bc. temp length is a whole number of dwords
}
}
@@ -60,3 +61,13 @@ impl From<Vec<u8>> for ObjectBuffer {
}))
}
}
+
+#[inline]
+pub(super) fn pad_vec(temp: &mut Vec<u8>) -> u32 {
+ let mut pad = 0;
+ while temp.len() % 4 != 0 {
+ pad += 1;
+ temp.push(0);
+ }
+ pad
+}
diff --git a/common/object/src/lib.rs b/common/object/src/lib.rs
index 522b6c1..540ce1c 100644
--- a/common/object/src/lib.rs
+++ b/common/object/src/lib.rs
@@ -47,6 +47,13 @@ impl<'a> Object<'a> {
.is_some_and(|&x| x == tag.0)
.then_some(first)
}
+ #[inline]
+ fn offset(&self, i: usize) -> usize {
+ self.offsets
+ .get(i)
+ .map(|&v| v >> 2)
+ .unwrap_or(self.values.len() as u32) as usize
+ }
fn get_aligned(&self, index: usize) -> Option<&[u32]> {
let start_raw = self.offsets[index];
let end_raw = self
@@ -86,6 +93,12 @@ 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> {
+ ObjectIter {
+ object: self,
+ index: 0,
+ }
+ }
pub fn iter<'b: 'a, T>(&'b self, tag: TypedTag<T>) -> FieldIter<'b, T> {
FieldIter {
object: self,
@@ -94,6 +107,71 @@ impl<'a> Object<'a> {
ty: PhantomData,
}
}
+ pub fn insert<T: ValueStore>(&self, tag: TypedTag<T>, value: T) -> ObjectBuffer {
+ self.insert_multi(tag, &[value])
+ }
+ 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);
+ let values_prefix = self.offset(prefix + 1);
+ let values_suffix = self.offset(suffix + 1);
+
+ let mut buf = Vec::new();
+ let cut_size = suffix - prefix;
+ buf.push((self.tags.len() - cut_size + values.len()) as u32);
+
+ buf.extend(&self.tags[..prefix]);
+ buf.extend(values.iter().map(|_| tag.0.0));
+ buf.extend(&self.tags[suffix..]);
+
+ 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
+ let suffix_end = buf.len();
+
+ let values_start = buf.len() as u32;
+ buf.extend(&self.values[..values_prefix]);
+ let mut temp = Vec::new();
+ let values_new = buf.len();
+ for (i, val) in values.iter().enumerate() {
+ let off = (buf.len() as u32 - values_start) << 2;
+ if val.is_aligned() {
+ buf[new_offs + i] = off;
+ val.store_aligned(&mut buf);
+ } else {
+ temp.clear();
+ val.store_unaligned(&mut temp);
+ let pad = pad_vec(&mut temp);
+ buf[new_offs + i] = off | pad;
+ buf.extend(bytemuck::cast_slice(&temp));
+ }
+ }
+ let insert_size = (buf.len() - values_new) as u32;
+ buf[suffix_offs..suffix_end]
+ .iter_mut()
+ .for_each(|e| *e += insert_size << 2);
+ buf.extend(&self.values[values_suffix..]);
+
+ ObjectBuffer(buf)
+ }
+}
+
+pub struct ObjectIter<'a> {
+ object: &'a Object<'a>,
+ index: usize,
+}
+impl Iterator for ObjectIter<'_> {
+ type Item = Tag;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.index >= self.object.tags.len() {
+ return None;
+ } else {
+ self.index += 1;
+ Some(Tag(self.object.tags[self.index - 1]))
+ }
+ }
}
pub struct FieldIter<'a, T> {
diff --git a/common/object/src/tests.rs b/common/object/src/tests.rs
index 143782c..181b46f 100644
--- a/common/object/src/tests.rs
+++ b/common/object/src/tests.rs
@@ -49,3 +49,13 @@ fn vec_align_test() {
}
assert_eq!(c, 10_000, "correctly aligned vecs by system allocator")
}
+
+#[test]
+fn insert() {
+ let bob = test_object();
+ let edward = bob.as_object().insert(NAME, "Edward");
+
+ let edward = edward.as_object();
+ eprintln!("{edward:#?}");
+ assert_eq!(edward.get(NAME), Some("Edward"));
+}
diff --git a/database/src/table.rs b/database/src/table.rs
index 42e03a3..16b9ed5 100644
--- a/database/src/table.rs
+++ b/database/src/table.rs
@@ -4,14 +4,12 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use std::sync::Arc;
-
use crate::{
backends::{ReadTransaction, WriteTransaction},
indices::Index,
};
use anyhow::Result;
-use jellycommon::jellyobject::{Object, ObjectBuffer};
+use jellycommon::jellyobject::ObjectBuffer;
pub type TableNum = u64;
pub type RowNum = u64;
@@ -33,7 +31,7 @@ impl Table {
key.extend(row.to_be_bytes());
key
}
- pub fn insert(&self, db: &mut dyn WriteTransaction, entry: T) -> Result<RowNum> {
+ pub fn insert(&self, db: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result<RowNum> {
let mut id_counter = db
.get(&self.id.to_be_bytes())?
.map(|k| k.as_slice().try_into().map(RowNum::from_be_bytes).ok())
@@ -43,10 +41,11 @@ impl Table {
id_counter += 1;
db.set(&self.id.to_be_bytes(), &id_counter.to_be_bytes())?;
- db.set(&self.key(row), &serde_json::to_vec(&entry)?)?;
+ db.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
+ let ob = entry.as_object();
for idx in &self.indices {
- idx.add(db, row, &entry)?;
+ idx.add(db, row, ob)?;
}
Ok(id_counter)