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 {}