use crate::imp::core::datasection::{lookup_key as core_lookup_key, DataView};
use crate::imp::core::Bytes32;
use crate::imp::core::KeyTableEntry;
use alloc::vec::Vec;
pub use crate::imp::core::datasection::{encode_key_table, SectionId};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SectionError;
pub struct DataSection<'a> {
view: DataView<'a>,
}
impl<'a> DataSection<'a> {
pub fn parse(raw: &'a [u8]) -> Result<Self, SectionError> {
let view = DataView::parse(raw).map_err(|_| SectionError)?;
Ok(DataSection { view })
}
pub fn section(&self, id: SectionId) -> Option<&'a [u8]> {
self.view.section(id)
}
pub fn total_len(&self) -> usize {
self.view.total_len()
}
pub fn store_id(&self) -> Bytes32 {
bytes32_or_zero(self.section(SectionId::StoreId))
}
pub fn current_root(&self) -> Bytes32 {
bytes32_or_zero(self.section(SectionId::CurrentRoot))
}
pub fn lookup_key(&self, retrieval_key: &Bytes32) -> Option<KeyTableEntry> {
let body = self.section(SectionId::KeyTable)?;
core_lookup_key(body, retrieval_key)
}
}
fn bytes32_or_zero(section: Option<&[u8]>) -> Bytes32 {
let s = section.unwrap_or(&[]);
let mut a = [0u8; 32];
let n = s.len().min(32);
a[..n].copy_from_slice(&s[..n]);
Bytes32(a)
}
#[cfg(target_arch = "wasm32")]
pub fn embedded<'a>() -> DataSection<'a> {
use crate::imp::core::datasection::DIGS_DATA_OFFSET;
const HEADER_LEN: usize = 9;
const ROW_LEN: usize = 10;
let empty = || DataSection {
view: DataView::parse(EMPTY_BLOB).unwrap(),
};
unsafe {
let base = DIGS_DATA_OFFSET as *const u8;
let header = core::slice::from_raw_parts(base, HEADER_LEN);
if &header[0..4] != b"DIGS" || header[4] != 1 {
return empty();
}
let count = u32::from_be_bytes([header[5], header[6], header[7], header[8]]) as usize;
let table_len = match count
.checked_mul(ROW_LEN)
.and_then(|t| t.checked_add(HEADER_LEN))
{
Some(n) => n,
None => return empty(),
};
let head_and_rows = core::slice::from_raw_parts(base, table_len);
let mut total_len = table_len;
for i in 0..count {
let p = HEADER_LEN + i * ROW_LEN;
let offset = u32::from_be_bytes([
head_and_rows[p + 2],
head_and_rows[p + 3],
head_and_rows[p + 4],
head_and_rows[p + 5],
]) as usize;
let len = u32::from_be_bytes([
head_and_rows[p + 6],
head_and_rows[p + 7],
head_and_rows[p + 8],
head_and_rows[p + 9],
]) as usize;
let end = match offset.checked_add(len) {
Some(e) => e,
None => return empty(),
};
if end > total_len {
total_len = end;
}
}
let full = core::slice::from_raw_parts(base, total_len);
DataSection::parse(full).unwrap_or_else(|_| empty())
}
}
#[cfg(target_arch = "wasm32")]
const EMPTY_BLOB: &[u8] = b"DIGS\x01\x00\x00\x00\x00";
pub fn from_blob(blob: &[u8]) -> Result<DataSection<'_>, SectionError> {
DataSection::parse(blob)
}
pub fn encode_blob(sections: &[(u16, Vec<u8>)]) -> Vec<u8> {
crate::imp::core::datasection::encode_blob(sections)
}