Skip to main content

protocache_core/
access.rs

1//! Access surface matching `access.h`.
2
3use core::marker::PhantomData;
4
5use crate::perfect_hash::PerfectHashView;
6use crate::utils::{Scalar, word_size};
7
8/// A scalar key that can be converted to the bytes used by a map index.
9pub trait MapKey {
10    /// Returns the key's canonical little-endian representation.
11    fn as_key_bytes(&self) -> Vec<u8>;
12}
13
14/// Decodes a typed value from an encoded message, array, or map field.
15pub trait FieldDecode<'a>: Sized {
16    /// Returns `None` when the field does not have the expected shape.
17    fn decode(field: FieldView<'a>) -> Option<Self>;
18}
19
20impl<'a, T: Scalar> FieldDecode<'a> for T {
21    fn decode(field: FieldView<'a>) -> Option<Self> {
22        field.scalar::<T>()
23    }
24}
25
26macro_rules! impl_map_key {
27    ($($ty:ty),* $(,)?) => {
28        $(
29            impl MapKey for $ty {
30                fn as_key_bytes(&self) -> Vec<u8> {
31                    self.to_le_bytes().to_vec()
32                }
33            }
34        )*
35    };
36}
37
38impl_map_key!(i32, u32, i64, u64);
39
40#[derive(Clone, Copy, Debug)]
41/// A borrowed ProtoCache byte string.
42///
43/// ProtoCache does not require string payloads to be UTF-8; use [`Self::as_str`]
44/// when text validation is required.
45pub struct StringView<'a> {
46    bytes: &'a [u8],
47}
48
49impl<'a> StringView<'a> {
50    /// Parses a string/bytes object from the beginning of `words`.
51    #[inline(always)]
52    pub fn new(words: &'a [u32]) -> Option<Self> {
53        let raw = bytes_of_words(words);
54        let first = *raw.first()?;
55        if (first & 3) != 0 {
56            return None;
57        }
58
59        let mut mark = 0usize;
60        let mut shift = 0usize;
61        let mut used = 0usize;
62        while shift < 32 {
63            let byte = *raw.get(used)?;
64            used += 1;
65            if (byte & 0x80) != 0 {
66                mark |= ((byte & 0x7f) as usize) << shift;
67            } else {
68                mark |= (byte as usize) << shift;
69                let byte_len = mark >> 2;
70                let end = used.checked_add(byte_len)?;
71                return Some(Self {
72                    bytes: raw.get(used..end)?,
73                });
74            }
75            shift += 7;
76        }
77        None
78    }
79
80    /// Returns the encoded object length in words without constructing a view.
81    #[inline(always)]
82    pub fn detect_len(words: &'a [u32]) -> Option<usize> {
83        let raw = bytes_of_words(words);
84        let first = *raw.first()?;
85        if (first & 3) != 0 {
86            return None;
87        }
88
89        let mut mark = 0usize;
90        let mut shift = 0usize;
91        let mut used = 0usize;
92        while shift < 32 {
93            let byte = *raw.get(used)?;
94            used += 1;
95            if (byte & 0x80) != 0 {
96                mark |= ((byte & 0x7f) as usize) << shift;
97            } else {
98                mark |= (byte as usize) << shift;
99                let total = used.checked_add(mark >> 2)?;
100                return Some(word_size(total));
101            }
102            shift += 7;
103        }
104        None
105    }
106
107    /// Returns the exact encoded subslice occupied by the string/bytes object.
108    #[inline(always)]
109    pub fn detect(words: &'a [u32]) -> Option<&'a [u32]> {
110        words.get(..Self::detect_len(words)?)
111    }
112
113    /// Returns the payload without UTF-8 validation.
114    #[inline(always)]
115    pub fn as_bytes(self) -> &'a [u8] {
116        self.bytes
117    }
118
119    /// Returns the payload as text, or `None` if it is not valid UTF-8.
120    #[inline(always)]
121    pub fn as_str(self) -> Option<&'a str> {
122        core::str::from_utf8(self.bytes).ok()
123    }
124
125    /// Interprets every payload byte as one boolean value.
126    #[inline(always)]
127    pub fn as_bool_array(self) -> BoolArray<'a> {
128        BoolArray { bytes: self.bytes }
129    }
130}
131
132impl AsRef<[u8]> for StringView<'_> {
133    fn as_ref(&self) -> &[u8] {
134        self.bytes
135    }
136}
137
138impl<'a> core::fmt::Display for StringView<'a> {
139    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
140        match self.as_str() {
141            Some(value) => f.write_str(value),
142            None => write!(f, "{:?}", self.bytes),
143        }
144    }
145}
146
147#[derive(Clone, Copy, Debug)]
148/// A borrowed sequence of booleans stored as ProtoCache bytes.
149pub struct BoolArray<'a> {
150    bytes: &'a [u8],
151}
152
153impl<'a> BoolArray<'a> {
154    #[inline(always)]
155    pub fn len(&self) -> usize {
156        self.bytes.len()
157    }
158
159    #[inline(always)]
160    pub fn is_empty(&self) -> bool {
161        self.bytes.is_empty()
162    }
163
164    #[inline(always)]
165    pub fn get(&self, index: usize) -> Option<bool> {
166        Some(*self.bytes.get(index)? != 0)
167    }
168
169    #[inline(always)]
170    pub fn iter(&self) -> impl Iterator<Item = bool> + 'a {
171        self.bytes.iter().copied().map(|v| v != 0)
172    }
173}
174
175#[derive(Clone, Copy, Debug)]
176/// The encoded words and width metadata for one field.
177///
178/// Prefer the typed conversion methods (`scalar`, `string`, `message`,
179/// `array`, and `map`) unless implementing a generated accessor.
180pub struct FieldView<'a> {
181    tail: &'a [u32],
182    width: usize,
183}
184
185impl<'a> FieldView<'a> {
186    #[inline(always)]
187    pub fn raw_words(self) -> Option<&'a [u32]> {
188        self.tail.get(..self.width)
189    }
190
191    #[inline(always)]
192    pub fn expect_raw_words(self) -> &'a [u32] {
193        &self.tail[..self.width]
194    }
195
196    #[inline(always)]
197    pub fn object_words(self) -> Option<&'a [u32]> {
198        let first = *self.tail.first()?;
199        if (first & 3) == 3 {
200            self.tail.get((first >> 2) as usize..)
201        } else {
202            Some(self.tail)
203        }
204    }
205
206    #[inline(always)]
207    pub fn expect_object_words(self) -> &'a [u32] {
208        let first = self.tail[0];
209        if (first & 3) == 3 {
210            &self.tail[(first >> 2) as usize..]
211        } else {
212            self.tail
213        }
214    }
215
216    #[inline(always)]
217    pub fn scalar<T: Scalar>(self) -> Option<T> {
218        T::from_words(self.raw_words()?)
219    }
220
221    #[inline(always)]
222    pub fn expect_scalar<T: Scalar>(self) -> T {
223        T::from_words(self.expect_raw_words()).expect("invalid scalar field")
224    }
225
226    #[inline(always)]
227    pub fn detect_scalar(self) -> Option<&'a [u32]> {
228        self.raw_words()
229    }
230
231    #[inline(always)]
232    pub fn string(self) -> Option<StringView<'a>> {
233        StringView::new(self.object_words()?)
234    }
235
236    #[inline(always)]
237    pub fn expect_string(self) -> StringView<'a> {
238        StringView::new(self.expect_object_words()).expect("invalid string field")
239    }
240
241    #[inline(always)]
242    pub fn detect_string(self) -> Option<&'a [u32]> {
243        StringView::detect(self.object_words()?)
244    }
245
246    #[inline(always)]
247    pub fn message(self) -> Option<MessageView<'a>> {
248        MessageView::new(self.object_words()?)
249    }
250
251    #[inline(always)]
252    pub fn expect_message(self) -> MessageView<'a> {
253        MessageView::new(self.expect_object_words()).expect("invalid message field")
254    }
255
256    #[inline(always)]
257    pub fn detect_message(self) -> Option<&'a [u32]> {
258        MessageView::detect(self.object_words()?)
259    }
260
261    #[inline(always)]
262    pub fn array(self) -> Option<ArrayView<'a>> {
263        ArrayView::new(self.object_words()?)
264    }
265
266    #[inline(always)]
267    pub fn expect_array(self) -> ArrayView<'a> {
268        ArrayView::new(self.expect_object_words()).expect("invalid array field")
269    }
270
271    #[inline(always)]
272    pub fn detect_array(self) -> Option<&'a [u32]> {
273        ArrayView::detect(self.object_words()?)
274    }
275
276    #[inline(always)]
277    pub fn map(self) -> Option<MapView<'a>> {
278        MapView::new(self.object_words()?)
279    }
280
281    #[inline(always)]
282    pub fn expect_map(self) -> MapView<'a> {
283        MapView::new(self.expect_object_words()).expect("invalid map field")
284    }
285
286    #[inline(always)]
287    pub fn detect_map(self) -> Option<&'a [u32]> {
288        MapView::detect(self.object_words()?)
289    }
290}
291
292#[derive(Clone, Copy, Debug)]
293/// A zero-copy view over an encoded ProtoCache message.
294pub struct MessageView<'a> {
295    head: u32,
296    words: &'a [u32],
297    body: &'a [u32],
298    section: usize,
299}
300
301#[derive(Clone, Copy, Debug)]
302pub(crate) struct MessageLayout {
303    head: u32,
304    body_offset: usize,
305    section: usize,
306}
307
308impl<'a> MessageView<'a> {
309    /// Parses a message header from `words`.
310    ///
311    /// The view may borrow a larger enclosing slice; call [`Self::detect`] when
312    /// the exact encoded extent is needed.
313    #[inline(always)]
314    pub fn new(words: &'a [u32]) -> Option<Self> {
315        let layout = Self::layout(words)?;
316        let body = words.get(layout.body_offset..)?;
317        Some(Self {
318            head: layout.head,
319            words,
320            body,
321            section: layout.section,
322        })
323    }
324
325    /// Alias for [`Self::new`] used by generated bindings.
326    #[inline(always)]
327    pub fn from_words(words: &'a [u32]) -> Option<Self> {
328        Self::new(words)
329    }
330
331    /// Returns the minimum message header/body slice retained by this view.
332    #[inline(always)]
333    pub fn raw_words(self) -> &'a [u32] {
334        self.words
335    }
336
337    /// Detects the complete encoded message length, including referenced data.
338    #[inline(always)]
339    pub fn detect_len(words: &'a [u32]) -> Option<usize> {
340        let head = *words.first()?;
341        let section = (head & 0xff) as usize;
342        let mut tail = 1usize.checked_add(section.checked_mul(2)?)?;
343        if section == 0 {
344            tail = tail.checked_add(count32(head))?;
345        } else {
346            let sec_words = words.get(tail - 2..tail)?;
347            let raw = bytes_of_words(sec_words);
348            let sec = u64::from_le_bytes(raw.try_into().ok()?);
349            tail = tail.checked_add(count64(sec << 14))?;
350            tail = tail.checked_add((sec >> 50) as usize)?;
351        }
352        words.get(..tail)?;
353        Some(tail)
354    }
355
356    /// Returns the exact encoded slice occupied by a valid message.
357    #[inline(always)]
358    pub fn detect(words: &'a [u32]) -> Option<&'a [u32]> {
359        words.get(..Self::detect_len(words)?)
360    }
361
362    /// Returns whether the message contains the field with zero-based `id`.
363    #[inline(always)]
364    pub fn has_field(self, id: usize) -> bool {
365        self.field(id).is_some()
366    }
367
368    /// Returns a raw field view for zero-based `id`.
369    #[inline(always)]
370    pub fn field(self, id: usize) -> Option<FieldView<'a>> {
371        Self::field_in(
372            self.words,
373            &MessageLayout {
374                head: self.head,
375                body_offset: self.words.len() - self.body.len(),
376                section: self.section,
377            },
378            id,
379        )
380    }
381
382    #[inline(always)]
383    pub fn expect_field(self, id: usize) -> FieldView<'a> {
384        self.field(id).expect("missing message field")
385    }
386
387    #[inline(always)]
388    pub fn scalar<T: Scalar>(self, id: usize) -> Option<T> {
389        self.field(id)?.scalar::<T>()
390    }
391
392    #[inline(always)]
393    pub fn string(self, id: usize) -> Option<StringView<'a>> {
394        self.field(id)?.string()
395    }
396
397    #[inline(always)]
398    pub fn bytes(self, id: usize) -> Option<&'a [u8]> {
399        Some(self.string(id)?.as_bytes())
400    }
401
402    #[inline(always)]
403    pub fn bools(self, id: usize) -> Option<BoolArray<'a>> {
404        Some(self.string(id)?.as_bool_array())
405    }
406
407    #[inline(always)]
408    pub fn message(self, id: usize) -> Option<MessageView<'a>> {
409        self.field(id)?.message()
410    }
411
412    #[inline(always)]
413    pub fn array(self, id: usize) -> Option<ArrayView<'a>> {
414        self.field(id)?.array()
415    }
416
417    #[inline(always)]
418    pub fn map(self, id: usize) -> Option<MapView<'a>> {
419        self.field(id)?.map()
420    }
421
422    #[inline(always)]
423    pub(crate) fn layout(words: &[u32]) -> Option<MessageLayout> {
424        let head = *words.first()?;
425        let section = (head & 0xff) as usize;
426        let body_offset = 1usize.checked_add(section.checked_mul(2)?)?;
427        words.get(body_offset..)?;
428        Some(MessageLayout {
429            head,
430            body_offset,
431            section,
432        })
433    }
434
435    #[inline(always)]
436    pub(crate) fn field_in<'b>(
437        words: &'b [u32],
438        layout: &MessageLayout,
439        id: usize,
440    ) -> Option<FieldView<'b>> {
441        let (width, off) = if id < 12 {
442            let mut v = layout.head >> 8;
443            let width = ((v >> (id * 2)) & 3) as usize;
444            if width == 0 {
445                return None;
446            }
447            v &= !(u32::MAX << (id * 2));
448            (width, count32(v))
449        } else {
450            let section_index = (id - 12) / 25;
451            let bit_index = (id - 12) % 25;
452            if section_index >= layout.section {
453                return None;
454            }
455            let sec_words = words.get(1 + section_index * 2..1 + section_index * 2 + 2)?;
456            let raw = bytes_of_words(sec_words);
457            let vec = u64::from_le_bytes(raw.try_into().ok()?);
458            let width = ((vec >> (bit_index * 2)) & 3) as usize;
459            if width == 0 {
460                return None;
461            }
462            let mask = if bit_index == 0 {
463                0
464            } else {
465                (1u64 << (bit_index * 2)) - 1
466            };
467            (width, count64(vec & mask) + (vec >> 50) as usize)
468        };
469
470        let body = words.get(layout.body_offset..)?;
471        Some(FieldView {
472            tail: body.get(off..)?,
473            width,
474        })
475    }
476}
477
478#[derive(Clone, Copy, Debug)]
479/// A zero-copy view over an encoded ProtoCache array.
480pub struct ArrayView<'a> {
481    body: &'a [u32],
482    len: usize,
483    width: usize,
484}
485
486impl<'a> ArrayView<'a> {
487    /// Parses an encoded array from `words`.
488    #[inline(always)]
489    pub fn new(words: &'a [u32]) -> Option<Self> {
490        let head = *words.first()?;
491        let len = (head >> 2) as usize;
492        let width = (head & 3) as usize;
493        if width == 0 {
494            return None;
495        }
496        let body = words.get(1..)?;
497        body.get(..len.checked_mul(width)?)?;
498        Some(Self { body, len, width })
499    }
500
501    /// Detects the complete encoded array length, including referenced items.
502    #[inline(always)]
503    pub fn detect_len(words: &'a [u32]) -> Option<usize> {
504        let head = *words.first()?;
505        let len = (head >> 2) as usize;
506        let width = (head & 3) as usize;
507        if width == 0 {
508            return None;
509        }
510        1usize.checked_add(len.checked_mul(width)?)
511    }
512
513    /// Returns the exact encoded slice occupied by a valid array.
514    #[inline(always)]
515    pub fn detect(words: &'a [u32]) -> Option<&'a [u32]> {
516        words.get(..Self::detect_len(words)?)
517    }
518
519    /// Returns the number of array elements.
520    #[inline(always)]
521    pub fn len(self) -> usize {
522        self.len
523    }
524
525    #[inline(always)]
526    pub fn is_empty(self) -> bool {
527        self.len == 0
528    }
529
530    #[inline(always)]
531    pub fn width(self) -> usize {
532        self.width
533    }
534
535    #[inline(always)]
536    pub(crate) fn total_words(self) -> usize {
537        1 + self.len * self.width
538    }
539
540    /// Returns a raw field view for the element at `index`.
541    #[inline(always)]
542    pub fn field(self, index: usize) -> Option<FieldView<'a>> {
543        if index >= self.len {
544            return None;
545        }
546        let start = index.checked_mul(self.width)?;
547        Some(FieldView {
548            tail: self.body.get(start..)?,
549            width: self.width,
550        })
551    }
552
553    #[inline(always)]
554    pub fn expect_field(self, index: usize) -> FieldView<'a> {
555        let start = index * self.width;
556        FieldView {
557            tail: &self.body[start..],
558            width: self.width,
559        }
560    }
561
562    #[inline(always)]
563    pub fn scalars<T: Scalar>(self) -> Option<ScalarArray<'a, T>> {
564        if self.width != T::WIDTH {
565            return None;
566        }
567        Some(ScalarArray {
568            words: self.body.get(..self.len * self.width)?,
569            len: self.len,
570            _marker: PhantomData,
571        })
572    }
573
574    #[inline(always)]
575    pub fn expect_scalars<T: Scalar>(self) -> ScalarArray<'a, T> {
576        assert_eq!(self.width, T::WIDTH);
577        ScalarArray {
578            words: &self.body[..self.len * self.width],
579            len: self.len,
580            _marker: PhantomData,
581        }
582    }
583
584    #[inline(always)]
585    pub fn iter(self) -> ArrayIter<'a> {
586        ArrayIter {
587            array: self,
588            index: 0,
589        }
590    }
591}
592
593/// Iterator over the raw fields of an [`ArrayView`].
594pub struct ArrayIter<'a> {
595    array: ArrayView<'a>,
596    index: usize,
597}
598
599impl<'a> Iterator for ArrayIter<'a> {
600    type Item = FieldView<'a>;
601
602    #[inline(always)]
603    fn next(&mut self) -> Option<Self::Item> {
604        let item = self.array.field(self.index)?;
605        self.index += 1;
606        Some(item)
607    }
608
609    #[inline(always)]
610    fn size_hint(&self) -> (usize, Option<usize>) {
611        let remaining = self.array.len.saturating_sub(self.index);
612        (remaining, Some(remaining))
613    }
614}
615
616impl ExactSizeIterator for ArrayIter<'_> {}
617impl core::iter::FusedIterator for ArrayIter<'_> {}
618
619/// A typed, zero-copy array facade built on [`ArrayView`].
620pub struct ViewArray<'a, T> {
621    array: ArrayView<'a>,
622    _marker: PhantomData<T>,
623}
624
625impl<'a, T> Copy for ViewArray<'a, T> {}
626
627impl<'a, T> Clone for ViewArray<'a, T> {
628    fn clone(&self) -> Self {
629        *self
630    }
631}
632
633impl<'a, T: FieldDecode<'a>> ViewArray<'a, T> {
634    #[inline(always)]
635    pub fn new(array: ArrayView<'a>) -> Self {
636        Self {
637            array,
638            _marker: PhantomData,
639        }
640    }
641
642    #[inline(always)]
643    pub fn len(&self) -> usize {
644        self.array.len()
645    }
646
647    #[inline(always)]
648    pub fn is_empty(&self) -> bool {
649        self.array.is_empty()
650    }
651
652    #[inline(always)]
653    pub fn get(&self, index: usize) -> Option<T> {
654        T::decode(self.array.field(index)?)
655    }
656
657    #[inline(always)]
658    pub fn iter(&self) -> ViewArrayIter<'a, T> {
659        ViewArrayIter {
660            array: *self,
661            index: 0,
662        }
663    }
664
665    #[inline(always)]
666    pub fn raw(&self) -> ArrayView<'a> {
667        self.array
668    }
669}
670
671/// Iterator over decoded values in a [`ViewArray`].
672pub struct ViewArrayIter<'a, T> {
673    array: ViewArray<'a, T>,
674    index: usize,
675}
676
677impl<'a, T: FieldDecode<'a>> Iterator for ViewArrayIter<'a, T> {
678    type Item = T;
679
680    #[inline(always)]
681    fn next(&mut self) -> Option<Self::Item> {
682        let value = self.array.get(self.index)?;
683        self.index += 1;
684        Some(value)
685    }
686
687    #[inline(always)]
688    fn size_hint(&self) -> (usize, Option<usize>) {
689        let remaining = self.array.len().saturating_sub(self.index);
690        (remaining, Some(remaining))
691    }
692}
693
694impl<'a, T: FieldDecode<'a>> ExactSizeIterator for ViewArrayIter<'a, T> {}
695impl<'a, T: FieldDecode<'a>> core::iter::FusedIterator for ViewArrayIter<'a, T> {}
696
697/// A zero-copy view over a densely encoded array of scalar values.
698pub struct ScalarArray<'a, T> {
699    words: &'a [u32],
700    len: usize,
701    _marker: PhantomData<T>,
702}
703
704impl<'a, T> Copy for ScalarArray<'a, T> {}
705
706impl<'a, T> Clone for ScalarArray<'a, T> {
707    fn clone(&self) -> Self {
708        *self
709    }
710}
711
712impl<'a, T: Scalar> ScalarArray<'a, T> {
713    #[inline(always)]
714    pub fn len(&self) -> usize {
715        self.len
716    }
717
718    #[inline(always)]
719    pub fn is_empty(&self) -> bool {
720        self.len == 0
721    }
722
723    #[inline(always)]
724    pub fn get(&self, index: usize) -> Option<T> {
725        if index >= self.len {
726            return None;
727        }
728        let start = index.checked_mul(T::WIDTH)?;
729        T::from_words(self.words.get(start..start + T::WIDTH)?)
730    }
731
732    #[inline(always)]
733    pub fn iter(&self) -> ScalarArrayIter<'a, T> {
734        ScalarArrayIter {
735            array: *self,
736            index: 0,
737        }
738    }
739}
740
741/// Iterator over scalar values in a [`ScalarArray`].
742pub struct ScalarArrayIter<'a, T> {
743    array: ScalarArray<'a, T>,
744    index: usize,
745}
746
747impl<'a, T: Scalar> Iterator for ScalarArrayIter<'a, T> {
748    type Item = T;
749
750    #[inline(always)]
751    fn next(&mut self) -> Option<Self::Item> {
752        let value = self.array.get(self.index)?;
753        self.index += 1;
754        Some(value)
755    }
756
757    #[inline(always)]
758    fn size_hint(&self) -> (usize, Option<usize>) {
759        let remaining = self.array.len().saturating_sub(self.index);
760        (remaining, Some(remaining))
761    }
762}
763
764impl<T: Scalar> ExactSizeIterator for ScalarArrayIter<'_, T> {}
765impl<T: Scalar> core::iter::FusedIterator for ScalarArrayIter<'_, T> {}
766
767#[derive(Clone, Copy, Debug)]
768/// A borrowed key/value pair from a [`MapView`].
769pub struct PairView<'a> {
770    tail: &'a [u32],
771    key_width: usize,
772    value_width: usize,
773}
774
775impl<'a> PairView<'a> {
776    #[inline(always)]
777    pub fn key(self) -> FieldView<'a> {
778        FieldView {
779            tail: self.tail,
780            width: self.key_width,
781        }
782    }
783
784    #[inline(always)]
785    pub fn value(self) -> FieldView<'a> {
786        FieldView {
787            tail: &self.tail[self.key_width..],
788            width: self.value_width,
789        }
790    }
791}
792
793#[derive(Clone, Copy, Debug)]
794/// A zero-copy view over an encoded ProtoCache map and its perfect-hash index.
795pub struct MapView<'a> {
796    index: PerfectHashView<'a>,
797    body: &'a [u32],
798    len: usize,
799    key_width: usize,
800    value_width: usize,
801    total_words: usize,
802}
803
804impl<'a> MapView<'a> {
805    /// Parses an encoded map and validates its structural header.
806    #[inline(always)]
807    pub fn new(words: &'a [u32]) -> Option<Self> {
808        let head = *words.first()?;
809        let key_width = ((head >> 30) & 3) as usize;
810        let value_width = ((head >> 28) & 3) as usize;
811        if key_width == 0 || value_width == 0 {
812            return None;
813        }
814
815        let index = PerfectHashView::new(bytes_of_words(words)).ok()?;
816        let body_offset = word_size(index.data_size());
817        let body = words.get(body_offset..)?;
818        let pair_words = index.len().checked_mul(key_width + value_width)?;
819        body.get(..pair_words)?;
820        Some(Self {
821            index,
822            body,
823            len: index.len(),
824            key_width,
825            value_width,
826            total_words: body_offset.checked_add(pair_words)?,
827        })
828    }
829
830    /// Detects the complete encoded map length, including keys and values.
831    #[inline(always)]
832    pub fn detect_len(words: &'a [u32]) -> Option<usize> {
833        let head = *words.first()?;
834        let key_width = ((head >> 30) & 3) as usize;
835        let value_width = ((head >> 28) & 3) as usize;
836        if key_width == 0 || value_width == 0 {
837            return None;
838        }
839        let index = PerfectHashView::new(bytes_of_words(words)).ok()?;
840        word_size(index.data_size()).checked_add(index.len().checked_mul(key_width + value_width)?)
841    }
842
843    /// Returns the exact encoded slice occupied by a valid map.
844    #[inline(always)]
845    pub fn detect(words: &'a [u32]) -> Option<&'a [u32]> {
846        words.get(..Self::detect_len(words)?)
847    }
848
849    /// Returns the number of key/value pairs.
850    #[inline(always)]
851    pub fn len(self) -> usize {
852        self.len
853    }
854
855    #[inline(always)]
856    pub fn is_empty(self) -> bool {
857        self.len == 0
858    }
859
860    #[inline(always)]
861    pub(crate) fn total_words(self) -> usize {
862        self.total_words
863    }
864
865    /// Returns the raw pair stored at perfect-hash position `index`.
866    #[inline(always)]
867    pub fn pair(self, index: usize) -> Option<PairView<'a>> {
868        if index >= self.len {
869            return None;
870        }
871        let width = self.key_width + self.value_width;
872        let start = index.checked_mul(width)?;
873        Some(PairView {
874            tail: self.body.get(start..)?,
875            key_width: self.key_width,
876            value_width: self.value_width,
877        })
878    }
879
880    #[inline(always)]
881    pub fn expect_pair(self, index: usize) -> PairView<'a> {
882        let width = self.key_width + self.value_width;
883        let start = index * width;
884        PairView {
885            tail: &self.body[start..],
886            key_width: self.key_width,
887            value_width: self.value_width,
888        }
889    }
890
891    #[inline(always)]
892    pub fn iter(self) -> MapIter<'a> {
893        MapIter {
894            map: self,
895            index: 0,
896        }
897    }
898
899    /// Looks up an arbitrary byte-string key.
900    #[inline(always)]
901    pub fn find_bytes(self, key: &[u8]) -> Option<PairView<'a>> {
902        let pos = self.index.locate(key)?;
903        let pair = self.pair(pos)?;
904        if pair.key().string()?.as_bytes() == key {
905            Some(pair)
906        } else {
907            None
908        }
909    }
910
911    /// Looks up a UTF-8 key by its encoded bytes.
912    #[inline(always)]
913    pub fn find_str(self, key: &str) -> Option<PairView<'a>> {
914        self.find_bytes(key.as_bytes())
915    }
916
917    /// Looks up a scalar key using its canonical little-endian bytes.
918    #[inline(always)]
919    pub fn find_scalar<K: MapKey + Scalar + PartialEq>(self, key: K) -> Option<PairView<'a>> {
920        let key_bytes = key.as_key_bytes();
921        let pos = self.index.locate(&key_bytes)?;
922        let pair = self.pair(pos)?;
923        if pair.key().scalar::<K>()? == key {
924            Some(pair)
925        } else {
926            None
927        }
928    }
929}
930
931/// Iterator over raw key/value pairs in a [`MapView`].
932pub struct MapIter<'a> {
933    map: MapView<'a>,
934    index: usize,
935}
936
937impl<'a> Iterator for MapIter<'a> {
938    type Item = PairView<'a>;
939
940    #[inline(always)]
941    fn next(&mut self) -> Option<Self::Item> {
942        let item = self.map.pair(self.index)?;
943        self.index += 1;
944        Some(item)
945    }
946
947    #[inline(always)]
948    fn size_hint(&self) -> (usize, Option<usize>) {
949        let remaining = self.map.len.saturating_sub(self.index);
950        (remaining, Some(remaining))
951    }
952}
953
954impl ExactSizeIterator for MapIter<'_> {}
955impl core::iter::FusedIterator for MapIter<'_> {}
956
957/// A typed, zero-copy map facade built on [`MapView`].
958pub struct ViewMap<'a, K, V> {
959    map: MapView<'a>,
960    _key: PhantomData<K>,
961    _value: PhantomData<V>,
962}
963
964impl<'a, K, V> Copy for ViewMap<'a, K, V> {}
965
966impl<'a, K, V> Clone for ViewMap<'a, K, V> {
967    fn clone(&self) -> Self {
968        *self
969    }
970}
971
972impl<'a, K: FieldDecode<'a>, V: FieldDecode<'a>> ViewMap<'a, K, V> {
973    #[inline(always)]
974    pub fn new(map: MapView<'a>) -> Self {
975        Self {
976            map,
977            _key: PhantomData,
978            _value: PhantomData,
979        }
980    }
981
982    #[inline(always)]
983    pub fn len(&self) -> usize {
984        self.map.len()
985    }
986
987    #[inline(always)]
988    pub fn is_empty(&self) -> bool {
989        self.map.is_empty()
990    }
991
992    #[inline(always)]
993    pub fn get(&self, index: usize) -> Option<(K, V)> {
994        let pair = self.map.pair(index)?;
995        Some((K::decode(pair.key())?, V::decode(pair.value())?))
996    }
997
998    #[inline(always)]
999    pub fn iter(&self) -> ViewMapIter<'a, K, V> {
1000        ViewMapIter {
1001            map: *self,
1002            index: 0,
1003        }
1004    }
1005
1006    #[inline(always)]
1007    pub fn raw(&self) -> MapView<'a> {
1008        self.map
1009    }
1010}
1011
1012impl<'a, V: FieldDecode<'a>> ViewMap<'a, StringView<'a>, V> {
1013    #[inline(always)]
1014    pub fn find_str(&self, key: &str) -> Option<(StringView<'a>, V)> {
1015        let pair = self.map.find_str(key)?;
1016        Some((StringView::decode(pair.key())?, V::decode(pair.value())?))
1017    }
1018}
1019
1020impl<'a, K: FieldDecode<'a> + MapKey + Scalar + PartialEq, V: FieldDecode<'a>> ViewMap<'a, K, V> {
1021    #[inline(always)]
1022    pub fn find_scalar(&self, key: K) -> Option<(K, V)> {
1023        let pair = self.map.find_scalar(key)?;
1024        Some((K::decode(pair.key())?, V::decode(pair.value())?))
1025    }
1026}
1027
1028/// Iterator over decoded entries in a [`ViewMap`].
1029pub struct ViewMapIter<'a, K, V> {
1030    map: ViewMap<'a, K, V>,
1031    index: usize,
1032}
1033
1034impl<'a, K: FieldDecode<'a>, V: FieldDecode<'a>> Iterator for ViewMapIter<'a, K, V> {
1035    type Item = (K, V);
1036
1037    #[inline(always)]
1038    fn next(&mut self) -> Option<Self::Item> {
1039        let value = self.map.get(self.index)?;
1040        self.index += 1;
1041        Some(value)
1042    }
1043
1044    #[inline(always)]
1045    fn size_hint(&self) -> (usize, Option<usize>) {
1046        let remaining = self.map.len().saturating_sub(self.index);
1047        (remaining, Some(remaining))
1048    }
1049}
1050
1051impl<'a, K: FieldDecode<'a>, V: FieldDecode<'a>> ExactSizeIterator for ViewMapIter<'a, K, V> {}
1052impl<'a, K: FieldDecode<'a>, V: FieldDecode<'a>> core::iter::FusedIterator
1053    for ViewMapIter<'a, K, V>
1054{
1055}
1056
1057impl<'a> IntoIterator for BoolArray<'a> {
1058    type Item = bool;
1059    type IntoIter = core::iter::Map<core::iter::Copied<core::slice::Iter<'a, u8>>, fn(u8) -> bool>;
1060
1061    #[inline(always)]
1062    fn into_iter(self) -> Self::IntoIter {
1063        fn as_bool(value: u8) -> bool {
1064            value != 0
1065        }
1066
1067        self.bytes.iter().copied().map(as_bool)
1068    }
1069}
1070
1071impl<'a, T: Scalar> IntoIterator for ScalarArray<'a, T> {
1072    type Item = T;
1073    type IntoIter = ScalarArrayIter<'a, T>;
1074
1075    #[inline(always)]
1076    fn into_iter(self) -> Self::IntoIter {
1077        self.iter()
1078    }
1079}
1080
1081impl<'a, T: FieldDecode<'a>> IntoIterator for ViewArray<'a, T> {
1082    type Item = T;
1083    type IntoIter = ViewArrayIter<'a, T>;
1084
1085    #[inline(always)]
1086    fn into_iter(self) -> Self::IntoIter {
1087        self.iter()
1088    }
1089}
1090
1091impl<'a, K: FieldDecode<'a>, V: FieldDecode<'a>> IntoIterator for ViewMap<'a, K, V> {
1092    type Item = (K, V);
1093    type IntoIter = ViewMapIter<'a, K, V>;
1094
1095    #[inline(always)]
1096    fn into_iter(self) -> Self::IntoIter {
1097        self.iter()
1098    }
1099}
1100
1101impl<'a> FieldDecode<'a> for StringView<'a> {
1102    fn decode(field: FieldView<'a>) -> Option<Self> {
1103        field.string()
1104    }
1105}
1106
1107impl<'a> FieldDecode<'a> for MessageView<'a> {
1108    fn decode(field: FieldView<'a>) -> Option<Self> {
1109        field.message()
1110    }
1111}
1112
1113impl<'a> FieldDecode<'a> for ArrayView<'a> {
1114    fn decode(field: FieldView<'a>) -> Option<Self> {
1115        field.array()
1116    }
1117}
1118
1119impl<'a> FieldDecode<'a> for MapView<'a> {
1120    fn decode(field: FieldView<'a>) -> Option<Self> {
1121        field.map()
1122    }
1123}
1124
1125#[inline(always)]
1126/// Extends `end` to include a detected subslice after validating its provenance.
1127///
1128/// Returns `None` if `detected` is not word-aligned or not fully contained in
1129/// `words`. This validation is required before composing safe detection APIs.
1130pub fn detect_slice_end(words: &[u32], detected: &[u32], end: &mut usize) -> Option<()> {
1131    *end = (*end).max(checked_slice_end(words, detected)?);
1132    Some(())
1133}
1134
1135#[inline(always)]
1136pub(crate) fn checked_slice_end(words: &[u32], detected: &[u32]) -> Option<usize> {
1137    let word_size = core::mem::size_of::<u32>();
1138    let words_start = words.as_ptr().addr();
1139    let words_end = words_start.checked_add(words.len().checked_mul(word_size)?)?;
1140    let detected_start = detected.as_ptr().addr();
1141    let detected_end = detected_start.checked_add(detected.len().checked_mul(word_size)?)?;
1142
1143    if detected_start < words_start || detected_end > words_end {
1144        return None;
1145    }
1146
1147    let byte_offset = detected_start.checked_sub(words_start)?;
1148    if !byte_offset.is_multiple_of(word_size) {
1149        return None;
1150    }
1151    byte_offset
1152        .checked_div(word_size)?
1153        .checked_add(detected.len())
1154}
1155
1156#[inline(always)]
1157/// Detects the complete encoded extent of an array using an element detector.
1158pub fn detect_array_with<'a>(
1159    words: &'a [u32],
1160    mut detect: impl FnMut(FieldView<'a>) -> Option<&'a [u32]>,
1161) -> Option<&'a [u32]> {
1162    let array = ArrayView::new(words)?;
1163    let end = array.total_words();
1164    for index in (0..array.len()).rev() {
1165        let detected = detect(array.expect_field(index))?;
1166        let detected_end = checked_slice_end(words, detected)?;
1167        if detected_end > end {
1168            return words.get(..detected_end);
1169        }
1170    }
1171    words.get(..end)
1172}
1173
1174#[inline(always)]
1175/// Detects the complete encoded extent of a map using key and value detectors.
1176pub fn detect_map_with<'a>(
1177    words: &'a [u32],
1178    mut detect_key: impl FnMut(FieldView<'a>) -> Option<&'a [u32]>,
1179    mut detect_value: impl FnMut(FieldView<'a>) -> Option<&'a [u32]>,
1180) -> Option<&'a [u32]> {
1181    let map = MapView::new(words)?;
1182    let end = map.total_words();
1183    for index in (0..map.len()).rev() {
1184        let pair = map.expect_pair(index);
1185        let detected = detect_value(pair.value())?;
1186        let detected_end = checked_slice_end(words, detected)?;
1187        if detected_end > end {
1188            return words.get(..detected_end);
1189        }
1190
1191        let detected = detect_key(pair.key())?;
1192        let detected_end = checked_slice_end(words, detected)?;
1193        if detected_end > end {
1194            return words.get(..detected_end);
1195        }
1196    }
1197    words.get(..end)
1198}
1199
1200#[inline(always)]
1201fn bytes_of_words(words: &[u32]) -> &[u8] {
1202    // u8 alignment is 1, so viewing the word buffer as bytes is safe.
1203    unsafe { core::slice::from_raw_parts(words.as_ptr().cast::<u8>(), words.len() * 4) }
1204}
1205
1206#[inline(always)]
1207fn count32(v: u32) -> usize {
1208    ((v & 0xaaaa_aaaa).count_ones() + v.count_ones()) as usize
1209}
1210
1211#[inline(always)]
1212fn count64(v: u64) -> usize {
1213    ((v & 0xaaaa_aaaa_aaaa_aaaa).count_ones() + v.count_ones()) as usize
1214}