use std::fmt;
use crate::segment::identifier::SegmentIdentifier;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[repr(u8)]
pub enum RecordType {
MapLeaf = 0,
MapBranch = 1,
ListBucket = 2,
List = 3,
Value = 4,
Block = 5,
Template = 6,
Node = 7,
ExternalBlobIdentifier = 8,
}
impl RecordType {
#[must_use]
pub const fn from_byte(byte: u8) -> Option<Self> {
match byte {
0 => Some(Self::MapLeaf),
1 => Some(Self::MapBranch),
2 => Some(Self::ListBucket),
3 => Some(Self::List),
4 => Some(Self::Value),
5 => Some(Self::Block),
6 => Some(Self::Template),
7 => Some(Self::Node),
8 => Some(Self::ExternalBlobIdentifier),
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct RecordIdentifier {
pub segment: SegmentIdentifier,
pub record_number: u32,
}
impl RecordIdentifier {
#[must_use]
pub const fn new(segment: SegmentIdentifier, record_number: u32) -> Self {
Self {
segment,
record_number,
}
}
}
impl fmt::Display for RecordIdentifier {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}.{:08x}", self.segment, self.record_number)
}
}
impl fmt::Debug for RecordIdentifier {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "RecordIdentifier({self})")
}
}
#[cfg(test)]
mod tests {
use super::{RecordIdentifier, RecordType};
use crate::segment::identifier::SegmentIdentifier;
#[test]
fn record_type_bytes_round_trip() {
for byte in 0..=8u8 {
let record_type = RecordType::from_byte(byte).expect("valid record type byte");
assert_eq!(record_type as u8, byte);
}
assert_eq!(RecordType::from_byte(9), None);
assert_eq!(RecordType::from_byte(255), None);
}
#[test]
fn record_identifier_formats_like_oak() {
let identifier = RecordIdentifier::new(
SegmentIdentifier::new(0xF813_78FB_92B1_4B52, 0xA5C8_E0A6_7152_ED2C),
0x0002_21A8,
);
assert_eq!(
identifier.to_string(),
"f81378fb-92b1-4b52-a5c8-e0a67152ed2c.000221a8"
);
}
}