use crate::layout::HopperHeader;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct Segment {
pub offset: u32,
pub size: u32,
}
impl Segment {
#[inline(always)]
pub const fn new(offset: u32, size: u32) -> Self {
Self { offset, size }
}
#[inline(always)]
pub const fn body(body_offset: u32, size: u32) -> Self {
Self {
offset: HopperHeader::SIZE as u32 + body_offset,
size,
}
}
#[inline(always)]
pub const fn end(&self) -> u32 {
self.offset + self.size
}
#[inline(always)]
pub const fn overlaps(&self, other: &Segment) -> bool {
self.offset < other.end() && other.offset < self.end()
}
#[inline(always)]
pub const fn contained_in(&self, container: &Segment) -> bool {
self.offset >= container.offset && self.end() <= container.end()
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct TypedSegment<T: crate::Pod, const OFFSET: u32> {
_marker: core::marker::PhantomData<fn() -> T>,
}
impl<T: crate::Pod, const OFFSET: u32> TypedSegment<T, OFFSET> {
#[inline(always)]
pub const fn new() -> Self {
Self { _marker: core::marker::PhantomData }
}
#[inline(always)]
pub const fn offset() -> u32 {
OFFSET
}
#[inline(always)]
pub const fn size() -> u32 {
core::mem::size_of::<T>() as u32
}
#[inline(always)]
pub const fn end() -> u32 {
OFFSET + core::mem::size_of::<T>() as u32
}
#[inline(always)]
pub const fn as_segment() -> Segment {
Segment::new(OFFSET, core::mem::size_of::<T>() as u32)
}
}
const _: () = {
assert!(
core::mem::size_of::<TypedSegment<u64, 0>>() == 0,
"TypedSegment must be zero-sized so it costs nothing to pass around",
);
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn typed_segment_is_zero_sized() {
assert_eq!(core::mem::size_of::<TypedSegment<u64, 16>>(), 0);
}
#[test]
fn typed_segment_offset_and_size_fold() {
const S: TypedSegment<u64, 16> = TypedSegment::new();
assert_eq!(TypedSegment::<u64, 16>::offset(), 16);
assert_eq!(TypedSegment::<u64, 16>::size(), 8);
assert_eq!(TypedSegment::<u64, 16>::end(), 24);
let _ = S; }
#[test]
fn typed_segment_lowers_to_runtime_segment() {
const S: Segment = TypedSegment::<u64, 16>::as_segment();
assert_eq!(S.offset, 16);
assert_eq!(S.size, 8);
}
#[test]
fn body_adds_header() {
let s = Segment::body(0, 8);
assert_eq!(s.offset, HopperHeader::SIZE as u32);
assert_eq!(s.size, 8);
assert_eq!(s.end(), HopperHeader::SIZE as u32 + 8);
}
#[test]
fn overlaps_detects_shared_bytes() {
let a = Segment::new(0, 16);
let b = Segment::new(8, 16);
let c = Segment::new(16, 16);
assert!(a.overlaps(&b));
assert!(!a.overlaps(&c)); assert!(b.overlaps(&c));
}
#[test]
fn contained_in_reports_proper_nesting() {
let outer = Segment::new(0, 32);
let inner = Segment::new(8, 8);
let equal = Segment::new(0, 32);
let escape = Segment::new(24, 16);
assert!(inner.contained_in(&outer));
assert!(equal.contained_in(&outer));
assert!(!escape.contained_in(&outer));
}
}