aboutsummaryrefslogtreecommitdiff
path: root/database/src/indices/reference.rs
blob: 66efa248b0afb7446a73e6942205140004adc02e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*
    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::{
    backends::{ReadTransaction, WriteTransaction},
    indices::Index,
    prefix_iterator::PrefixIterator,
    table::{RowNum, TableNum},
};
use anyhow::Result;
use bytemuck::{NoUninit, bytes_of};
use jellycommon::jellyobject::{Object, TypedTag};

pub struct ReferenceIndex {
    id: TableNum,
    tag: TypedTag<RowNum>,
}

#[repr(C)]
#[derive(NoUninit, Clone, Copy)]
pub struct Key(TableNum, RowNum, RowNum);

impl ReferenceIndex {
    pub fn new(id: TableNum, tag: TypedTag<RowNum>) -> Self {
        Self { id, tag }
    }
    pub fn lookup<'a>(
        &self,
        db: &'a dyn ReadTransaction,
        to: RowNum,
    ) -> Result<PrefixIterator<'a>> {
        let mut prefix = Vec::new();
        prefix.extend(self.id.to_be_bytes());
        prefix.extend(to.to_be_bytes());
        Ok(PrefixIterator {
            inner: db.iter(&prefix, false)?,
            prefix: prefix.into(),
        })
    }
}
impl Index for ReferenceIndex {
    fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, val: Object) -> Result<()> {
        for to in val.iter(self.tag) {
            db.set(bytes_of(&Key(self.id, to, id)), &[])?;
        }
        Ok(())
    }
    fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, val: Object) -> Result<()> {
        for to in val.iter(self.tag) {
            db.del(bytes_of(&Key(self.id, to, id)))?;
        }
        Ok(())
    }
    fn compare(&self, before: Object, after: Object) -> bool {
        let mut before = before.iter(self.tag);
        let mut after = after.iter(self.tag);
        loop {
            let b = before.next();
            let a = after.next();
            if a.is_none() && b.is_none() {
                break true;
            }
            if a != b {
                break false;
            }
        }
    }
}