/// Position of an entry's value on disk.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct DiskLoc {
    pub offset: u32,
    pub len: u32,
    pub file_id: u32,
}

impl DiskLoc {
    #[inline]
    pub fn new(file_id: u32, offset: u32, len: u32) -> Self {
        Self {
            offset,
            len,
            file_id,
        }
    }

    /// True when this value is routed to the whole-value cache (> 2 blocks)
    /// rather than the 4 KiB block cache. Threshold fixed at 8192 bytes
    /// (`start_within_block + len`). See the value-cache design.
    #[cfg(feature = "var-collections")]
    #[inline]
    pub(crate) fn is_value_cache_routed(&self) -> bool {
        (self.offset & 4095) as usize + self.len as usize > 8192
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::mem::{align_of, size_of};

    #[test]
    fn disk_loc_size_is_12() {
        assert_eq!(size_of::<DiskLoc>(), 12);
    }

    #[test]
    fn disk_loc_alignment_is_4() {
        assert_eq!(align_of::<DiskLoc>(), 4);
    }

    #[test]
    fn disk_loc_roundtrip_large_file_id() {
        for &fid in &[0u32, 1, 65535, 65536, 65537, 1_000_000, u32::MAX] {
            let loc = DiskLoc::new(fid, 4096, 1024);
            assert_eq!(loc.file_id, fid);
            assert_eq!(loc.offset, 4096);
            assert_eq!(loc.len, 1024);
        }
    }
}
