use crate::backend::native::NativeBackendError;
use crate::backend::native::types::NativeResult;
#[derive(Debug, Clone)]
pub struct PersistentHeaderV2 {
pub magic: [u8; 8],
pub version: u32,
pub flags: u32,
pub node_count: u64,
pub edge_count: u64,
pub schema_version: u32,
pub reserved: u32,
pub node_data_offset: u64,
pub edge_data_offset: u64,
pub outgoing_cluster_offset: u64,
pub incoming_cluster_offset: u64,
pub free_space_offset: u64,
}
pub mod offset {
pub const MAGIC: usize = 0; pub const VERSION: usize = 8; pub const FLAGS: usize = 12; pub const NODE_COUNT: usize = 16; pub const EDGE_COUNT: usize = 24; pub const SCHEMA_VERSION: usize = 32; pub const RESERVED: usize = 36; pub const NODE_DATA_OFFSET: usize = 40; pub const EDGE_DATA_OFFSET: usize = 48; pub const OUTGOING_CLUSTER_OFFSET: usize = 56; pub const INCOMING_CLUSTER_OFFSET: usize = 64; pub const FREE_SPACE_OFFSET: usize = 72; }
pub mod size {
pub const MAGIC: usize = 8;
pub const VERSION: usize = 4;
pub const FLAGS: usize = 4;
pub const NODE_COUNT: usize = 8;
pub const EDGE_COUNT: usize = 8;
pub const SCHEMA_VERSION: usize = 4; pub const RESERVED: usize = 4; pub const NODE_DATA_OFFSET: usize = 8;
pub const EDGE_DATA_OFFSET: usize = 8;
pub const OUTGOING_CLUSTER_OFFSET: usize = 8;
pub const INCOMING_CLUSTER_OFFSET: usize = 8;
pub const FREE_SPACE_OFFSET: usize = 8;
}
impl PersistentHeaderV2 {
pub fn new_v2() -> Self {
use crate::backend::native::v2::{V2_FORMAT_VERSION, V2_MAGIC};
Self {
magic: V2_MAGIC,
version: V2_FORMAT_VERSION,
flags: crate::backend::native::constants::DEFAULT_FEATURE_FLAGS,
node_count: 0,
edge_count: 0,
schema_version: crate::backend::native::constants::DEFAULT_SCHEMA_VERSION,
reserved: 0,
node_data_offset: crate::backend::native::constants::HEADER_SIZE,
edge_data_offset: crate::backend::native::constants::HEADER_SIZE,
outgoing_cluster_offset: 0,
incoming_cluster_offset: 0,
free_space_offset: 0,
}
}
pub fn validate(&self) -> NativeResult<()> {
use crate::backend::native::constants;
if self.magic != constants::MAGIC_BYTES {
return Err(NativeBackendError::InvalidMagic {
expected: u64::from_be_bytes(constants::MAGIC_BYTES),
found: u64::from_be_bytes(self.magic),
});
}
if self.version != constants::FILE_FORMAT_VERSION {
return Err(NativeBackendError::UnsupportedVersion {
version: self.version,
supported_version: constants::FILE_FORMAT_VERSION,
});
}
let required_flags = constants::FLAG_V2_FRAMED_RECORDS | constants::FLAG_V2_ATOMIC_COMMIT;
if (self.flags & required_flags) != required_flags {
return Err(NativeBackendError::UnsupportedVersion {
version: 1, supported_version: constants::FILE_FORMAT_VERSION,
});
}
if self.node_data_offset < constants::HEADER_SIZE {
return Err(NativeBackendError::InvalidHeader {
field: "node_data_offset".to_string(),
reason: "must be >= header_size".to_string(),
});
}
if self.edge_data_offset < self.node_data_offset {
return Err(NativeBackendError::InvalidHeader {
field: "edge_data_offset".to_string(),
reason: "must be >= node_data_offset".to_string(),
});
}
if self.outgoing_cluster_offset > 0 && self.outgoing_cluster_offset < self.node_data_offset
{
return Err(NativeBackendError::InvalidHeader {
field: "outgoing_cluster_offset".to_string(),
reason: "must be >= node_data_offset".to_string(),
});
}
if self.incoming_cluster_offset > 0
&& self.incoming_cluster_offset < self.outgoing_cluster_offset
{
return Err(NativeBackendError::InvalidHeader {
field: "incoming_cluster_offset".to_string(),
reason: "must be >= outgoing_cluster_offset".to_string(),
});
}
if self.free_space_offset > 0 && self.free_space_offset < self.incoming_cluster_offset {
return Err(NativeBackendError::InvalidHeader {
field: "free_space_offset".to_string(),
reason: "must be >= incoming_cluster_offset".to_string(),
});
}
Ok(())
}
}
pub const PERSISTENT_HEADER_SIZE: usize = size::MAGIC
+ size::VERSION
+ size::FLAGS
+ size::NODE_COUNT
+ size::EDGE_COUNT
+ size::SCHEMA_VERSION
+ size::RESERVED
+ size::NODE_DATA_OFFSET
+ size::EDGE_DATA_OFFSET
+ size::OUTGOING_CLUSTER_OFFSET
+ size::INCOMING_CLUSTER_OFFSET
+ size::FREE_SPACE_OFFSET;
const _: [(); 80] = [(); PERSISTENT_HEADER_SIZE];