plotnik_lib/ir/
slice.rs

1//! Relative range within a segment.
2//!
3//! `start_index` is an **element index**, not a byte offset. This naming
4//! distinguishes it from byte offsets like `StringRef.offset`.
5//!
6//! This struct is 8 bytes with 4-byte alignment for efficient access.
7//! Type safety is provided through generic methods, not stored PhantomData.
8
9use std::marker::PhantomData;
10
11/// Relative range within a compiled query segment.
12///
13/// Used for variable-length data (successors, effects, negated fields, type members).
14/// The slice references elements by index into the corresponding segment array.
15///
16/// Layout: 8 bytes (4 + 2 + 2), align 4.
17#[repr(C)]
18#[derive(Clone, Copy)]
19pub struct Slice<T> {
20    /// Element index into the segment array (NOT byte offset).
21    start_index: u32,
22    /// Number of elements. 65k elements per slice is sufficient.
23    len: u16,
24    _pad: u16,
25    _phantom: PhantomData<fn() -> T>,
26}
27
28// Compile-time size/alignment verification
29const _: () = assert!(size_of::<Slice<u8>>() == 8);
30const _: () = assert!(align_of::<Slice<u8>>() == 4);
31
32impl<T> Slice<T> {
33    /// Creates a new slice.
34    #[inline]
35    pub const fn new(start_index: u32, len: u16) -> Self {
36        Self {
37            start_index,
38            len,
39            _pad: 0,
40            _phantom: PhantomData,
41        }
42    }
43
44    /// Creates an empty slice.
45    #[inline]
46    pub const fn empty() -> Self {
47        Self::new(0, 0)
48    }
49
50    /// Returns the start index (element index, not byte offset).
51    #[inline]
52    pub fn start_index(&self) -> u32 {
53        self.start_index
54    }
55
56    /// Returns the number of elements.
57    #[inline]
58    pub fn len(&self) -> u16 {
59        self.len
60    }
61
62    /// Returns true if the slice is empty.
63    #[inline]
64    pub fn is_empty(&self) -> bool {
65        self.len == 0
66    }
67
68    /// Creates a slice encoding an inner type ID (for wrapper TypeDef).
69    /// The `start_index` stores the TypeId as u32, `len` is 0.
70    #[inline]
71    pub const fn from_inner_type(type_id: u16) -> Self {
72        Self::new(type_id as u32, 0)
73    }
74}
75
76impl<T> Default for Slice<T> {
77    fn default() -> Self {
78        Self::empty()
79    }
80}
81
82impl<T> PartialEq for Slice<T> {
83    fn eq(&self, other: &Self) -> bool {
84        self.start_index == other.start_index && self.len == other.len
85    }
86}
87
88impl<T> Eq for Slice<T> {}
89
90impl<T> std::fmt::Debug for Slice<T> {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        f.debug_struct("Slice")
93            .field("start_index", &self.start_index)
94            .field("len", &self.len)
95            .finish()
96    }
97}