index_ext/
tag.rs

1//! Statically elide bounds checks with the type system.
2//!
3//! ## Rough mechanism
4//!
5//! The main idea is to use types as a compile time tag to identify a particular length of a slice
6//! without storing this bound in the instances associated with the constraint. For this, we
7//! utilize strategies such as [generativity] or concrete compile time tags.
8//!
9//! [generativity]: https://docs.rs/generativity/latest/generativity/
10//!
11//! This allows us to construct wrapper types for indices and slices that guarantees its accesses
12//! to be in-bounds when combined with any other value with the same tag. Critically, these indices
13//! and slices can be stored and acted on independent of each other and without introducing borrow
14//! coupling between them. The type system _guarantees_ a bounds-check free code path for indexing
15//! into the slices by adding an indexing operator which unconditionally performs the unsafe
16//! access.
17//!
18//! This works particularly well for programs with fixed size buffers, i.e. kernels, bootloaders,
19//! embedded, high-assurance programs. If you encapsulate the `ExactSize` instance containing the
20//! authoritative source of the associated length then you can have a very high confidence in have
21//! ran appropriate access and bounds checks before accesses.
22//!
23//! ## Built-in Tag types
24//!
25//! There are a couple of different methods for creating tag types with such associations:
26//!
27//! 1. As a compile time constant. The [`Constant`] and [`Const`] offer different ways of defining
28//!    the associated length as a fixed number. The former let's you give it a type as a name while
29//!    the latter is based on generic parameters.
30//!
31//! 2. The generative way. The [`Generative`] type is unique for every created instance, by having
32//!    a unique lifetime parameter.  That is, you can not choose its lifetime parameters freely.
33//!    Instead, to create an instance you write a function prepared to handle arbitrary lifetime
34//!    and the library hands an instance to you. This makes the exact lifetime opaque to you and
35//!    the compiler which forces all non-local code to assume that it is indeed unique and it can
36//!    not be unified with any other. We associate such a [`Generative`] instance with the length
37//!    of the one slice provided during its construction.
38//!
39//! 3. And finally one might come up with an internal naming scheme where types are used to express
40//!    unique bounds. This requires some unsafe code and the programmers guarantee of uniqueness of
41//!    values but permits the combination of runtime values with `'static` lifetime of the tag.
42//!
43//! Each tag relates to _one_ specific length of slices, without encoding that value itself into
44//! values but rather this is a 'hidden' variable. Usage of the tag guarantees a separation between
45//! slices associated with the tag and all indices. This allows transitive reasoning: All [`Slice`]
46//! with that exact same tag are at least as long as all the sizes in [`Prefix`] structs of the
47//! same lifetime and strictly for [`Idx`]. Note that it even allows passing information on a
48//! slice's length across function boundaries by explicitly mentioning the same tag such as a
49//! generative lifetime twice.
50//!
51//! Use [`with_ref`] and [`with_mut`] as main entry functions or one the constructors on the type
52//! [`Generative`]. Note the interaction with the [`generativity`] crate which provides a macro that
53//! doesn't influence code flow, instead of requiring a closure wrapper like the methods given in
54//! this crate.
55//!
56//! [`generativity`]: https://docs.rs/generativity/
57//!
58//! [`with_ref`]: fn.with_ref.html
59//! [`with_mut`]: fn.with_mut.html
60//!
61//! The interface also permits some mutable operations on indices. These operations are restricted
62//! to some that can not make the new value exceed the bound of the hidden variable (such as:
63//! monotonically decreasing operations).
64//!
65//! The module even provides an 'algebra' for type level tags themselves. you can dynamically prove
66//! two tags to be equivalent, comparable, etc, by asserting that of the _hidden_ variables
67//! associated with each tag. This does not necessarily require the hidden value to be concrete but
68//! it is most powerful when you locally haven an [`ExactSize`] representing that hidden value.
69//! Then you can leverage these facts (which are also encoded as zero-sized types) to substitute
70//! tags in different manner. See the [`TagLessEq`] and [`TagEq`] types as well as the many
71//! combinators on [`ExactSize`], [`Prefix`], and [`Idx`].
72//!
73//! ## Checked constant bounds
74//!
75//! Alternatively we can choose other unique type instances. By that we mean that for any
76//! particular type exactly _one_ value must be used to construct [`ExactSize`]. One possible way
77//! is if this is simply a constant which is implemented by the `Constant` wrapper and its
78//! [`ConstantSource`] trait. For example one may define:
79//!
80//! ```
81//! use index_ext::tag::{Constant, ConstantSource, ExactSize};
82//!
83//! const BUFFER_SIZE: usize = 4096;
84//! struct BufferSize4K;
85//!
86//! impl ConstantSource for BufferSize4K {
87//!     const LEN: usize = BUFFER_SIZE;
88//! }
89//!
90//! const LEN: ExactSize<Constant<BufferSize4K>> = Constant::EXACT_SIZE;
91//! ```
92use core::marker::PhantomData;
93use core::num::NonZeroUsize;
94use core::ops::{Range, RangeFrom, RangeTo};
95
96/// A type suitable for tagging length, indices, and containers.
97///
98/// # Safety
99///
100/// The manner in which new [`ExactSize`] instances of types implementing this trait can be created
101/// is an invariant of each individual type. It must **not** be allowed to subvert the invariants
102/// imposed by any other type implementing this trait. In particular you mustn't create an instance
103/// that allows coercing a `ExactSize<ATag>` into `ExactSize<BTag>` where you don't control both
104/// these types. Note that this restriction MUST hold for every possible coercion allowed by the
105/// language. There are no inherently safe constructors for `ExactSize` but each tag type might
106/// define some.
107///
108/// The type must further promise to be zero-sized and have an alignment of exactly `1`. This
109/// allows tags to be virtually added to other referenced objects in-place.
110pub unsafe trait Tag: Copy {}
111
112/// A generative lifetime.
113///
114/// This is a simple implementor of `Tag` that allows a _local_ but entirely safe and macro-free
115/// use of check indices. The compiler introduces new lifetimes and the design of these types
116/// ensure that no other object with the same can be created.
117#[derive(Clone, Copy)]
118pub struct Generative<'lt> {
119    /// An invariant lifetime.
120    generated: PhantomData<&'lt fn(&'lt [()])>,
121}
122
123/// SAFETY: This is invariant over the lifetime. There are no other coercions.
124/// See <https://doc.rust-lang.org/nomicon/coercions.html#coercions>
125unsafe impl Tag for Generative<'_> {}
126
127/// A unique tag, 'named' by its type parameter.
128///
129/// Note that this type is safe to construct, but it is not safe to tag a slice or index with it.
130/// The user is responsible for ensuring the uniqueness of the type parameter, which is necessary
131/// for the soundness of wrapping an index or slice.
132pub struct TagNamed<T> {
133    phantom: PhantomData<T>,
134}
135
136/// Enter a region for soundly indexing a slice without bounds checks.
137///
138/// Prefer [`Generative::with_ref`] if possible.
139///
140/// The supplied function gets a freshly constructed pair of corresponding slice reference and
141/// length tag. It has no control over the exact lifetime used for the tag.
142pub fn with_ref<'slice, T, U>(
143    slice: &'slice [T],
144    f: impl for<'r> FnOnce(&'slice Slice<T, Generative<'r>>, ExactSize<Generative<'r>>) -> U,
145) -> U {
146    // We can not use `Generative::with_ref` here due to a lifetime conflict. If this was defined
147    // in this body then it would not outlive `'slice`.
148    let len = ExactSize {
149        inner: Prefix {
150            len: slice.len(),
151            tag: Generative {
152                generated: PhantomData,
153            },
154        },
155    };
156
157    let slice = unsafe { Slice::new_unchecked(slice, len.inner.tag) };
158
159    f(slice, len)
160}
161
162/// Enter a region for soundly indexing a mutable slice without bounds checks.
163///
164/// Prefer [`Generative::with_mut`] if possible.
165///
166/// The supplied function gets a freshly constructed pair of corresponding slice reference and
167/// length tag. It has no control over the exact lifetime used for the tag.
168pub fn with_mut<'slice, T, U>(
169    slice: &'slice mut [T],
170    f: impl for<'r> FnOnce(&'slice mut Slice<T, Generative<'r>>, ExactSize<Generative<'r>>) -> U,
171) -> U {
172    // We can not use `Generative::with_mut` here due to a lifetime conflict. If this was defined
173    // in this body then it would not outlive `'slice`.
174    let len = ExactSize {
175        inner: Prefix {
176            len: slice.len(),
177            tag: Generative {
178                generated: PhantomData,
179            },
180        },
181    };
182
183    let slice = unsafe { Slice::new_unchecked_mut(slice, len.inner.tag) };
184
185    f(slice, len)
186}
187
188/// The length of a particular slice (or a number of slices).
189///
190/// The encapsulated length field is guaranteed to be at most the length of each of the slices with
191/// the exact same tag. In other words, all indices _strictly smaller_ than this number are
192/// safe.
193///
194/// This allows this instance to construct indices that are validated to be able to soundly
195/// access the slices without required any particular slice instance. In particular, the construct
196/// might happen by a numerical algorithm independent of the slices and across method bounds where
197/// the compiler's optimizer and inline pass is no longer aware of the connection and would
198/// otherwise insert another check when the slice is indexed later.
199#[derive(Clone, Copy)]
200pub struct Prefix<Tag> {
201    len: usize,
202    tag: Tag,
203}
204
205/// A number that overestimates the guaranteed size of a number of slices.
206///
207/// This is the counter part of [`Prefix`]. It encapsulates a field that is guaranteed to be at least
208/// the size of all indices with the exact same tag. In other words, all slices at least as long
209/// as this number are safe to be accessed by indices.
210#[derive(Clone, Copy)]
211pub struct Capacity<Tag> {
212    len: usize,
213    tag: Tag,
214}
215
216/// The length of a non-empty slice.
217#[derive(Clone, Copy)]
218pub struct NonZeroLen<Tag> {
219    len: NonZeroUsize,
220    tag: Tag,
221}
222
223/// The _exact_ length separating slices and indices for a tag.
224///
225/// This serves as an constructor basis for 'importing' lengths and slices that are not previously
226/// connected through [`with_ref`] or equivalent constructors. This is also useful for cases where
227/// you want to create some bounds prior to the slice being available, or for creating bounds of
228/// custom tags.
229#[derive(Clone, Copy)]
230pub struct ExactSize<Tag> {
231    inner: Prefix<Tag>,
232}
233
234/// A proof that the length if A is smaller or equal to B.
235///
236/// This guarantees that indices of `A` can also be used in `B`.
237#[derive(Clone, Copy)]
238pub struct TagLessEq<TagA, TagB> {
239    a: TagA,
240    b: TagB,
241}
242
243/// A proof that two tags refer to equal lengths.
244///
245/// This guarantees that indices of `A` and `B` can be used interchangeably.
246#[derive(Clone, Copy)]
247pub struct TagEq<TagA, TagB> {
248    a: TagA,
249    b: TagB,
250}
251
252/// A slice with a unique type tag.
253///
254/// You can only construct this via the tag semantics associated with the type parameter, `Tag`.
255/// For instance see [`with_ref`], [`Generative::with_ref`], [`Const::with_ref`].
256///
257pub struct Slice<T, Tag> {
258    #[allow(dead_code)]
259    tag: Tag,
260    slice: [T],
261}
262
263/// An owned, allocated slice with a checked length.
264#[cfg(feature = "alloc")]
265pub struct Boxed<T, Tag> {
266    inner: alloc::boxed::Box<[T]>,
267    tag: Tag,
268}
269
270/// A type that names a constant buffer size.
271///
272/// See the module level documentation.
273pub trait ConstantSource {
274    /// The chosen length separating indices and slices.
275    const LEN: usize;
276}
277
278/// A tag using a `ConstantSource`.
279///
280/// The only safe way to construct an `ExactSize` is by copying the associated constant which
281/// expresses the length indicated in the trait impl. This implies that the value is unique.
282/// (Disregarding unsound rustc issues that allow duplicate trait impls).
283pub struct Constant<T>(PhantomData<fn(&mut T) -> T>);
284
285unsafe impl<T: ConstantSource> Tag for Constant<T> {}
286
287/// A tag using a const generic length parameter.
288///
289/// The only safe way to construct an `ExactSize` is by copying the associated constant which
290/// expresses the length indicated in the trait impl. This implies that the value is unique.
291///
292/// # Usage
293///
294/// ```
295/// use index_ext::tag::{Const, Slice};
296///
297/// let size = Const::<8>::EXACT_SIZE;
298///
299/// let data = [0, 1, 2, 3, 4, 5, 6, 7];
300/// let slice = Slice::new(&data[..], size).unwrap();
301///
302/// let prefix = size
303///     .into_len()
304///     .truncate(4)
305///     .range_to_self();
306///
307/// let prefix = &slice[prefix];
308/// assert_eq!(prefix, [0, 1, 2, 3]);
309/// ```
310#[derive(Clone, Copy)]
311pub struct Const<const N: usize>;
312
313unsafe impl<const N: usize> Tag for Const<N> {}
314
315/// A valid index for all slices of the same length.
316///
317/// While this has a generic parameter, you can only instantiate this type for specific types
318/// through one of the constructors of a corresponding [`Prefix]` struct.
319///
320/// [`Prefix`]: struct.Prefix.html
321#[derive(Clone, Copy)]
322pub struct Idx<I, Tag> {
323    idx: I,
324    /// An invariant lifetime.
325    tag: Tag,
326}
327
328/// An allocation of bounded indices that can be retrieved with a bound.
329///
330/// The usefulness comes from the fact that there is not tag on the type but instead one is
331/// assigned when retrieving the contents. In particular you don't need a unique type to construct
332/// this container.
333#[cfg(feature = "alloc")]
334pub struct IdxBox<Idx> {
335    indices: alloc::boxed::Box<[Idx]>,
336    /// The dynamic bound of indices.
337    exact_size: usize,
338}
339
340impl<T: Tag> Prefix<T> {
341    /// Interpret this with the tag of a set of potentially longer slices.
342    ///
343    /// The proof of inequality was performed in any of the possible constructors that allow the
344    /// instance of `TagLessEq` to exist in the first place.
345    pub fn with_tag<NewT>(self, less: TagLessEq<T, NewT>) -> Prefix<NewT> {
346        let len = self.len;
347        let tag = less.b;
348        Prefix { len, tag }
349    }
350
351    /// Returns the stored length.
352    #[must_use = "Is a no-op. Use the returned length."]
353    pub fn get(self) -> usize {
354        self.len
355    }
356
357    /// Construct an index to a single element.
358    ///
359    /// This method return `Some` when the index is smaller than the length.
360    #[must_use = "Returns a new index"]
361    pub fn index(self, idx: usize) -> Option<Idx<usize, T>> {
362        if idx < self.len {
363            Some(Idx { idx, tag: self.tag })
364        } else {
365            None
366        }
367    }
368
369    /// Construct an index to a range of element.
370    ///
371    /// This method return `Some` when the indices are ordered and `to` does not exceed the length.
372    #[must_use = "Returns a new index"]
373    pub fn range(self, from: usize, to: usize) -> Option<Idx<core::ops::Range<usize>, T>> {
374        if from <= to && to <= self.len {
375            Some(Idx {
376                idx: from..to,
377                tag: self.tag,
378            })
379        } else {
380            None
381        }
382    }
383
384    /// Construct an index to a range from an element.
385    ///
386    /// This method return `Some` when `from` does not exceed the length.
387    #[must_use = "Returns a new index"]
388    pub fn range_from(self, from: usize) -> Option<Idx<core::ops::RangeFrom<usize>, T>> {
389        if from <= self.len {
390            Some(Idx {
391                idx: from..,
392                tag: self.tag,
393            })
394        } else {
395            None
396        }
397    }
398
399    /// Construct an index to a range starting at this length.
400    ///
401    /// This method might return an index for an empty range.
402    #[must_use = "Returns a new index"]
403    pub fn range_from_self(self) -> Idx<core::ops::RangeFrom<usize>, T> {
404        Idx {
405            idx: self.len..,
406            tag: self.tag,
407        }
408    }
409
410    /// Construct an index to a range up to an element.
411    ///
412    /// This method return `Some` when `to` does not exceed the length.
413    #[must_use = "Returns a new index"]
414    pub fn range_to(self, to: usize) -> Option<Idx<core::ops::RangeTo<usize>, T>> {
415        if to <= self.len {
416            Some(Idx {
417                idx: ..to,
418                tag: self.tag,
419            })
420        } else {
421            None
422        }
423    }
424
425    /// Construct an index to a range up, exclusive, to this length.
426    ///
427    /// This method might return an index for an empty range.
428    #[must_use = "Returns a new index"]
429    pub fn range_to_self(self) -> Idx<core::ops::RangeTo<usize>, T> {
430        Idx {
431            idx: ..self.len,
432            tag: self.tag,
433        }
434    }
435
436    /// Construct an index referring to the unordered range from one element to another.
437    ///
438    /// This method might return an empty range. The order of arguments does not matter.
439    #[must_use = "Returns a new index"]
440    pub fn range_between(self, other: Self) -> Idx<core::ops::Range<usize>, T> {
441        Idx {
442            idx: self.len.min(other.len)..self.len.max(other.len),
443            tag: self.tag,
444        }
445    }
446
447    /// Construct an index to all elements.
448    ///
449    /// This method exists mostly for completeness sake. There is no bounds check when accessing a
450    /// complete slice with `..`.
451    #[must_use = "Returns a new index"]
452    pub fn range_full(self) -> Idx<core::ops::RangeFull, T> {
453        Idx {
454            idx: ..,
455            tag: self.tag,
456        }
457    }
458
459    /// Create a smaller length.
460    #[must_use = "Returns a new index"]
461    pub fn saturating_sub(self, sub: usize) -> Self {
462        Prefix {
463            len: self.len.saturating_sub(sub),
464            tag: self.tag,
465        }
466    }
467
468    /// Bound the length from above.
469    #[must_use = "Returns a new index"]
470    pub fn truncate(self, min: usize) -> Self {
471        Prefix {
472            len: self.len.min(min),
473            tag: self.tag,
474        }
475    }
476}
477
478impl<T: Tag> Capacity<T> {
479    /// Interpret this with the tag of a set of potentially shorter slices.
480    ///
481    /// The proof of inequality was performed in any of the possible constructors that allow the
482    /// instance of `TagLessEq` to exist in the first place.
483    pub fn with_tag<NewT>(self, less: TagLessEq<NewT, T>) -> Capacity<NewT> {
484        let len = self.len;
485        let tag = less.a;
486        Capacity { len, tag }
487    }
488
489    /// Returns the stored length.
490    #[must_use = "Is a no-op. Use the returned length."]
491    pub fn get(self) -> usize {
492        self.len
493    }
494
495    /// Create a larger capacity.
496    #[must_use = "Returns a new capacity"]
497    pub fn saturating_add(self, add: usize) -> Self {
498        Capacity {
499            len: self.len.saturating_add(add),
500            tag: self.tag,
501        }
502    }
503
504    /// Bound the length from below.
505    #[must_use = "Returns a new capacity"]
506    pub fn ensure(self, min: usize) -> Self {
507        Capacity {
508            len: self.len.max(min),
509            tag: self.tag,
510        }
511    }
512}
513
514impl<T: Tag> NonZeroLen<T> {
515    /// Construct the length of a non-empty slice.
516    pub fn new(complete: Prefix<T>) -> Option<Self> {
517        let len = NonZeroUsize::new(complete.len)?;
518        Some(NonZeroLen {
519            len,
520            tag: complete.tag,
521        })
522    }
523
524    /// Interpret this with the tag of a potentially longer slice.
525    ///
526    /// The proof of inequality was performed in any of the possible constructors that allow the
527    /// instance of `TagLessEq` to exist in the first place.
528    pub fn with_tag<NewT>(self, less: TagLessEq<T, NewT>) -> NonZeroLen<NewT> {
529        let len = self.len;
530        let tag = less.b;
531        NonZeroLen { len, tag }
532    }
533
534    /// Construct an index to the first element of a non-empty slice.
535    #[must_use = "Returns a new index"]
536    pub fn first(self) -> Idx<usize, T> {
537        Idx {
538            idx: 0,
539            tag: self.tag,
540        }
541    }
542
543    /// Construct an index to the last element of a non-empty slice.
544    #[must_use = "Returns a new index"]
545    pub fn last(self) -> Idx<usize, T> {
546        Idx {
547            idx: self.len.get() - 1,
548            tag: self.tag,
549        }
550    }
551
552    /// Construct the corresponding potentially empty length representation.
553    #[must_use = "Returns a new index"]
554    pub fn into_len(self) -> Prefix<T> {
555        Prefix {
556            len: self.len.get(),
557            tag: self.tag,
558        }
559    }
560
561    /// Get the non-zero length.
562    #[must_use = "Is a no-op. Use the returned length."]
563    pub fn get(self) -> NonZeroUsize {
564        self.len
565    }
566}
567
568/// The const methods for `ExactSize`.
569///
570/// Since trait bounds are not currently usable on stable the selection is limited. **Note**: It is
571/// of importance to soundness that it is not possible to construct an instance without the `Tag`
572/// bound. Otherwise, one might coerce _into_ an `ExactSize` with an improper tag. This is not
573/// likely to be possible but nevertheless the `Tag` does not require it to be impossible.
574impl<T> ExactSize<T> {
575    /// Construct a new bound between yet-to-create indices and slices.
576    ///
577    /// # Safety
578    ///
579    /// All `ExactSize` instances with the same tag type must also have the same `len` field.
580    pub const unsafe fn new_untagged(len: usize, tag: T) -> Self {
581        ExactSize {
582            inner: Prefix { len, tag },
583        }
584    }
585
586    /// Construct a new bound from a length.
587    ///
588    /// # Safety
589    ///
590    /// You _must_ ensure that no slice with this same tag can be shorter than `len`. In particular
591    /// there mustn't be any other `ExactSize` with a differing length.
592    ///
593    /// `T` should be a type implementing `Tag` but this can not be expressed with `const fn` atm.
594    pub const unsafe fn from_len_untagged(bound: Prefix<T>) -> Self {
595        ExactSize { inner: bound }
596    }
597
598    /// Returns the length.
599    #[must_use = "Is a no-op. Use the returned length."]
600    pub const fn get(&self) -> usize {
601        self.inner.len
602    }
603}
604
605impl<'lt> Generative<'lt> {
606    /// Construct a size with a generative guard and explicit length.
607    ///
608    /// The `Guard` instance is a token that verifies that no other instance with that particular
609    /// lifetime exists. It is thus not possible to safely construct a second `ExactSize` with the
610    /// same tag but a different length. This uniquely ties the value `len` to that lifetime.
611    pub fn with_len(len: usize, token: generativity::Guard<'lt>) -> ExactSize<Self> {
612        ExactSize::with_guard(len, token)
613    }
614
615    /// Consume a generativity token to associated a lifetime with the slice's length.
616    ///
617    /// This isn't fundamentally different from using [`Self::with_len`] and [`Slice::new`], and
618    /// you might want to see those documentations, but it clarifies that this combination is
619    /// infallible.
620    ///
621    /// This essentially shares the generative uniqueness of the lifetime among all values relying
622    /// on the length predicate of the same slice.
623    ///
624    /// # Usage
625    ///
626    /// This allows you to do the same as [`with_ref`] but ad-hoc within a function body without
627    /// introducing any new scope.
628    ///
629    /// ```
630    /// use generativity::make_guard;
631    /// use index_ext::tag::Generative;
632    ///
633    /// let data = (0..117).collect::<Vec<_>>();
634    /// make_guard!(guard);
635    /// let (slice, size) = Generative::with_ref(&data, guard);
636    /// let index = size.into_len().range_to_self();
637    ///
638    /// // … Later, no bounds check here.
639    /// let data = &slice[index];
640    /// ```
641    pub fn with_ref<'slice, T>(
642        slice: &'slice [T],
643        token: generativity::Guard<'lt>,
644    ) -> (&'slice Slice<T, Self>, ExactSize<Self>) {
645        let size = ExactSize::with_guard(slice.len(), token);
646        // Safety: This tag is associated with the exact length of the slice in the line above
647        // which is less or equal to the length of the slice.
648        let ref_ = unsafe { Slice::new_unchecked(slice, size.inner.tag) };
649        (ref_, size)
650    }
651
652    /// Consume a generativity token to associated a lifetime with the mutable slice's length.
653    ///
654    /// This isn't fundamentally different from using [`Self::with_len`] and [`Slice::new_mut`],
655    /// and you might want to see those documentations, but it clarifies that this combination is
656    /// infallible.
657    ///
658    /// This essentially shares the generative uniqueness of the lifetime among all values relying
659    /// on the length predicate of the same slice.
660    ///
661    /// # Usage
662    ///
663    /// This allows you to do the same as [`with_mut`] but ad-hoc within a function body without
664    /// introducing any new scope.
665    ///
666    /// ```
667    /// use generativity::make_guard;
668    /// use index_ext::tag::Generative;
669    ///
670    /// let mut data = (0..117).collect::<Vec<_>>();
671    /// make_guard!(guard);
672    /// let (mut slice, size) = Generative::with_mut(&mut data, guard);
673    /// let index = size.into_len().range_to_self();
674    ///
675    /// // … Later, no bounds check here.
676    /// let data = &mut slice[index];
677    pub fn with_mut<'slice, T>(
678        slice: &'slice mut [T],
679        token: generativity::Guard<'lt>,
680    ) -> (&'slice mut Slice<T, Self>, ExactSize<Self>) {
681        let size = ExactSize::with_guard(slice.len(), token);
682        // Safety: This tag is associated with the exact length of the slice in the line above
683        // which is less or equal to the length of the slice.
684        let ref_ = unsafe { Slice::new_unchecked_mut(slice, size.inner.tag) };
685        (ref_, size)
686    }
687}
688
689impl<'lt> ExactSize<Generative<'lt>> {
690    /// Construct a size with a generative guard.
691    ///
692    /// The `Guard` instance is a token that verifies that no other instance with that particular
693    /// lifetime exists. It is thus not possible to safely construct a second `ExactSize` with the
694    /// same tag but a different length. This uniquely ties the value `len` to that lifetime.
695    ///
696    /// FIXME: make this `const fn` which requires `PhantomData<fn()>` to be allowed in const
697    /// context (a small subset of #57563).
698    pub fn with_guard(len: usize, _: generativity::Guard<'lt>) -> Self {
699        ExactSize {
700            inner: Prefix {
701                len,
702                tag: Generative {
703                    generated: PhantomData,
704                },
705            },
706        }
707    }
708}
709
710impl<T: Tag> ExactSize<T> {
711    /// Construct a new bound between yet-to-create indices and slices.
712    ///
713    /// # Safety
714    ///
715    /// All `ExactSize` instances with the same tag type must also have the same `len` field.
716    pub unsafe fn new(len: usize, tag: T) -> Self {
717        // Safety: Propagates the exact same safety requirements.
718        unsafe { Self::new_untagged(len, tag) }
719    }
720
721    /// Construct a new bound from a length.
722    ///
723    /// # Safety
724    ///
725    /// You _must_ ensure that no slice with this same tag can be shorter than `len`. In particular
726    /// there mustn't be any other `ExactSize` with a differing length.
727    pub unsafe fn from_len(len: Prefix<T>) -> Self {
728        // Safety: Propagates a subset of safety requirements.
729        unsafe { Self::from_len_untagged(len) }
730    }
731
732    /// Construct a new bound from a capacity.
733    ///
734    /// # Safety
735    ///
736    /// You _must_ ensure that no index with this same tag can be above `cap`. In particular there
737    /// mustn't be any other `ExactSize` with a differing length but the same tag type.
738    pub unsafe fn from_capacity(cap: Capacity<T>) -> Self {
739        // Safety: Propagates a subset of safety requirements.
740        unsafe { Self::new_untagged(cap.len, cap.tag) }
741    }
742
743    /// Interpret this with the tag of an equal sized slice.
744    ///
745    /// The proof of equality was performed in any of the possible constructors that allow the
746    /// instance of `TagEq` to exist in the first place.
747    pub fn with_tag<NewT>(self, equality: TagEq<T, NewT>) -> ExactSize<NewT> {
748        let len = self.inner.len;
749        let tag = equality.b;
750        ExactSize {
751            inner: Prefix { len, tag },
752        }
753    }
754
755    /// Convert this into a simple `Prefix` without changing the length.
756    ///
757    /// The `Prefix` is only required to be _not longer_ than all slices but not required to have the
758    /// exact separating size. As such, one can not use it to infer that some particular slice is
759    /// long enough to be allowed. This is not safely reversible.
760    #[must_use = "Returns a new index"]
761    pub fn into_len(self) -> Prefix<T> {
762        self.inner
763    }
764
765    /// Convert this into a simple `Capacity` without changing the length.
766    ///
767    /// The `Capacity` is only required to be _not shorter_ than all slices but not required to
768    /// have the exact separating size. As such, one can use it only to infer that some particular
769    /// slice is long enough to be allowed. This is not safely reversible.
770    #[must_use = "Returns a new index"]
771    pub fn into_capacity(self) -> Capacity<T> {
772        Capacity {
773            len: self.inner.len,
774            tag: self.inner.tag,
775        }
776    }
777
778    /// Construct a new bound from an pair of Prefix and Capacity with the same value.
779    ///
780    /// Note that the invariant of `ExactSize` is that all `Prefix` are guaranteed to be at most the
781    /// size and all `Capacity` are guaranteed to be at least the size. The only possible overlap
782    /// between the two is the exact length, which we can dynamically check.
783    pub fn with_matching_pair(len: Prefix<T>, cap: Capacity<T>) -> Option<Self> {
784        if len.get() == cap.get() {
785            Some(ExactSize {
786                inner: Prefix {
787                    len: len.get(),
788                    tag: len.tag,
789                },
790            })
791        } else {
792            None
793        }
794    }
795}
796
797impl<A: Tag> TagEq<A, A> {
798    /// Construct the reflexive proof.
799    pub fn reflexive(tag: A) -> Self {
800        TagEq { a: tag, b: tag }
801    }
802}
803
804impl<A: Tag, B: Tag> TagEq<A, B> {
805    /// Create an equality from evidence `a <= b <= a`.
806    pub fn new(lhs: TagLessEq<A, B>, _: TagLessEq<B, A>) -> Self {
807        TagEq { a: lhs.a, b: lhs.b }
808    }
809
810    /// Swap the two tags, `a = b` iff `b = a`.
811    pub fn transpose(self) -> TagEq<B, A> {
812        TagEq {
813            a: self.b,
814            b: self.a,
815        }
816    }
817
818    /// Relax this into a less or equal relation.
819    pub fn into_le(self) -> TagLessEq<A, B> {
820        TagLessEq {
821            a: self.a,
822            b: self.b,
823        }
824    }
825}
826
827impl<A: Tag> TagLessEq<A, A> {
828    /// Construct the reflexive proof.
829    pub fn reflexive(tag: A) -> Self {
830        TagLessEq { a: tag, b: tag }
831    }
832}
833
834impl<A: Tag, B: Tag> TagLessEq<A, B> {
835    /// Construct the proof from the sizes of A and B.
836    pub fn with_sizes(a: ExactSize<A>, b: ExactSize<B>) -> Option<Self> {
837        if a.get() <= b.get() {
838            Some(TagLessEq {
839                a: a.inner.tag,
840                b: b.inner.tag,
841            })
842        } else {
843            None
844        }
845    }
846
847    /// Construct the proof from a pair of bounds for A and B.
848    ///
849    /// The `Capacity` upper bounds all indices applicable to A, and the exact size. The `Prefix`
850    /// lower bounds all lengths and the exact size.
851    ///
852    /// This returns `Some` when the lower bound for B is not smaller than the upper bound for A.
853    pub fn with_pair(a: Capacity<A>, b: Prefix<B>) -> Option<Self> {
854        if b.get() >= a.get() {
855            Some(TagLessEq { a: a.tag, b: b.tag })
856        } else {
857            None
858        }
859    }
860}
861
862impl<T> TagNamed<T> {
863    /// Create a new named tag.
864    ///
865    /// The instance is only to be encouraged to only use types private to your crate or module,
866    /// this method immediately *forgets* the instance which is currently required for `const`ness.
867    pub const fn new(t: T) -> Self {
868        // Const-fn does not allow dropping values. We don't want (and can't have) `T: Copy` so we
869        // need to statically prove this to rustc by actually removing the drop call.
870        let _ = core::mem::ManuallyDrop::new(t);
871        TagNamed {
872            phantom: PhantomData,
873        }
874    }
875}
876
877unsafe impl<T> Tag for TagNamed<T> {}
878
879impl<T: Tag> From<NonZeroLen<T>> for Prefix<T> {
880    fn from(from: NonZeroLen<T>) -> Self {
881        Prefix {
882            len: from.len.get(),
883            tag: from.tag,
884        }
885    }
886}
887
888impl<T, I> Idx<I, T> {
889    /// Get the inner index.
890    pub fn into_inner(self) -> I {
891        self.idx
892    }
893
894    /// Interpret this as an index into a larger slice.
895    pub fn with_tag<NewT>(self, larger: TagLessEq<T, NewT>) -> Idx<I, NewT> {
896        Idx {
897            idx: self.idx,
898            tag: larger.b,
899        }
900    }
901}
902
903impl<T> Idx<usize, T> {
904    /// Create a smaller index.
905    #[must_use = "Returns a new index"]
906    pub fn saturating_sub(self, sub: usize) -> Self {
907        Idx {
908            idx: self.idx.saturating_sub(sub),
909            tag: self.tag,
910        }
911    }
912
913    /// Bound the index from above.
914    #[must_use = "Returns a new index"]
915    pub fn truncate(self, min: usize) -> Self {
916        Idx {
917            idx: self.idx.min(min),
918            tag: self.tag,
919        }
920    }
921
922    /// Return the range that contains this element.
923    #[must_use = "Returns a new index"]
924    pub fn into_range(self) -> Idx<core::ops::Range<usize>, T> {
925        Idx {
926            idx: self.idx..self.idx + 1,
927            tag: self.tag,
928        }
929    }
930
931    /// Get a length up-to, not including this index.
932    #[must_use = "Returns a new index"]
933    pub fn into_len(self) -> Prefix<T> {
934        Prefix {
935            len: self.idx,
936            tag: self.tag,
937        }
938    }
939
940    /// Get the length beyond this index.
941    ///
942    /// Unlike turning it into a range and using its end, this guarantees that the end is non-zero
943    /// as it knows the range not to be empty.
944    #[must_use = "Returns a new index"]
945    pub fn into_end(self) -> NonZeroLen<T> {
946        NonZeroLen {
947            len: NonZeroUsize::new(self.idx + 1).unwrap(),
948            tag: self.tag,
949        }
950    }
951}
952
953impl<T> Idx<RangeTo<usize>, T> {
954    /// Get a length up-to, not including this index.
955    #[must_use = "Returns a new index"]
956    pub fn into_end(self) -> Prefix<T> {
957        Prefix {
958            len: self.idx.end,
959            tag: self.tag,
960        }
961    }
962
963    /// Construct an index starting at an element.
964    ///
965    /// This method return `Some` when `from` does not exceed the end index.
966    #[must_use = "Returns a new index"]
967    pub fn range_from(self, from: Prefix<T>) -> Option<Idx<core::ops::Range<usize>, T>> {
968        if from.len <= self.idx.end {
969            Some(Idx {
970                idx: from.len..self.idx.end,
971                tag: self.tag,
972            })
973        } else {
974            None
975        }
976    }
977}
978
979impl<T> Idx<RangeFrom<usize>, T> {
980    /// Get a length up-to, not including this index.
981    #[must_use = "Returns a new index"]
982    pub fn into_start(self) -> Prefix<T> {
983        Prefix {
984            len: self.idx.start,
985            tag: self.tag,
986        }
987    }
988
989    /// Construct an index up to at an element.
990    ///
991    /// This method return `Some` when `to` does not exceed the end index.
992    #[must_use = "Returns a new index"]
993    pub fn range_to(self, to: Prefix<T>) -> Option<Idx<core::ops::Range<usize>, T>> {
994        if to.len >= self.idx.start {
995            Some(Idx {
996                idx: self.idx.start..to.len,
997                tag: self.tag,
998            })
999        } else {
1000            None
1001        }
1002    }
1003}
1004
1005impl<T> Idx<Range<usize>, T> {
1006    /// Get a length up-to, not including this index.
1007    #[must_use = "Returns a new index"]
1008    pub fn into_start(self) -> Prefix<T> {
1009        Prefix {
1010            len: self.idx.start,
1011            tag: self.tag,
1012        }
1013    }
1014
1015    /// Get a length up-to, not including this index.
1016    #[must_use = "Returns a new index"]
1017    pub fn into_end(self) -> Prefix<T> {
1018        Prefix {
1019            len: self.idx.end,
1020            tag: self.tag,
1021        }
1022    }
1023}
1024
1025#[allow(unused_unsafe)]
1026impl<T: Tag, E> Slice<E, T> {
1027    /// Try to wrap a slice into a safe index wrapper.
1028    ///
1029    /// Returns `Some(_)` if the slice is at least as long as the `size` requires, otherwise
1030    /// returns `None`.
1031    pub fn new(slice: &[E], size: ExactSize<T>) -> Option<&'_ Self> {
1032        if slice.len() >= size.into_len().get() {
1033            Some(unsafe { Self::new_unchecked(slice, size.inner.tag) })
1034        } else {
1035            None
1036        }
1037    }
1038
1039    /// Try to wrap a mutable slice into a safe index wrapper.
1040    ///
1041    /// Returns `Some(_)` if the slice is at least as long as the `size` requires, otherwise
1042    /// returns `None`.
1043    pub fn new_mut(slice: &mut [E], size: ExactSize<T>) -> Option<&'_ mut Self> {
1044        if slice.len() >= size.into_len().get() {
1045            Some(unsafe { Self::new_unchecked_mut(slice, size.inner.tag) })
1046        } else {
1047            None
1048        }
1049    }
1050
1051    /// Unsafely wrap a slice into an index wrapper.
1052    ///
1053    /// # Safety
1054    ///
1055    /// The caller must uphold that the _exact size_ associated with the type `Tag` (see
1056    /// [`ExactSize::new_untagged`]) is at most as large as the length of this slice.
1057    pub unsafe fn new_unchecked(slice: &[E], _: T) -> &'_ Self {
1058        // SAFETY: by T: Tag we know that T is 1-ZST which makes Self have the same layout as [E].
1059        // Further, tag is evidence that T is inhabited and T: Copy implies T: !Drop.
1060        // Finally, the tag is valid for the slice's length by assumption of relying on the caller.
1061        unsafe { &*(slice as *const [E] as *const Self) }
1062    }
1063
1064    /// Unsafely wrap a mutable slice into an index wrapper.
1065    ///
1066    /// # Safety
1067    ///
1068    /// The caller must uphold that the _exact size_ associated with the type `Tag` (see
1069    /// [`ExactSize::new_untagged`]) is at most as large as the length of this slice.
1070    pub unsafe fn new_unchecked_mut(slice: &mut [E], _: T) -> &'_ mut Self {
1071        // SAFETY: by T: Tag we know that T is 1-ZST which makes Self have the same layout as [E].
1072        // Further, tag is evidence that T is inhabited and T: Copy implies T: !Drop.
1073        // Finally, the tag is valid for the slice's length by assumption of relying on the caller.
1074        unsafe { &mut *(slice as *mut [E] as *mut Self) }
1075    }
1076
1077    /// Interpret this as a slice with smaller length.
1078    pub fn with_tag<NewT: Tag>(&self, _: TagLessEq<NewT, T>) -> &'_ Slice<E, NewT> {
1079        // SAFETY: by NewT: Tag we know that T NewT is 1-ZST which makes Self have the same layout
1080        // as [E] and consequently the same layout as Self.  Further, smaller.a is evidence that
1081        // NewT is inhabited and NewT: Copy implies NewT: !Drop. Finally, the tag is valid for the
1082        // slice's length by assumption of relying on self.element being valid based on the
1083        // invariant of Self.
1084        unsafe { &*(self as *const Self as *const Slice<E, NewT>) }
1085    }
1086
1087    /// Interpret this as a slice with smaller length.
1088    pub fn with_tag_mut<NewT: Tag>(&mut self, _: TagLessEq<NewT, T>) -> &'_ mut Slice<E, NewT> {
1089        // SAFETY: by NewT: Tag we know that T NewT is 1-ZST which makes Self have the same layout
1090        // as [E] and consequently the same layout as Self.  Further, smaller.a is evidence that
1091        // NewT is inhabited and NewT: Copy implies NewT: !Drop. Finally, the tag is valid for the
1092        // slice's length by assumption of relying on self.element being valid based on the
1093        // invariant of Self.
1094        unsafe { &mut *(self as *mut Self as *mut Slice<E, NewT>) }
1095    }
1096
1097    /// Get the length as a `Capacity` of all slices with this tag.
1098    pub fn capacity(&self) -> Capacity<T> {
1099        Capacity {
1100            len: self.slice.len(),
1101            tag: self.tag,
1102        }
1103    }
1104}
1105
1106impl<T, E> Slice<E, T> {
1107    /// Index the slice unchecked but soundly.
1108    pub fn get_safe<I: core::slice::SliceIndex<[E]>>(&self, index: Idx<I, T>) -> &I::Output {
1109        unsafe { self.slice.get_unchecked(index.idx) }
1110    }
1111
1112    /// Mutably index the slice unchecked but soundly.
1113    pub fn get_safe_mut<I: core::slice::SliceIndex<[E]>>(
1114        &mut self,
1115        index: Idx<I, T>,
1116    ) -> &mut I::Output {
1117        unsafe { self.slice.get_unchecked_mut(index.idx) }
1118    }
1119}
1120
1121#[cfg(feature = "alloc")]
1122impl<T: Tag, E> Boxed<E, T> {
1123    /// Try to construct an asserted box, returning it on error.
1124    ///
1125    /// The box slice must have _exactly_ the length indicated.
1126    pub fn new(
1127        inner: alloc::boxed::Box<[E]>,
1128        len: ExactSize<T>,
1129    ) -> Result<Self, alloc::boxed::Box<[E]>> {
1130        match Slice::new(&*inner, len) {
1131            Some(_) => Ok(Boxed {
1132                inner,
1133                tag: len.inner.tag,
1134            }),
1135            None => Err(inner),
1136        }
1137    }
1138
1139    /// Reference the contents as an asserted `Slice`.
1140    pub fn as_ref(&self) -> &'_ Slice<E, T> {
1141        // SAFETY: the inner invariant of `Boxed` is that the length is at least as large as the
1142        // `ExactSize`, ensured in its only constructor `new`.
1143        unsafe { Slice::new_unchecked(&*self.inner, self.tag) }
1144    }
1145
1146    /// Reference the contents as an asserted mutable `Slice`.
1147    pub fn as_mut(&mut self) -> &'_ mut Slice<E, T> {
1148        // SAFETY: the inner invariant of `Boxed` is that the length is at least as large as the
1149        // `ExactSize`, ensured in its only constructor `new`.
1150        unsafe { Slice::new_unchecked_mut(&mut *self.inner, self.tag) }
1151    }
1152
1153    /// Get the length as a `Capacity` of all slices with this tag.
1154    pub fn capacity(&self) -> Capacity<T> {
1155        Capacity {
1156            len: self.inner.len(),
1157            tag: self.tag,
1158        }
1159    }
1160
1161    /// Index the boxed slice unchecked but soundly.
1162    pub fn get_safe<I: core::slice::SliceIndex<[E]>>(&self, index: Idx<I, T>) -> &I::Output {
1163        self.as_ref().get_safe(index)
1164    }
1165
1166    /// Mutably index the boxed slice unchecked but soundly.
1167    pub fn get_safe_mut<I: core::slice::SliceIndex<[E]>>(
1168        &mut self,
1169        index: Idx<I, T>,
1170    ) -> &mut I::Output {
1171        self.as_mut().get_safe_mut(index)
1172    }
1173
1174    /// Unwrap the inner box, dropping all assertions of safe indexing.
1175    pub fn into_inner(self) -> alloc::boxed::Box<[E]> {
1176        self.inner
1177    }
1178}
1179
1180impl<E, T> core::ops::Deref for Slice<E, T> {
1181    type Target = [E];
1182    fn deref(&self) -> &[E] {
1183        &self.slice
1184    }
1185}
1186
1187impl<E, T> core::ops::DerefMut for Slice<E, T> {
1188    fn deref_mut(&mut self) -> &mut [E] {
1189        &mut self.slice
1190    }
1191}
1192
1193impl<T: Tag, E, I> core::ops::Index<Idx<I, T>> for Slice<E, T>
1194where
1195    I: core::slice::SliceIndex<[E]>,
1196{
1197    type Output = I::Output;
1198    fn index(&self, idx: Idx<I, T>) -> &Self::Output {
1199        self.get_safe(idx)
1200    }
1201}
1202
1203impl<T: Tag, E, I> core::ops::IndexMut<Idx<I, T>> for Slice<E, T>
1204where
1205    I: core::slice::SliceIndex<[E]>,
1206{
1207    fn index_mut(&mut self, idx: Idx<I, T>) -> &mut Self::Output {
1208        self.get_safe_mut(idx)
1209    }
1210}
1211
1212impl<T> Clone for TagNamed<T> {
1213    fn clone(&self) -> Self {
1214        *self
1215    }
1216}
1217
1218impl<T> Copy for TagNamed<T> {}
1219
1220impl<T> Clone for Constant<T> {
1221    fn clone(&self) -> Self {
1222        *self
1223    }
1224}
1225
1226impl<T> Copy for Constant<T> {}
1227
1228impl<T: ConstantSource> Constant<T> {
1229    /// A constructed instance of `ExactSize<Self>`.
1230    ///
1231    /// The instance can be freely copied. Making this an associated constant ensures that the
1232    /// length associated with the type is the associated `LEN` constant while also permitting use
1233    /// in `const` environments, despite the `ConstantSource` bound on the parameter. There are no
1234    /// other safe constructors for this tag's `ExactSize` type.
1235    pub const EXACT_SIZE: ExactSize<Self> =
1236        // SAFETY: all instances have the same length, `LEN`.
1237        unsafe { ExactSize::new_untagged(T::LEN, Constant(PhantomData)) };
1238}
1239
1240impl<const N: usize> Const<N> {
1241    /// A constructed instance of `ExactSize<Self>`.
1242    ///
1243    /// The instance can be freely copied. Making this an associated constant ensures that the
1244    /// length associated with the type is the constant parameter `N`. There are no other safe
1245    /// constructors for this tag's `ExactSize` type.
1246    pub const EXACT_SIZE: ExactSize<Self> =
1247        // SAFETY: all instances have the same length, `N`.
1248        unsafe { ExactSize::new_untagged(N, Const) };
1249
1250    /// Create a [`Slice`] wrapping the array.
1251    pub fn with_ref<T>(self, arr: &[T; N]) -> &'_ Slice<T, Self> {
1252        unsafe { Slice::new_unchecked(&arr[..], self) }
1253    }
1254
1255    /// Create a [`Slice`] wrapping the array mutably.
1256    pub fn with_mut<T>(self, arr: &mut [T; N]) -> &'_ mut Slice<T, Self> {
1257        unsafe { Slice::new_unchecked_mut(&mut arr[..], self) }
1258    }
1259}
1260
1261#[cfg(feature = "alloc")]
1262mod impl_of_boxed_idx {
1263    use super::{ExactSize, Idx, IdxBox, Prefix, Tag};
1264    use core::ops::{RangeFrom, RangeTo};
1265
1266    /// Sealed trait, quite unsafe..
1267    pub trait HiddenMaxIndex: Sized {
1268        fn exclusive_upper_bound(this: &[Self]) -> Option<usize>;
1269    }
1270
1271    impl HiddenMaxIndex for usize {
1272        fn exclusive_upper_bound(this: &[Self]) -> Option<usize> {
1273            this.iter()
1274                .copied()
1275                .max()
1276                .map_or(Some(0), |idx| idx.checked_add(1))
1277        }
1278    }
1279
1280    impl HiddenMaxIndex for RangeFrom<usize> {
1281        fn exclusive_upper_bound(this: &[Self]) -> Option<usize> {
1282            this.iter().map(|range| range.start).max()
1283        }
1284    }
1285
1286    impl HiddenMaxIndex for RangeTo<usize> {
1287        fn exclusive_upper_bound(this: &[Self]) -> Option<usize> {
1288            this.iter().map(|range| range.end).max()
1289        }
1290    }
1291
1292    impl<I: HiddenMaxIndex> IdxBox<I> {
1293        /// Wrap an allocation of indices.
1294        /// This will fail if it not possible to express the lower bound of slices for which all
1295        /// indices are valid, as a `usize`. That is, if any of the indices references the element
1296        /// with index `usize::MAX` itself.
1297        pub fn new(indices: alloc::boxed::Box<[I]>) -> Result<Self, alloc::boxed::Box<[I]>> {
1298            match HiddenMaxIndex::exclusive_upper_bound(&indices[..]) {
1299                Some(upper_bound) => Ok(IdxBox {
1300                    indices,
1301                    exact_size: upper_bound,
1302                }),
1303                None => Err(indices),
1304            }
1305        }
1306
1307        /// Return the upper bound over all indices.
1308        /// This is not guaranteed to be the _least_ upper bound.
1309        pub fn bound(&self) -> usize {
1310            self.exact_size
1311        }
1312
1313        /// Ensure that the stored `bound` is at least `min`.
1314        pub fn ensure(&mut self, min: usize) {
1315            self.exact_size = self.exact_size.max(min);
1316        }
1317
1318        /// Set the bound to the least upper bound of all indices.
1319        ///
1320        /// This always reduces the `bound` and there can not be any lower bound that is consistent
1321        /// with all indices stored in this `IdxBox`.
1322        pub fn truncate(&mut self) {
1323            let least_bound = HiddenMaxIndex::exclusive_upper_bound(&self.indices)
1324                // All mutation was performed under some concrete upper bound, and current elements
1325                // must still be bounded by the largest such bound.
1326                .expect("Some upper bound must still apply");
1327            debug_assert!(
1328                self.exact_size >= least_bound,
1329                "The exact size was corrupted to be below the least bound."
1330            );
1331            self.exact_size = least_bound;
1332        }
1333
1334        /// Reinterpret the contents as indices of a given tag.
1335        ///
1336        /// The given size must not be smaller than the `bound` of this allocated. This guarantees
1337        /// that all indices within the box are valid for the Tag. Since you can only _view_ the
1338        /// indices, they will remain valid.
1339        pub fn as_ref<T: Tag>(&self, size: Prefix<T>) -> Option<&'_ [Idx<I, T>]> {
1340            if size.get() >= self.exact_size {
1341                Some(unsafe {
1342                    // SAFETY: `Idx` is a transparent wrapper around `I`, the type of this slice,
1343                    // and the type `T` is a ZST. The instance `size.tag` also proves that this ZST
1344                    // is inhabited and it is Copy as per requirements of `Tag`. The index is
1345                    // smaller than the ExactSize corresponding to `T` by transitivity over `size`.
1346                    let content: *const [I] = &self.indices[..];
1347                    &*(content as *const [Idx<I, T>])
1348                })
1349            } else {
1350                None
1351            }
1352        }
1353
1354        /// Reinterpret the contents as mutable indices of a given tag.
1355        ///
1356        /// The given exact size must not be exactly the same as the `bound` of this allocated
1357        /// slice. This guarantees that all indices within the box are valid for the Tag, and that
1358        /// all stored indices will be valid for all future tags.
1359        pub fn as_mut<T: Tag>(&mut self, size: ExactSize<T>) -> Option<&'_ mut [Idx<I, T>]> {
1360            if size.get() == self.exact_size {
1361                Some(unsafe {
1362                    // SAFETY: `Idx` is a transparent wrapper around `I`, the type of this slice,
1363                    // and the type `T` is a ZST. The instance `size.tag` also proves that this ZST
1364                    // is inhabited and it is Copy as per requirements of `Tag`. The index is
1365                    // smaller than the ExactSize corresponding to `T` by transitivity over `size`.
1366                    // Also any instance written will be smaller than `self.exact_size`,
1367                    // guaranteeing that the invariants of this type hold afterwards.
1368                    let content: *mut [I] = &mut self.indices[..];
1369                    &mut *(content as *mut [Idx<I, T>])
1370                })
1371            } else {
1372                None
1373            }
1374        }
1375    }
1376}
1377
1378#[cfg(test)]
1379mod tests {
1380    use super::{with_ref, Constant, ConstantSource, Slice, TagEq, TagLessEq};
1381
1382    #[test]
1383    fn basics() {
1384        fn problematic(buf: &mut [u8], offsets: &[u8], idx: usize) {
1385            with_ref(&offsets[..=idx], |offsets, size| {
1386                let mut idx = size.into_len().index(idx).unwrap();
1387                for b in buf {
1388                    *b = idx.into_inner() as u8;
1389                    idx = idx.saturating_sub(usize::from(offsets[idx]));
1390                }
1391            })
1392        }
1393
1394        let mut output = [0; 3];
1395        let offsets = [1, 0, 2, 2];
1396        problematic(&mut output, &offsets[..], 3);
1397        assert_eq!(output, [3, 1, 1]);
1398    }
1399
1400    #[test]
1401    fn tag_switching() {
1402        struct ConstantLen;
1403        impl ConstantSource for ConstantLen {
1404            const LEN: usize = 4;
1405        }
1406
1407        let mut buffer = [0u8; 4];
1408        let csize = Constant::<ConstantLen>::EXACT_SIZE;
1409
1410        let slice = Slice::new_mut(&mut buffer[..], csize).unwrap();
1411        assert_eq!(slice.len(), ConstantLen::LEN);
1412        let all = csize.into_len().range_to_self();
1413
1414        with_ref(&buffer[..], |slice, size| {
1415            let lesseq = TagLessEq::with_sizes(size, csize).unwrap();
1416            let moreeq = TagLessEq::with_sizes(csize, size).unwrap();
1417            // 'prove': csize = size
1418            let eq = TagEq::new(lesseq, moreeq).transpose();
1419
1420            // Use this to transport the index.
1421            let all = all.with_tag(eq.into_le());
1422            let safe = slice.get_safe(all);
1423            assert_eq!(safe.len(), ConstantLen::LEN);
1424
1425            assert_eq!(csize.with_tag(eq).get(), csize.get());
1426        });
1427    }
1428
1429    #[test]
1430    fn bad_inequalities() {
1431        struct SmallLen;
1432        struct LargeLen;
1433        impl ConstantSource for SmallLen {
1434            const LEN: usize = 1;
1435        }
1436        impl ConstantSource for LargeLen {
1437            const LEN: usize = 2;
1438        }
1439
1440        let small = Constant::<SmallLen>::EXACT_SIZE;
1441        let large = Constant::<LargeLen>::EXACT_SIZE;
1442
1443        assert!(
1444            TagLessEq::with_pair(small.into_capacity(), large.into_len()).is_some(),
1445            "Small is in fact less than large"
1446        );
1447        assert!(
1448            TagLessEq::with_pair(large.into_capacity(), small.into_len()).is_none(),
1449            "Large should not appear less than small"
1450        );
1451    }
1452
1453    #[test]
1454    #[cfg(feature = "alloc")]
1455    fn idx_boxing() {
1456        use super::IdxBox;
1457        use alloc::boxed::Box;
1458
1459        struct ExactBound;
1460        struct LargerBound;
1461
1462        impl ConstantSource for ExactBound {
1463            const LEN: usize = 3;
1464        }
1465
1466        impl ConstantSource for LargerBound {
1467            const LEN: usize = 4;
1468        }
1469
1470        let indices = Box::from([0, 1, 2]);
1471
1472        let mut boxed = IdxBox::new(indices).expect("Have a valid upper bound");
1473        assert_eq!(boxed.bound(), <ExactBound as ConstantSource>::LEN);
1474
1475        let exact = Constant::<ExactBound>::EXACT_SIZE;
1476        boxed.as_ref(exact.into_len()).expect("A valid upper bound");
1477        let larger = Constant::<LargerBound>::EXACT_SIZE;
1478        boxed
1479            .as_ref(larger.into_len())
1480            .expect("A valid upper bound");
1481
1482        boxed.as_mut(exact).expect("A valid exact bound");
1483        assert!(boxed.as_mut(larger).is_none(), "An invalid exact bound");
1484
1485        // Now increase the bound
1486        boxed.ensure(larger.get());
1487        assert_eq!(boxed.bound(), <LargerBound as ConstantSource>::LEN);
1488        assert!(
1489            boxed.as_mut(exact).is_none(),
1490            "No longer a valid exact bound"
1491        );
1492        boxed.as_mut(larger).expect("Now a valid exact bound");
1493
1494        // But we've not _actually_ changed any index, so go back.
1495        boxed.truncate();
1496        assert_eq!(boxed.bound(), <ExactBound as ConstantSource>::LEN);
1497
1498        boxed.as_mut(exact).expect("A valid exact bound");
1499        assert!(boxed.as_mut(larger).is_none(), "An invalid exact bound");
1500    }
1501}
1502
1503/// assertion macros are due to (c) theInkSquid (foobles)
1504/// ```compile_fail
1505/// use index_ext::tag;
1506/// macro_rules! assert_is_covariant {
1507///     (for[$($gen_params:tt)*] ($type_name:ty) over $lf:lifetime) => {
1508///         #[allow(warnings)]
1509///         const _: fn() = || {
1510///             struct Cov<$lf, $($gen_params)*>($type_name);
1511///
1512///             fn test_cov<'__s, '__a: '__b, '__b, $($gen_params)*>(
1513///                 subtype: &'__s Cov<'__a, $($gen_params)*>,
1514///                 mut _supertype: &'__s Cov<'__b, $($gen_params)*>,
1515///             ) {
1516///                 _supertype = subtype;
1517///             }
1518///         };
1519///     };
1520///
1521///     (($type_name:ty) over $lf:lifetime) => {
1522///         assert_is_covariant!(for[] ($type_name) over $lf);
1523///     };
1524/// }
1525///
1526/// assert_is_covariant! {
1527///     (tag::Prefix<'r>) over 'r
1528/// }
1529/// ```
1530///
1531/// ```compile_fail
1532/// use index_ext::tag;
1533/// macro_rules! assert_is_contravariant {
1534///     (for[$($gen_params:tt)*] ($type_name:ty) over $lf:lifetime) => {
1535///         #[allow(warnings)]
1536///         const _: fn() = || {
1537///             struct Contra<$lf, $($gen_params)*>($type_name);
1538///
1539///             fn test_contra<'__s, '__a: '__b, '__b, $($gen_params)*>(
1540///                 mut _subtype: &'__s Contra<'__a, $($gen_params)*>,
1541///                 supertype: &'__s Contra<'__b, $($gen_params)*>,
1542///             ) {
1543///                 _subtype = supertype;
1544///             }
1545///         };
1546///     };
1547///
1548///     (($type_name:ty) over $lf:lifetime) => {
1549///         assert_is_contravariant!(for[] ($type_name) over $lf);
1550///     };
1551/// }
1552///
1553/// assert_is_contravariant! {
1554///     (tag::Prefix<'r>) over 'r
1555/// }
1556/// ```
1557#[cfg(doc)]
1558mod _doctests {}