lunar-lib 0.10.0

Common utilities for lunar applications
Documentation
use std::sync::LazyLock;

use serde::{Deserialize, Serialize};

use crate::{
    database::{DatabaseEntry, Db, Id, Mergeable},
    vec_ext::VecExtensions,
};

define_db!(Test {
   fn path() -> Option<std::path::PathBuf> {
       None
   }
});

static TEMP_DB: LazyLock<Db<Test>> = LazyLock::new(|| Db::open().unwrap());

pub fn id_from_short_slice<T: DatabaseEntry>(slice: &'static [u8; 4]) -> Id<T> {
    let mut buf = [0u8; 32];
    buf[28..].copy_from_slice(slice);
    Id::from(buf)
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Item {
    field: u32,
    option: Option<u32>,
    vec: Vec<u32>,
    unqiue_vec: Vec<u32>,
}

impl DatabaseEntry for Item {
    type DbInner = Test;

    const VERSION_NUMBER: u32 = 1;

    const TREE_NAME: &str = "item";
}

impl Mergeable for Item {
    fn merge_data(&mut self, from: Self) {
        self.field = from.field;
        self.option = self.option.or(from.option);
        self.vec.extend(from.vec);
        self.unqiue_vec.extend_unique(from.unqiue_vec);
    }

    fn relink_references(
        _from: &super::Entry<Self>,
        _to: Id<Self>,
        _cas_tx: &mut super::CompareAndSwapTransaction<Self::DbInner>,
    ) -> Result<(), super::TransactionError> {
        Ok(())
    }
}

#[test]
fn test_insert() {
    let item = Item {
        field: 10,
        option: None,
        vec: vec![0; 10],
        unqiue_vec: vec![1, 2, 3, 4, 5],
    };

    let id = id_from_short_slice(b"UPSR");
    let entry = item.clone().to_entry(id);
    entry.db_insert(&*TEMP_DB).unwrap();

    assert_eq!(id.db_get(&*TEMP_DB).unwrap().unwrap().into_item(), item)
}

#[test]
fn test_patch() {
    let item_a = Item {
        field: 10,
        option: None,
        vec: vec![0; 3],
        unqiue_vec: vec![1, 2, 3, 4, 5],
    };
    let item_b = Item {
        field: 20,
        option: Some(10),
        vec: vec![1; 3],
        unqiue_vec: vec![3, 4, 5, 6, 7],
    };

    let id = id_from_short_slice(b"PTCH");
    let entry_a = item_a.clone().to_entry(id);
    entry_a.db_insert(&*TEMP_DB).unwrap();

    let entry_b = item_b.clone().to_entry(id);
    entry_b.db_patch(&*TEMP_DB).unwrap();

    let test_patched = Item {
        field: 20,
        option: Some(10),
        vec: vec![0, 0, 0, 1, 1, 1],
        unqiue_vec: vec![1, 2, 3, 4, 5, 6, 7],
    };

    assert_eq!(
        id.db_get(&*TEMP_DB).unwrap().unwrap().into_item(),
        test_patched
    )
}