bitvec/
domain.rs

1#![doc = include_str!("../doc/domain.md")]
2
3use core::{
4	any,
5	convert::{
6		TryFrom,
7		TryInto,
8	},
9	fmt::{
10		self,
11		Binary,
12		Debug,
13		Display,
14		Formatter,
15		LowerHex,
16		Octal,
17		UpperHex,
18	},
19	hash::{
20		Hash,
21		Hasher,
22	},
23	iter::FusedIterator,
24	marker::PhantomData,
25};
26
27use tap::{
28	Conv,
29	Pipe,
30	Tap,
31};
32use wyz::{
33	comu::{
34		Address,
35		Const,
36		Mut,
37		Mutability,
38		Reference,
39		Referential,
40		SliceReferential,
41	},
42	fmt::FmtForward,
43};
44
45use crate::{
46	access::BitAccess,
47	index::{
48		BitEnd,
49		BitIdx,
50		BitMask,
51	},
52	order::{
53		BitOrder,
54		Lsb0,
55	},
56	ptr::BitSpan,
57	slice::BitSlice,
58	store::BitStore,
59};
60
61#[doc = include_str!("../doc/domain/BitDomain.md")]
62pub enum BitDomain<'a, M = Const, T = usize, O = Lsb0>
63where
64	M: Mutability,
65	T: 'a + BitStore,
66	O: BitOrder,
67	Address<M, BitSlice<T, O>>: Referential<'a>,
68	Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
69{
70	/// Indicates that a bit-slice’s contents are entirely in the interior
71	/// indices of a single memory element.
72	///
73	/// The contained value is always the bit-slice that created this view.
74	Enclave(Reference<'a, M, BitSlice<T, O>>),
75	/// Indicates that a bit-slice’s contents touch an element edge.
76	///
77	/// This splits the bit-slice into three partitions, each of which may be
78	/// empty: two partially-occupied edge elements, with their original type
79	/// status, and one interior span, which is known to not have any other
80	/// aliases derived from the bit-slice that created this view.
81	Region {
82		/// Any bits that partially-fill the first element of the underlying
83		/// storage region.
84		///
85		/// This does not modify its aliasing status, as it will already be
86		/// appropriately marked before this view is constructed.
87		head: Reference<'a, M, BitSlice<T, O>>,
88		/// Any bits that wholly-fill elements in the interior of the bit-slice.
89		///
90		/// This is marked as unaliased, because it is statically impossible for
91		/// any other handle derived from the source bit-slice to have
92		/// conflicting access to the region of memory it describes. As such,
93		/// even a bit-slice that was marked as `::Alias` can revert this
94		/// protection on the known-unaliased interior.
95		///
96		/// Proofs:
97		///
98		/// - Rust’s `&`/`&mut` exclusion rules universally apply. If a
99		///   reference exists, no other reference has unsynchronized write
100		///   capability.
101		/// - `BitStore::Unalias` only modifies unsynchronized types. `Cell` and
102		///   atomic types unalias to themselves, and retain their original
103		///   behavior.
104		body: Reference<'a, M, BitSlice<T::Unalias, O>>,
105		/// Any bits that partially-fill the last element of the underlying
106		/// storage region.
107		///
108		/// This does not modify its aliasing status, as it will already be
109		/// appropriately marked before this view is constructed.
110		tail: Reference<'a, M, BitSlice<T, O>>,
111	},
112}
113
114impl<'a, M, T, O> BitDomain<'a, M, T, O>
115where
116	M: Mutability,
117	T: 'a + BitStore,
118	O: BitOrder,
119	Address<M, BitSlice<T, O>>: Referential<'a>,
120	Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
121{
122	/// Attempts to unpack the bit-domain as an [`Enclave`] variant. This is
123	/// just a shorthand for explicit destructuring.
124	///
125	/// [`Enclave`]: Self::Enclave
126	#[inline]
127	pub fn enclave(self) -> Option<Reference<'a, M, BitSlice<T, O>>> {
128		match self {
129			Self::Enclave(bits) => Some(bits),
130			_ => None,
131		}
132	}
133
134	/// Attempts to unpack the bit-domain as a [`Region`] variant. This is just
135	/// a shorthand for explicit destructuring.
136	///
137	/// [`Region`]: Self::Region
138	#[inline]
139	pub fn region(
140		self,
141	) -> Option<(
142		Reference<'a, M, BitSlice<T, O>>,
143		Reference<'a, M, BitSlice<T::Unalias, O>>,
144		Reference<'a, M, BitSlice<T, O>>,
145	)> {
146		match self {
147			Self::Region { head, body, tail } => Some((head, body, tail)),
148			_ => None,
149		}
150	}
151}
152
153impl<'a, M, T, O> Default for BitDomain<'a, M, T, O>
154where
155	M: Mutability,
156	T: 'a + BitStore,
157	O: BitOrder,
158	Address<M, BitSlice<T, O>>: Referential<'a>,
159	Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
160	Reference<'a, M, BitSlice<T, O>>: Default,
161	Reference<'a, M, BitSlice<T::Unalias, O>>: Default,
162{
163	#[inline]
164	fn default() -> Self {
165		Self::Region {
166			head: Default::default(),
167			body: Default::default(),
168			tail: Default::default(),
169		}
170	}
171}
172
173impl<'a, M, T, O> Debug for BitDomain<'a, M, T, O>
174where
175	M: Mutability,
176	T: 'a + BitStore,
177	O: BitOrder,
178	Address<M, BitSlice<T, O>>: Referential<'a>,
179	Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
180	Reference<'a, M, BitSlice<T, O>>: Debug,
181	Reference<'a, M, BitSlice<T::Unalias, O>>: Debug,
182{
183	#[inline]
184	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
185		write!(
186			fmt,
187			"BitDomain::<{} {}, {}>::",
188			M::RENDER,
189			any::type_name::<T::Mem>(),
190			any::type_name::<O>(),
191		)?;
192		match self {
193			Self::Enclave(elem) => {
194				fmt.debug_tuple("Enclave").field(elem).finish()
195			},
196			Self::Region { head, body, tail } => fmt
197				.debug_struct("Region")
198				.field("head", head)
199				.field("body", body)
200				.field("tail", tail)
201				.finish(),
202		}
203	}
204}
205
206#[cfg(not(tarpaulin_include))]
207impl<T, O> Clone for BitDomain<'_, Const, T, O>
208where
209	T: BitStore,
210	O: BitOrder,
211{
212	#[inline]
213	fn clone(&self) -> Self {
214		*self
215	}
216}
217
218impl<T, O> Copy for BitDomain<'_, Const, T, O>
219where
220	T: BitStore,
221	O: BitOrder,
222{
223}
224
225#[doc = include_str!("../doc/domain/Domain.md")]
226pub enum Domain<'a, M = Const, T = usize, O = Lsb0>
227where
228	M: Mutability,
229	T: 'a + BitStore,
230	O: BitOrder,
231	Address<M, T>: Referential<'a>,
232	Address<M, [T::Unalias]>: SliceReferential<'a>,
233{
234	/// Indicates that a bit-slice’s contents are entirely in the interior
235	/// indices of a single memory element.
236	///
237	/// The contained reference is only able to observe the bits governed by the
238	/// generating bit-slice. Other handles to the element may exist, and may
239	/// write to bits outside the range that this reference can observe.
240	Enclave(PartialElement<'a, M, T, O>),
241	/// Indicates that a bit-slice’s contents touch an element edge.
242	///
243	/// This splits the bit-slice into three partitions, each of which may be
244	/// empty: two partially-occupied edge elements, with their original type
245	/// status, and one interior span, which is known not to have any other
246	/// aliases derived from the bit-slice that created this view.
247	Region {
248		/// The first element in the bit-slice’s underlying storage, if it is
249		/// only partially used.
250		head: Option<PartialElement<'a, M, T, O>>,
251		/// All fully-used elements in the bit-slice’s underlying storage.
252		///
253		/// This is marked as unaliased, because it is statically impossible for
254		/// any other handle derived from the source bit-slice to have
255		/// conflicting access to the region of memory it describes. As such,
256		/// even a bit-slice that was marked as `::Alias` can revert this
257		/// protection on the known-unaliased interior.
258		body: Reference<'a, M, [T::Unalias]>,
259		/// The last element in the bit-slice’s underlying storage, if it is
260		/// only partially used.
261		tail: Option<PartialElement<'a, M, T, O>>,
262	},
263}
264
265impl<'a, M, T, O> Domain<'a, M, T, O>
266where
267	M: Mutability,
268	T: 'a + BitStore,
269	O: BitOrder,
270	Address<M, T>: Referential<'a>,
271	Address<M, [T::Unalias]>: SliceReferential<'a>,
272{
273	/// Attempts to unpack the bit-domain as an [`Enclave`] variant. This is
274	/// just a shorthand for explicit destructuring.
275	///
276	/// [`Enclave`]: Self::Enclave
277	#[inline]
278	pub fn enclave(self) -> Option<PartialElement<'a, M, T, O>> {
279		match self {
280			Self::Enclave(elem) => Some(elem),
281			_ => None,
282		}
283	}
284
285	/// Attempts to unpack the bit-domain as a [`Region`] variant. This is just
286	/// a shorthand for explicit destructuring.
287	///
288	/// [`Region`]: Self::Region
289	#[inline]
290	pub fn region(
291		self,
292	) -> Option<(
293		Option<PartialElement<'a, M, T, O>>,
294		Reference<'a, M, [T::Unalias]>,
295		Option<PartialElement<'a, M, T, O>>,
296	)> {
297		match self {
298			Self::Region { head, body, tail } => Some((head, body, tail)),
299			_ => None,
300		}
301	}
302
303	/// Converts the element-wise `Domain` into the equivalent `BitDomain`.
304	///
305	/// This transform replaces each memory reference with an equivalent
306	/// `BitSlice` reference.
307	#[inline]
308	pub fn into_bit_domain(self) -> BitDomain<'a, M, T, O>
309	where
310		Address<M, BitSlice<T, O>>: Referential<'a>,
311		Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
312		Reference<'a, M, BitSlice<T, O>>: Default,
313		Reference<'a, M, BitSlice<T::Unalias, O>>:
314			TryFrom<Reference<'a, M, [T::Unalias]>>,
315	{
316		match self {
317			Self::Enclave(elem) => BitDomain::Enclave(elem.into_bitslice()),
318			Self::Region { head, body, tail } => BitDomain::Region {
319				head: head.map_or_else(
320					Default::default,
321					PartialElement::into_bitslice,
322				),
323				body: body.try_into().unwrap_or_else(|_| {
324					match option_env!("CARGO_PKG_REPOSITORY") {
325						Some(env) => unreachable!(
326							"Construction of a slice with length {} should not \
327							 be possible. If this assumption is outdated, \
328							 please file an issue at {}",
329							(isize::MIN as usize) >> 3,
330							env,
331						),
332						None => unreachable!(
333							"Construction of a slice with length {} should not \
334							 be possible. If this assumption is outdated, \
335							 please consider filing an issue",
336							(isize::MIN as usize) >> 3
337						),
338					}
339				}),
340				tail: tail.map_or_else(
341					Default::default,
342					PartialElement::into_bitslice,
343				),
344			},
345		}
346	}
347}
348
349/** Domain constructors.
350
351Only `Domain<Const>` and `Domain<Mut>` are ever constructed, and they of course
352are only constructed from `&BitSlice` and `&mut BitSlice`, respectively.
353
354However, the Rust trait system does not have a way to express a closed set, so
355**/
356impl<'a, M, T, O> Domain<'a, M, T, O>
357where
358	M: Mutability,
359	T: 'a + BitStore,
360	O: BitOrder,
361	Address<M, T>: Referential<'a>,
362	Address<M, [T::Unalias]>:
363		SliceReferential<'a, ElementAddr = Address<M, T::Unalias>>,
364	Address<M, BitSlice<T, O>>: Referential<'a>,
365	Reference<'a, M, [T::Unalias]>: Default,
366{
367	/// Creates a new `Domain` over a bit-slice.
368	///
369	/// ## Parameters
370	///
371	/// - `bits`: Either a `&BitSlice` or `&mut BitSlice` reference, depending
372	///   on whether a `Domain<Const>` or `Domain<Mut>` is being produced.
373	///
374	/// ## Returns
375	///
376	/// A `Domain` description of the raw memory governed by `bits`.
377	pub(crate) fn new(bits: Reference<'a, M, BitSlice<T, O>>) -> Self
378	where BitSpan<M, T, O>: From<Reference<'a, M, BitSlice<T, O>>> {
379		let bitspan = bits.conv::<BitSpan<M, T, O>>();
380		let (head, elts, tail) =
381			(bitspan.head(), bitspan.elements(), bitspan.tail());
382		let base = bitspan.address();
383		let (min, max) = (BitIdx::<T::Mem>::MIN, BitEnd::<T::Mem>::MAX);
384		let ctor = match (head, elts, tail) {
385			(_, 0, _) => Self::empty,
386			(h, _, t) if h == min && t == max => Self::spanning,
387			(_, _, t) if t == max => Self::partial_head,
388			(h, ..) if h == min => Self::partial_tail,
389			(_, 1, _) => Self::minor,
390			_ => Self::major,
391		};
392		ctor(base, elts, head, tail)
393	}
394
395	/// Produces the canonical empty `Domain`.
396	#[inline]
397	fn empty(
398		_: Address<M, T>,
399		_: usize,
400		_: BitIdx<T::Mem>,
401		_: BitEnd<T::Mem>,
402	) -> Self {
403		Default::default()
404	}
405
406	/// Produces a `Domain::Region` that contains both `head` and `tail` partial
407	/// elements as well as a `body` slice (which may be empty).
408	#[inline]
409	fn major(
410		addr: Address<M, T>,
411		elts: usize,
412		head: BitIdx<T::Mem>,
413		tail: BitEnd<T::Mem>,
414	) -> Self {
415		let h_elem = addr;
416		let t_elem = unsafe { addr.add(elts - 1) };
417		let body = unsafe {
418			Address::<M, [T::Unalias]>::from_raw_parts(
419				addr.add(1).cast::<T::Unalias>(),
420				elts - 2,
421			)
422		};
423		Self::Region {
424			head: Some(PartialElement::new(h_elem, head, None)),
425			body,
426			tail: Some(PartialElement::new(t_elem, None, tail)),
427		}
428	}
429
430	/// Produces a `Domain::Enclave`.
431	#[inline]
432	fn minor(
433		addr: Address<M, T>,
434		_: usize,
435		head: BitIdx<T::Mem>,
436		tail: BitEnd<T::Mem>,
437	) -> Self {
438		let elem = addr;
439		Self::Enclave(PartialElement::new(elem, head, tail))
440	}
441
442	/// Produces a `Domain::Region` with a partial `head` and a `body`, but no
443	/// `tail`.
444	#[inline]
445	fn partial_head(
446		addr: Address<M, T>,
447		elts: usize,
448		head: BitIdx<T::Mem>,
449		_: BitEnd<T::Mem>,
450	) -> Self {
451		let elem = addr;
452		let body = unsafe {
453			Address::<M, [T::Unalias]>::from_raw_parts(
454				addr.add(1).cast::<T::Unalias>(),
455				elts - 1,
456			)
457		};
458		Self::Region {
459			head: Some(PartialElement::new(elem, head, None)),
460			body,
461			tail: None,
462		}
463	}
464
465	/// Produces a `Domain::Region` with a partial `tail` and a `body`, but no
466	/// `head`.
467	#[inline]
468	fn partial_tail(
469		addr: Address<M, T>,
470		elts: usize,
471		_: BitIdx<T::Mem>,
472		tail: BitEnd<T::Mem>,
473	) -> Self {
474		let elem = unsafe { addr.add(elts - 1) };
475		let body = unsafe {
476			Address::<M, [T::Unalias]>::from_raw_parts(
477				addr.cast::<T::Unalias>(),
478				elts - 1,
479			)
480		};
481		Self::Region {
482			head: None,
483			body,
484			tail: Some(PartialElement::new(elem, None, tail)),
485		}
486	}
487
488	/// Produces a `Domain::Region` with neither `head` nor `tail`, but only a
489	/// `body`.
490	#[inline]
491	fn spanning(
492		addr: Address<M, T>,
493		elts: usize,
494		_: BitIdx<T::Mem>,
495		_: BitEnd<T::Mem>,
496	) -> Self {
497		Self::Region {
498			head: None,
499			body: unsafe {
500				<Address<M, [T::Unalias]> as SliceReferential>::from_raw_parts(
501					addr.cast::<T::Unalias>(),
502					elts,
503				)
504			},
505			tail: None,
506		}
507	}
508}
509
510impl<'a, M, T, O> Default for Domain<'a, M, T, O>
511where
512	M: Mutability,
513	T: 'a + BitStore,
514	O: BitOrder,
515	Address<M, T>: Referential<'a>,
516	Address<M, [T::Unalias]>: SliceReferential<'a>,
517	Reference<'a, M, [T::Unalias]>: Default,
518{
519	#[inline]
520	fn default() -> Self {
521		Self::Region {
522			head: None,
523			body: Reference::<M, [T::Unalias]>::default(),
524			tail: None,
525		}
526	}
527}
528
529impl<'a, M, T, O> Debug for Domain<'a, M, T, O>
530where
531	M: Mutability,
532	T: 'a + BitStore,
533	O: BitOrder,
534	Address<M, T>: Referential<'a>,
535	Address<M, [T::Unalias]>: SliceReferential<'a>,
536	Reference<'a, M, [T::Unalias]>: Debug,
537{
538	#[inline]
539	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
540		write!(
541			fmt,
542			"Domain::<{} {}, {}>::",
543			M::RENDER,
544			any::type_name::<T>(),
545			any::type_name::<O>(),
546		)?;
547		match self {
548			Self::Enclave(elem) => {
549				fmt.debug_tuple("Enclave").field(elem).finish()
550			},
551			Self::Region { head, body, tail } => fmt
552				.debug_struct("Region")
553				.field("head", head)
554				.field("body", body)
555				.field("tail", tail)
556				.finish(),
557		}
558	}
559}
560
561#[cfg(not(tarpaulin_include))]
562impl<T, O> Clone for Domain<'_, Const, T, O>
563where
564	T: BitStore,
565	O: BitOrder,
566{
567	#[inline]
568	fn clone(&self) -> Self {
569		*self
570	}
571}
572
573impl<T, O> Iterator for Domain<'_, Const, T, O>
574where
575	T: BitStore,
576	O: BitOrder,
577{
578	type Item = T::Mem;
579
580	#[inline]
581	fn next(&mut self) -> Option<Self::Item> {
582		match self {
583			Self::Enclave(elem) => {
584				elem.load_value().tap(|_| *self = Default::default()).into()
585			},
586			Self::Region { head, body, tail } => {
587				if let Some(elem) = head.take() {
588					return elem.load_value().into();
589				}
590				if let Some((elem, rest)) = body.split_first() {
591					*body = rest;
592					return elem.load_value().into();
593				}
594				if let Some(elem) = tail.take() {
595					return elem.load_value().into();
596				}
597				None
598			},
599		}
600	}
601}
602
603impl<T, O> DoubleEndedIterator for Domain<'_, Const, T, O>
604where
605	T: BitStore,
606	O: BitOrder,
607{
608	#[inline]
609	fn next_back(&mut self) -> Option<Self::Item> {
610		match self {
611			Self::Enclave(elem) => {
612				elem.load_value().tap(|_| *self = Default::default()).into()
613			},
614			Self::Region { head, body, tail } => {
615				if let Some(elem) = tail.take() {
616					return elem.load_value().into();
617				}
618				if let Some((elem, rest)) = body.split_last() {
619					*body = rest;
620					return elem.load_value().into();
621				}
622				if let Some(elem) = head.take() {
623					return elem.load_value().into();
624				}
625				None
626			},
627		}
628	}
629}
630
631impl<T, O> ExactSizeIterator for Domain<'_, Const, T, O>
632where
633	T: BitStore,
634	O: BitOrder,
635{
636	#[inline]
637	fn len(&self) -> usize {
638		match self {
639			Self::Enclave(_) => 1,
640			Self::Region { head, body, tail } => {
641				head.is_some() as usize + body.len() + tail.is_some() as usize
642			},
643		}
644	}
645}
646
647impl<T, O> FusedIterator for Domain<'_, Const, T, O>
648where
649	T: BitStore,
650	O: BitOrder,
651{
652}
653
654impl<T, O> Copy for Domain<'_, Const, T, O>
655where
656	T: BitStore,
657	O: BitOrder,
658{
659}
660
661/// Implements numeric formatting by rendering each element.
662macro_rules! fmt {
663	($($fmt:ty => $fwd:ident),+ $(,)?) => { $(
664		impl<'a, T, O> $fmt for Domain<'a, Const, T, O>
665		where
666			O: BitOrder,
667			T: BitStore,
668		{
669			#[inline]
670			fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
671				fmt.debug_list()
672					.entries(self.into_iter().map(FmtForward::$fwd))
673					.finish()
674			}
675		}
676	)+ };
677}
678
679fmt! {
680	Binary => fmt_binary,
681	Display => fmt_display,
682	LowerHex => fmt_lower_hex,
683	Octal => fmt_octal,
684	UpperHex => fmt_upper_hex,
685}
686
687#[doc = include_str!("../doc/domain/PartialElement.md")]
688pub struct PartialElement<'a, M, T, O>
689where
690	M: Mutability,
691	T: 'a + BitStore,
692	O: BitOrder,
693{
694	/// The address of the memory element being partially viewed.
695	///
696	/// This must be stored as a pointer, not a reference, because it must
697	/// retain mutability permissions but cannot have an `&mut` reference to
698	/// a shared element.
699	///
700	/// Similarly, it must remain typed as `T`, not `T::Access`, to allow the
701	/// `<Const, uN>` case not to inappropriately produce a `<Const, Cell<uN>>`
702	/// even if no write is performed.
703	elem: Address<M, T>,
704	/// Cache the selector mask, so it never needs to be recomputed.
705	mask: BitMask<T::Mem>,
706	/// The starting index.
707	head: BitIdx<T::Mem>,
708	/// The ending index.
709	tail: BitEnd<T::Mem>,
710	/// Preserve the originating bit-order
711	_ord: PhantomData<O>,
712	/// This type acts as-if it were a shared-mutable reference.
713	_ref: PhantomData<&'a T::Access>,
714}
715
716impl<'a, M, T, O> PartialElement<'a, M, T, O>
717where
718	M: Mutability,
719	T: 'a + BitStore,
720	O: BitOrder,
721{
722	/// Constructs a new partial-element guarded reference.
723	///
724	/// ## Parameters
725	///
726	/// - `elem`: the element to which this partially points.
727	/// - `head`: the index at which the partial region begins.
728	/// - `tail`: the index at which the partial region ends.
729	#[inline]
730	fn new(
731		elem: Address<M, T>,
732		head: impl Into<Option<BitIdx<T::Mem>>>,
733		tail: impl Into<Option<BitEnd<T::Mem>>>,
734	) -> Self {
735		let (head, tail) = (
736			head.into().unwrap_or(BitIdx::MIN),
737			tail.into().unwrap_or(BitEnd::MAX),
738		);
739		Self {
740			elem,
741			mask: O::mask(head, tail),
742			head,
743			tail,
744			_ord: PhantomData,
745			_ref: PhantomData,
746		}
747	}
748
749	/// Fetches the value stored through `self` and masks away extra bits.
750	///
751	/// ## Returns
752	///
753	/// A bit-map containing any bits set to `1` in the governed bits. All other
754	/// bits are cleared to `0`.
755	#[inline]
756	pub fn load_value(&self) -> T::Mem {
757		self.elem
758			.pipe(|addr| unsafe { &*addr.to_const() })
759			.load_value()
760			& self.mask.into_inner()
761	}
762
763	/// Gets the starting index of the live bits in the element.
764	#[inline]
765	#[cfg(not(tarpaulin_include))]
766	pub fn head(&self) -> BitIdx<T::Mem> {
767		self.head
768	}
769
770	/// Gets the ending index of the live bits in the element.
771	#[inline]
772	#[cfg(not(tarpaulin_include))]
773	pub fn tail(&self) -> BitEnd<T::Mem> {
774		self.tail
775	}
776
777	/// Gets the semantic head and tail indices that constrain which bits of the
778	/// referent element may be accessed.
779	#[inline]
780	#[cfg(not(tarpaulin_include))]
781	pub fn bounds(&self) -> (BitIdx<T::Mem>, BitEnd<T::Mem>) {
782		(self.head, self.tail)
783	}
784
785	/// Gets the bit-mask over all accessible bits.
786	#[inline]
787	#[cfg(not(tarpaulin_include))]
788	pub fn mask(&self) -> BitMask<T::Mem> {
789		self.mask
790	}
791
792	/// Converts the partial element into a bit-slice over its governed bits.
793	#[inline]
794	pub fn into_bitslice(self) -> Reference<'a, M, BitSlice<T, O>>
795	where Address<M, BitSlice<T, O>>: Referential<'a> {
796		unsafe {
797			BitSpan::new_unchecked(
798				self.elem,
799				self.head,
800				(self.tail.into_inner() - self.head.into_inner()) as usize,
801			)
802		}
803		.to_bitslice()
804	}
805}
806
807impl<'a, T, O> PartialElement<'a, Mut, T, O>
808where
809	T: BitStore,
810	O: BitOrder,
811	Address<Mut, T>: Referential<'a>,
812{
813	/// Stores a value through `self` after masking away extra bits.
814	///
815	/// ## Parameters
816	///
817	/// - `&mut self`
818	/// - `value`: A bit-map which will be written into the governed bits. This
819	///   is a bit-map store, not an integer store; the value will not be
820	///   shifted into position and will only be masked directly against the
821	///   bits that this partial-element governs.
822	///
823	/// ## Returns
824	///
825	/// The previous value of the governed bits.
826	#[inline]
827	pub fn store_value(&mut self, value: T::Mem) -> T::Mem {
828		let this = self.access();
829		let prev = this.clear_bits(self.mask);
830		this.set_bits(self.mask & value);
831		prev & self.mask.into_inner()
832	}
833
834	/// Inverts the value of each bit governed by the partial-element.
835	///
836	/// ## Returns
837	///
838	/// The previous value of the governed bits.
839	#[inline]
840	#[cfg(not(tarpaulin_include))]
841	pub fn invert(&mut self) -> T::Mem {
842		self.access().invert_bits(self.mask) & self.mask.into_inner()
843	}
844
845	/// Clears all bits governed by the partial-element to `0`.
846	///
847	/// ## Returns
848	///
849	/// The previous value of the governed bits.
850	#[inline]
851	#[cfg(not(tarpaulin_include))]
852	pub fn clear(&mut self) -> T::Mem {
853		self.access().clear_bits(self.mask) & self.mask.into_inner()
854	}
855
856	/// Sets all bits governed by the partial-element to `1`.
857	///
858	/// ## Returns
859	///
860	/// The previous value of the governed bits.
861	#[inline]
862	#[cfg(not(tarpaulin_include))]
863	pub fn set(&mut self) -> T::Mem {
864		self.access().set_bits(self.mask) & self.mask.into_inner()
865	}
866
867	/// Produces a reference capable of tolerating other handles viewing the
868	/// same *memory element*.
869	#[inline]
870	fn access(&self) -> &T::Access {
871		unsafe { &*self.elem.to_const().cast::<T::Access>() }
872	}
873}
874
875impl<'a, M, T, O> PartialElement<'a, M, T, O>
876where
877	M: Mutability,
878	O: BitOrder,
879	T: 'a + BitStore + radium::Radium,
880{
881	/// Performs a store operation on a partial-element whose bits might be
882	/// observed by another handle.
883	#[inline]
884	pub fn store_value_aliased(&self, value: T::Mem) -> T::Mem {
885		let this = unsafe { &*self.elem.to_const().cast::<T::Access>() };
886		let prev = this.clear_bits(self.mask);
887		this.set_bits(self.mask & value);
888		prev & self.mask.into_inner()
889	}
890}
891
892#[cfg(not(tarpaulin_include))]
893impl<'a, T, O> Clone for PartialElement<'a, Const, T, O>
894where
895	T: BitStore,
896	O: BitOrder,
897	Address<Const, T>: Referential<'a>,
898{
899	#[inline]
900	fn clone(&self) -> Self {
901		*self
902	}
903}
904
905impl<'a, M, T, O> Debug for PartialElement<'a, M, T, O>
906where
907	M: Mutability,
908	T: 'a + BitStore,
909	O: BitOrder,
910{
911	#[inline]
912	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
913		write!(
914			fmt,
915			"PartialElement<{} {}, {}>",
916			M::RENDER,
917			any::type_name::<T>(),
918			any::type_name::<O>(),
919		)?;
920		fmt.debug_struct("")
921			.field("elem", &self.load_value())
922			.field("mask", &self.mask.fmt_display())
923			.field("head", &self.head.fmt_display())
924			.field("tail", &self.tail.fmt_display())
925			.finish()
926	}
927}
928
929#[cfg(not(tarpaulin_include))]
930impl<'a, M, T, O> Hash for PartialElement<'a, M, T, O>
931where
932	M: Mutability,
933	T: 'a + BitStore,
934	O: BitOrder,
935{
936	#[inline]
937	fn hash<H>(&self, hasher: &mut H)
938	where H: Hasher {
939		self.load_value().hash(hasher);
940		self.mask.hash(hasher);
941		self.head.hash(hasher);
942		self.tail.hash(hasher);
943	}
944}
945
946impl<T, O> Copy for PartialElement<'_, Const, T, O>
947where
948	T: BitStore,
949	O: BitOrder,
950{
951}
952
953#[cfg(test)]
954mod tests {
955	use rand::random;
956
957	use super::*;
958	use crate::prelude::*;
959
960	#[test]
961	fn bit_domain() {
962		let data = BitArray::<[u32; 3], Msb0>::new(random());
963
964		let bd = data.bit_domain();
965		assert!(bd.enclave().is_none());
966		let (head, body, tail) = bd.region().unwrap();
967		assert_eq!(data, body);
968		assert!(head.is_empty());
969		assert!(tail.is_empty());
970
971		let bd = data[2 ..].bit_domain();
972		let (head, body, tail) = bd.region().unwrap();
973		assert_eq!(head, &data[2 .. 32]);
974		assert_eq!(body, &data[32 ..]);
975		assert!(tail.is_empty());
976
977		let bd = data[.. 94].bit_domain();
978		let (head, body, tail) = bd.region().unwrap();
979		assert!(head.is_empty());
980		assert_eq!(body, &data[.. 64]);
981		assert_eq!(tail, &data[64 .. 94]);
982
983		let bd = data[2 .. 94].bit_domain();
984		let (head, body, tail) = bd.region().unwrap();
985		assert_eq!(head, &data[2 .. 32]);
986		assert_eq!(body, &data[32 .. 64]);
987		assert_eq!(tail, &data[64 .. 94]);
988
989		let bd = data[34 .. 62].bit_domain();
990		assert!(bd.region().is_none());
991		assert_eq!(bd.enclave().unwrap(), data[34 .. 62]);
992
993		let (head, body, tail) =
994			BitDomain::<Const, usize, Lsb0>::default().region().unwrap();
995		assert!(head.is_empty());
996		assert!(body.is_empty());
997		assert!(tail.is_empty());
998	}
999
1000	#[test]
1001	fn domain() {
1002		let data: [u32; 3] = random();
1003		let bits = data.view_bits::<Msb0>();
1004
1005		let d = bits.domain();
1006		assert!(d.enclave().is_none());
1007		let (head, body, tail) = d.region().unwrap();
1008		assert!(head.is_none());
1009		assert!(tail.is_none());
1010		assert_eq!(body, data);
1011
1012		let d = bits[2 ..].domain();
1013		let (head, body, tail) = d.region().unwrap();
1014		assert_eq!(head.unwrap().load_value(), (data[0] << 2) >> 2);
1015		assert_eq!(body, &data[1 ..]);
1016		assert!(tail.is_none());
1017
1018		let d = bits[.. 94].domain();
1019		let (head, body, tail) = d.region().unwrap();
1020		assert!(head.is_none());
1021		assert_eq!(body, &data[.. 2]);
1022		assert_eq!(tail.unwrap().load_value(), (data[2] >> 2) << 2);
1023
1024		let d = bits[2 .. 94].domain();
1025		let (head, body, tail) = d.region().unwrap();
1026		assert_eq!(head.unwrap().load_value(), (data[0] << 2) >> 2);
1027		assert_eq!(body, &data[1 .. 2]);
1028		assert_eq!(tail.unwrap().load_value(), (data[2] >> 2) << 2);
1029
1030		let d = bits[34 .. 62].domain();
1031		assert!(d.region().is_none());
1032		assert_eq!(
1033			d.enclave().unwrap().load_value(),
1034			((data[1] << 2) >> 4) << 2,
1035		);
1036
1037		assert!(matches!(bits![].domain(), Domain::Region {
1038			head: None,
1039			body: &[],
1040			tail: None,
1041		}));
1042
1043		assert!(matches!(
1044			Domain::<Const, usize, Lsb0>::default(),
1045			Domain::Region {
1046				head: None,
1047				body: &[],
1048				tail: None,
1049			},
1050		));
1051
1052		let data = core::cell::Cell::new(0u8);
1053		let partial =
1054			data.view_bits::<Lsb0>()[2 .. 6].domain().enclave().unwrap();
1055		assert_eq!(partial.store_value_aliased(!0), 0);
1056		assert_eq!(data.get(), 0b00_1111_00);
1057	}
1058
1059	#[test]
1060	fn iter() {
1061		let bits = [0x12u8, 0x34, 0x56].view_bits::<Lsb0>();
1062		let mut domain = bits[4 .. 12].domain();
1063		assert_eq!(domain.len(), 2);
1064		assert_eq!(domain.next().unwrap(), 0x10);
1065		assert_eq!(domain.next_back().unwrap(), 0x04);
1066
1067		assert!(domain.next().is_none());
1068		assert!(domain.next_back().is_none());
1069
1070		assert_eq!(bits[2 .. 6].domain().len(), 1);
1071		assert_eq!(bits[18 .. 22].domain().next_back().unwrap(), 0b00_0101_00);
1072
1073		let mut domain = bits[4 .. 20].domain();
1074		assert_eq!(domain.next_back().unwrap(), 0x06);
1075		assert_eq!(domain.next_back().unwrap(), 0x34);
1076		assert_eq!(domain.next_back().unwrap(), 0x10);
1077	}
1078
1079	#[test]
1080	#[cfg(feature = "alloc")]
1081	fn render() {
1082		#[cfg(not(feature = "std"))]
1083		use alloc::format;
1084
1085		let data = BitArray::<u32, Msb0>::new(random());
1086
1087		let render = format!("{:?}", data.bit_domain());
1088		let expected = format!(
1089			"BitDomain::<*const u32, {}>::Region {{ head: {:?}, body: {:?}, \
1090			 tail: {:?} }}",
1091			any::type_name::<Msb0>(),
1092			BitSlice::<u32, Msb0>::empty(),
1093			data.as_bitslice(),
1094			BitSlice::<u32, Msb0>::empty(),
1095		);
1096		assert_eq!(render, expected);
1097
1098		let render = format!("{:?}", data[2 .. 30].bit_domain());
1099		let expected = format!(
1100			"BitDomain::<*const u32, {}>::Enclave({:?})",
1101			any::type_name::<Msb0>(),
1102			&data[2 .. 30],
1103		);
1104		assert_eq!(render, expected);
1105
1106		let render = format!("{:?}", data.domain());
1107		let expected = format!(
1108			"Domain::<*const u32, {}>::Region {{ head: None, body: {:?}, tail: \
1109			 None }}",
1110			any::type_name::<Msb0>(),
1111			data.as_raw_slice(),
1112		);
1113		assert_eq!(render, expected);
1114
1115		let render = format!("{:?}", data[2 .. 30].domain());
1116		let expected = format!(
1117			"Domain::<*const u32, {}>::Enclave",
1118			any::type_name::<Msb0>(),
1119		);
1120		assert!(render.starts_with(&expected));
1121
1122		let partial = 0x3Cu8.view_bits::<Lsb0>()[2 .. 6]
1123			.domain()
1124			.enclave()
1125			.unwrap();
1126		let render = format!("{:?}", partial);
1127		assert_eq!(
1128			render,
1129			format!(
1130				"PartialElement<*const u8, {}> {{ elem: 60, mask: {}, head: \
1131				 {}, tail: {} }}",
1132				any::type_name::<Lsb0>(),
1133				partial.mask,
1134				partial.head,
1135				partial.tail,
1136			),
1137		);
1138	}
1139}