C36737FJVMZSBWSQV7ZEYRYUPJVNLK3MGY3EJVAPYHYAM36J7TJQC
YDHYZA77LFQ7RSKTVOTOQRL7EUSXMWYOSJAE5YAH6HLHE64B75LQC
XOXTGNPZRTDWNCZ5BI723A6CZ6LLTP4RXIGVWYYK7NQVRWZEZ77AC
QYDGYIZRNFRIQD7RUCY5YAN3F2THZA74E5UOHPIFWSULEJFAFVJQC
OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC
CCNPHVQCIGINWTLXCHOASGVWUPBZXFOLM2F7HTKMEA2DMFTOX7TAC
SYURNHHL3P22ZAERTML4YW3DYLATHY5ALZH4GL5NF3LENDSKL2NQC
E4MD6T3LNOYWVFTFFWCUKRNS4M2XVSKRLDWPYHMZHGDNO2T5JREQC
SO25TWFLSRQIVTJTTSN77LO5FZQVQPIZTSBULH7MWBBDEWSK3OCAC
OHUZ73MKWD7SSB4DKKA532DEQKXQDS6PZ6HJ3EC2DLVJSLQH3NLAC
YXKP4AIWDBIWBBUDWF66YIPG5ECMHNKEV3PX6KYXOVXY3EWG3WGQC
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct Ref {
p: u64,
len: u64,
}
pub union Slice<'b> {
len: u16,
page: Ref,
mem: Mem<'b>,
}
#[derive(Clone, Copy)]
#[repr(C)]
struct Mem<'b> {
_len: u16,
m: &'b [u8],
}
impl<'a> core::fmt::Debug for Slice<'a> {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(fmt, "Slice({:?})", unsafe { self.len })
}
}
impl<'a> core::convert::From<&'a [u8]> for Slice<'a> {
fn from(m: &'a [u8]) -> Slice<'a> {
let s = Slice {
mem: Mem { _len: 513, m },
};
s
}
}
impl<'a> Slice<'a> {
pub fn as_bytes<T: LoadPage>(&self, txn: &T) -> Result<&[u8], T::Error> {
Ok(unsafe {
let len = u16::from_le(self.len) & 0xfff;
if len == 512 {
// Stored externally
let p = txn.load_page(u64::from_le(self.page.p) & !0xfff)?;
core::slice::from_raw_parts(p.data, u64::from_le(self.page.len) as usize)
} else if len == 513 {
// Stored in memory, not on any page
self.mem.m
} else {
core::slice::from_raw_parts(
(&self.len as *const u16 as *const u8).add(2),
len as usize,
)
}
})
}
}
impl<'a> Storable for Slice<'a> {
type PageReferences = Pages;
fn page_references(&self) -> Self::PageReferences {
unsafe {
let len = u16::from_le(self.len);
if len == 512 {
let plen = u64::from_le(self.page.len);
let len_up = ((plen + PAGE_SIZE as u64 - 1) / PAGE_SIZE as u64)
* PAGE_SIZE as u64;
let offset = u64::from_le(self.page.p) & !0xfff;
Pages {
offset,
limit: offset + len_up,
}
} else {
Pages {
offset: 0,
limit: 0,
}
}
}
}
fn compare<T: LoadPage>(&self, t: &T, b: &Self) -> core::cmp::Ordering {
self.as_bytes(t).unwrap().cmp(b.as_bytes(t).unwrap())
}
}
pub struct Pages {
offset: u64,
limit: u64,
}
impl Iterator for Pages {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.limit {
None
} else {
let o = self.offset;
self.offset += PAGE_SIZE as u64;
Some(o)
}
}
impl<'b> UnsizedStorable for Slice<'b> {
const ALIGN: usize = 8;
fn size(&self) -> usize {
let s = unsafe {
if u16::from_le(self.len) == 512 {
// Stored externally
16
} else if u16::from_le(self.len) == 513 {
// Stored in memory, not on any page
if self.mem.m.len() > 510 {
16
} else {
2 + self.mem.m.len()
}
} else {
u16::from_le(self.len) as usize
}
};
s
}
unsafe fn from_raw_ptr<'a, T>(_: &T, p: *const u8) -> &'a Self {
&*(p as *const Self)
}
unsafe fn onpage_size(p: *const u8) -> usize {
let p = &*(p as *const Self);
if u16::from_le(p.len) == 512 {
// Stored externally
16
} else if u16::from_le(p.len) == 513 {
// Stored in memory, not on any page
2 + p.mem.m.len()
} else {
u16::from_le(p.len) as usize
}
}
unsafe fn write_to_page<T: AllocPage>(&self, t: &mut T, p: *mut u8) {
if self.len == 512 {
// Stored externally
core::ptr::copy(&self.page as *const Ref as *const u8, p, 16)
} else if self.len == 513 {
// Alloc ?
if self.mem.m.len() > 510 {
let len = self.mem.m.len();
let page = if len > 4096 {
t.alloc_contiguous(
(((len + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE)
as u64
).unwrap()
} else {
t.alloc_page().unwrap()
};
core::ptr::copy_nonoverlapping(self.mem.m.as_ptr(), page.0.data, len);
let p = &mut *(p as *mut Ref);
p.len = (self.mem.m.len() as u64).to_le();
p.p = (page.0.offset | 512).to_le();
} else {
let len = self.mem.m.len();
*(p as *mut u16) = (len as u16).to_le();
core::ptr::copy_nonoverlapping(self.mem.m.as_ptr(), p.add(2), len)
}
} else {
core::ptr::copy(&self.len as *const u16 as *const u8, p, 2 + u16::from_le(self.len) as usize)
}
}
}
pub use sanakirja_core::{btree, direct_repr, LoadPage, AllocPage, Storable, UnsizedStorable, MutPage, CowPage, Page};
pub use sanakirja_core::{btree, direct_repr, LoadPage, AllocPage, Storable, UnsizedStorable, MutPage, CowPage, Page, Slice};