#[repr(C)]
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ByteRange {
pub tag: u32,
pub start: u32,
pub end: u32,
}
impl ByteRange {
#[must_use]
pub const fn new(tag: u32, start: u32, end: u32) -> Self {
let end = if end < start { start } else { end };
Self { tag, start, end }
}
#[must_use]
pub const fn len(&self) -> u32 {
self.end - self.start
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.end == self.start
}
#[must_use]
pub const fn contains(&self, other: &ByteRange) -> bool {
self.start <= other.start && other.end <= self.end
}
#[must_use]
pub const fn ends_before(&self, other: &ByteRange) -> bool {
self.end <= other.start
}
}
#[cfg(feature = "vyre-foundation")]
mod match_bridge {
use super::ByteRange;
impl From<vyre_foundation::match_result::Match> for ByteRange {
fn from(m: vyre_foundation::match_result::Match) -> Self {
ByteRange::new(m.pattern_id, m.start, m.end)
}
}
impl From<ByteRange> for vyre_foundation::match_result::Match {
fn from(r: ByteRange) -> Self {
vyre_foundation::match_result::Match::new(r.tag, r.start, r.end)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_roundtrip() {
let r = ByteRange::new(42, 100, 200);
assert_eq!(r.tag, 42);
assert_eq!(r.start, 100);
assert_eq!(r.end, 200);
assert_eq!(r.len(), 100);
assert!(!r.is_empty());
}
#[test]
fn empty_is_zero_length() {
let r = ByteRange::new(1, 5, 5);
assert!(r.is_empty());
assert_eq!(r.len(), 0);
}
#[test]
fn contains_inclusive_bounds() {
let outer = ByteRange::new(0, 0, 100);
let inner = ByteRange::new(0, 10, 90);
assert!(outer.contains(&inner));
assert!(!inner.contains(&outer));
assert!(outer.contains(&outer));
}
#[test]
fn ends_before_requires_disjoint() {
let a = ByteRange::new(0, 0, 10);
let b = ByteRange::new(0, 10, 20);
let c = ByteRange::new(0, 5, 15);
assert!(a.ends_before(&b));
assert!(!a.ends_before(&c));
}
#[cfg(feature = "vyre-foundation")]
#[test]
fn bridge_from_match_preserves_fields() {
let m = vyre_foundation::match_result::Match::new(7, 11, 22);
let r: ByteRange = m.into();
assert_eq!(r.tag, 7);
assert_eq!(r.start, 11);
assert_eq!(r.end, 22);
}
#[cfg(feature = "vyre-foundation")]
#[test]
fn bridge_back_to_match_preserves_fields() {
let r = ByteRange::new(9, 13, 33);
let m: vyre_foundation::match_result::Match = r.into();
assert_eq!(m.pattern_id, 9);
assert_eq!(m.start, 13);
assert_eq!(m.end, 33);
}
#[test]
fn layout_is_repr_c_u32x3() {
assert_eq!(std::mem::size_of::<ByteRange>(), 12);
assert_eq!(std::mem::align_of::<ByteRange>(), 4);
}
}