Skip to main content

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
355this has to be spelled out explicitly in the trait bounds.
356**/
357impl<'a, M, T, O> Domain<'a, M, T, O>
358where
359	M: Mutability,
360	T: 'a + BitStore,
361	O: BitOrder,
362	Address<M, T>: Referential<'a>,
363	Address<M, [T::Unalias]>:
364		SliceReferential<'a, ElementAddr = Address<M, T::Unalias>>,
365	Address<M, BitSlice<T, O>>: Referential<'a>,
366	Reference<'a, M, [T::Unalias]>: Default,
367{
368	/// Creates a new `Domain` over a bit-slice.
369	///
370	/// ## Parameters
371	///
372	/// - `bits`: Either a `&BitSlice` or `&mut BitSlice` reference, depending
373	///   on whether a `Domain<Const>` or `Domain<Mut>` is being produced.
374	///
375	/// ## Returns
376	///
377	/// A `Domain` description of the raw memory governed by `bits`.
378	pub(crate) fn new(bits: Reference<'a, M, BitSlice<T, O>>) -> Self
379	where BitSpan<M, T, O>: From<Reference<'a, M, BitSlice<T, O>>> {
380		let bitspan = bits.conv::<BitSpan<M, T, O>>();
381		let (head, elts, tail) =
382			(bitspan.head(), bitspan.elements(), bitspan.tail());
383		let base = bitspan.address();
384		let (min, max) = (BitIdx::<T::Mem>::MIN, BitEnd::<T::Mem>::MAX);
385		let ctor = match (head, elts, tail) {
386			(_, 0, _) => Self::empty,
387			(h, _, t) if h == min && t == max => Self::spanning,
388			(_, _, t) if t == max => Self::partial_head,
389			(h, ..) if h == min => Self::partial_tail,
390			(_, 1, _) => Self::minor,
391			_ => Self::major,
392		};
393		ctor(base, elts, head, tail)
394	}
395
396	/// Produces the canonical empty `Domain`.
397	#[inline]
398	fn empty(
399		_: Address<M, T>,
400		_: usize,
401		_: BitIdx<T::Mem>,
402		_: BitEnd<T::Mem>,
403	) -> Self {
404		Default::default()
405	}
406
407	/// Produces a `Domain::Region` that contains both `head` and `tail` partial
408	/// elements as well as a `body` slice (which may be empty).
409	#[inline]
410	fn major(
411		addr: Address<M, T>,
412		elts: usize,
413		head: BitIdx<T::Mem>,
414		tail: BitEnd<T::Mem>,
415	) -> Self {
416		let h_elem = addr;
417		let t_elem = unsafe { addr.add(elts - 1) };
418		let body = unsafe {
419			Address::<M, [T::Unalias]>::from_raw_parts(
420				addr.add(1).cast::<T::Unalias>(),
421				elts - 2,
422			)
423		};
424		Self::Region {
425			head: Some(PartialElement::new(h_elem, head, None)),
426			body,
427			tail: Some(PartialElement::new(t_elem, None, tail)),
428		}
429	}
430
431	/// Produces a `Domain::Enclave`.
432	#[inline]
433	fn minor(
434		addr: Address<M, T>,
435		_: usize,
436		head: BitIdx<T::Mem>,
437		tail: BitEnd<T::Mem>,
438	) -> Self {
439		let elem = addr;
440		Self::Enclave(PartialElement::new(elem, head, tail))
441	}
442
443	/// Produces a `Domain::Region` with a partial `head` and a `body`, but no
444	/// `tail`.
445	#[inline]
446	fn partial_head(
447		addr: Address<M, T>,
448		elts: usize,
449		head: BitIdx<T::Mem>,
450		_: BitEnd<T::Mem>,
451	) -> Self {
452		let elem = addr;
453		let body = unsafe {
454			Address::<M, [T::Unalias]>::from_raw_parts(
455				addr.add(1).cast::<T::Unalias>(),
456				elts - 1,
457			)
458		};
459		Self::Region {
460			head: Some(PartialElement::new(elem, head, None)),
461			body,
462			tail: None,
463		}
464	}
465
466	/// Produces a `Domain::Region` with a partial `tail` and a `body`, but no
467	/// `head`.
468	#[inline]
469	fn partial_tail(
470		addr: Address<M, T>,
471		elts: usize,
472		_: BitIdx<T::Mem>,
473		tail: BitEnd<T::Mem>,
474	) -> Self {
475		let elem = unsafe { addr.add(elts - 1) };
476		let body = unsafe {
477			Address::<M, [T::Unalias]>::from_raw_parts(
478				addr.cast::<T::Unalias>(),
479				elts - 1,
480			)
481		};
482		Self::Region {
483			head: None,
484			body,
485			tail: Some(PartialElement::new(elem, None, tail)),
486		}
487	}
488
489	/// Produces a `Domain::Region` with neither `head` nor `tail`, but only a
490	/// `body`.
491	#[inline]
492	fn spanning(
493		addr: Address<M, T>,
494		elts: usize,
495		_: BitIdx<T::Mem>,
496		_: BitEnd<T::Mem>,
497	) -> Self {
498		Self::Region {
499			head: None,
500			body: unsafe {
501				<Address<M, [T::Unalias]> as SliceReferential>::from_raw_parts(
502					addr.cast::<T::Unalias>(),
503					elts,
504				)
505			},
506			tail: None,
507		}
508	}
509}
510
511impl<'a, M, T, O> Default for Domain<'a, M, T, O>
512where
513	M: Mutability,
514	T: 'a + BitStore,
515	O: BitOrder,
516	Address<M, T>: Referential<'a>,
517	Address<M, [T::Unalias]>: SliceReferential<'a>,
518	Reference<'a, M, [T::Unalias]>: Default,
519{
520	#[inline]
521	fn default() -> Self {
522		Self::Region {
523			head: None,
524			body: Reference::<M, [T::Unalias]>::default(),
525			tail: None,
526		}
527	}
528}
529
530impl<'a, M, T, O> Debug for Domain<'a, M, T, O>
531where
532	M: Mutability,
533	T: 'a + BitStore,
534	O: BitOrder,
535	Address<M, T>: Referential<'a>,
536	Address<M, [T::Unalias]>: SliceReferential<'a>,
537	Reference<'a, M, [T::Unalias]>: Debug,
538{
539	#[inline]
540	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
541		write!(
542			fmt,
543			"Domain::<{} {}, {}>::",
544			M::RENDER,
545			any::type_name::<T>(),
546			any::type_name::<O>(),
547		)?;
548		match self {
549			Self::Enclave(elem) => {
550				fmt.debug_tuple("Enclave").field(elem).finish()
551			},
552			Self::Region { head, body, tail } => fmt
553				.debug_struct("Region")
554				.field("head", head)
555				.field("body", body)
556				.field("tail", tail)
557				.finish(),
558		}
559	}
560}
561
562#[cfg(not(tarpaulin_include))]
563impl<T, O> Clone for Domain<'_, Const, T, O>
564where
565	T: BitStore,
566	O: BitOrder,
567{
568	#[inline]
569	fn clone(&self) -> Self {
570		*self
571	}
572}
573
574impl<T, O> Iterator for Domain<'_, Const, T, O>
575where
576	T: BitStore,
577	O: BitOrder,
578{
579	type Item = T::Mem;
580
581	#[inline]
582	fn next(&mut self) -> Option<Self::Item> {
583		match self {
584			Self::Enclave(elem) => {
585				elem.load_value().tap(|_| *self = Default::default()).into()
586			},
587			Self::Region { head, body, tail } => {
588				if let Some(elem) = head.take() {
589					return elem.load_value().into();
590				}
591				if let Some((elem, rest)) = body.split_first() {
592					*body = rest;
593					return elem.load_value().into();
594				}
595				if let Some(elem) = tail.take() {
596					return elem.load_value().into();
597				}
598				None
599			},
600		}
601	}
602}
603
604impl<T, O> DoubleEndedIterator for Domain<'_, Const, T, O>
605where
606	T: BitStore,
607	O: BitOrder,
608{
609	#[inline]
610	fn next_back(&mut self) -> Option<Self::Item> {
611		match self {
612			Self::Enclave(elem) => {
613				elem.load_value().tap(|_| *self = Default::default()).into()
614			},
615			Self::Region { head, body, tail } => {
616				if let Some(elem) = tail.take() {
617					return elem.load_value().into();
618				}
619				if let Some((elem, rest)) = body.split_last() {
620					*body = rest;
621					return elem.load_value().into();
622				}
623				if let Some(elem) = head.take() {
624					return elem.load_value().into();
625				}
626				None
627			},
628		}
629	}
630}
631
632impl<T, O> ExactSizeIterator for Domain<'_, Const, T, O>
633where
634	T: BitStore,
635	O: BitOrder,
636{
637	#[inline]
638	fn len(&self) -> usize {
639		match self {
640			Self::Enclave(_) => 1,
641			Self::Region { head, body, tail } => {
642				head.is_some() as usize + body.len() + tail.is_some() as usize
643			},
644		}
645	}
646}
647
648impl<T, O> FusedIterator for Domain<'_, Const, T, O>
649where
650	T: BitStore,
651	O: BitOrder,
652{
653}
654
655impl<T, O> Copy for Domain<'_, Const, T, O>
656where
657	T: BitStore,
658	O: BitOrder,
659{
660}
661
662/// Implements numeric formatting by rendering each element.
663macro_rules! fmt {
664	($($fmt:ty => $fwd:ident),+ $(,)?) => { $(
665		impl<'a, T, O> $fmt for Domain<'a, Const, T, O>
666		where
667			O: BitOrder,
668			T: BitStore,
669		{
670			#[inline]
671			fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
672				fmt.debug_list()
673					.entries(self.into_iter().map(FmtForward::$fwd))
674					.finish()
675			}
676		}
677	)+ };
678}
679
680fmt! {
681	Binary => fmt_binary,
682	Display => fmt_display,
683	LowerHex => fmt_lower_hex,
684	Octal => fmt_octal,
685	UpperHex => fmt_upper_hex,
686}
687
688#[doc = include_str!("../doc/domain/PartialElement.md")]
689pub struct PartialElement<'a, M, T, O>
690where
691	M: Mutability,
692	T: 'a + BitStore,
693	O: BitOrder,
694{
695	/// The address of the memory element being partially viewed.
696	///
697	/// This must be stored as a pointer, not a reference, because it must
698	/// retain mutability permissions but cannot have an `&mut` reference to
699	/// a shared element.
700	///
701	/// Similarly, it must remain typed as `T`, not `T::Access`, to allow the
702	/// `<Const, uN>` case not to inappropriately produce a `<Const, Cell<uN>>`
703	/// even if no write is performed.
704	elem: Address<M, T>,
705	/// Cache the selector mask, so it never needs to be recomputed.
706	mask: BitMask<T::Mem>,
707	/// The starting index.
708	head: BitIdx<T::Mem>,
709	/// The ending index.
710	tail: BitEnd<T::Mem>,
711	/// Preserve the originating bit-order
712	_ord: PhantomData<O>,
713	/// This type acts as-if it were a shared-mutable reference.
714	_ref: PhantomData<&'a T::Access>,
715}
716
717impl<'a, M, T, O> PartialElement<'a, M, T, O>
718where
719	M: Mutability,
720	T: 'a + BitStore,
721	O: BitOrder,
722{
723	/// Constructs a new partial-element guarded reference.
724	///
725	/// ## Parameters
726	///
727	/// - `elem`: the element to which this partially points.
728	/// - `head`: the index at which the partial region begins.
729	/// - `tail`: the index at which the partial region ends.
730	#[inline]
731	fn new(
732		elem: Address<M, T>,
733		head: impl Into<Option<BitIdx<T::Mem>>>,
734		tail: impl Into<Option<BitEnd<T::Mem>>>,
735	) -> Self {
736		let (head, tail) = (
737			head.into().unwrap_or(BitIdx::MIN),
738			tail.into().unwrap_or(BitEnd::MAX),
739		);
740		Self {
741			elem,
742			mask: O::mask(head, tail),
743			head,
744			tail,
745			_ord: PhantomData,
746			_ref: PhantomData,
747		}
748	}
749
750	/// Fetches the value stored through `self` and masks away extra bits.
751	///
752	/// ## Returns
753	///
754	/// A bit-map containing any bits set to `1` in the governed bits. All other
755	/// bits are cleared to `0`.
756	#[inline]
757	pub fn load_value(&self) -> T::Mem {
758		self.elem
759			.pipe(|addr| unsafe { &*addr.to_const() })
760			.load_value()
761			& self.mask.into_inner()
762	}
763
764	/// Gets the starting index of the live bits in the element.
765	#[inline]
766	#[cfg(not(tarpaulin_include))]
767	pub fn head(&self) -> BitIdx<T::Mem> {
768		self.head
769	}
770
771	/// Gets the ending index of the live bits in the element.
772	#[inline]
773	#[cfg(not(tarpaulin_include))]
774	pub fn tail(&self) -> BitEnd<T::Mem> {
775		self.tail
776	}
777
778	/// Gets the semantic head and tail indices that constrain which bits of the
779	/// referent element may be accessed.
780	#[inline]
781	#[cfg(not(tarpaulin_include))]
782	pub fn bounds(&self) -> (BitIdx<T::Mem>, BitEnd<T::Mem>) {
783		(self.head, self.tail)
784	}
785
786	/// Gets the bit-mask over all accessible bits.
787	#[inline]
788	#[cfg(not(tarpaulin_include))]
789	pub fn mask(&self) -> BitMask<T::Mem> {
790		self.mask
791	}
792
793	/// Converts the partial element into a bit-slice over its governed bits.
794	#[inline]
795	pub fn into_bitslice(self) -> Reference<'a, M, BitSlice<T, O>>
796	where Address<M, BitSlice<T, O>>: Referential<'a> {
797		unsafe {
798			BitSpan::new_unchecked(
799				self.elem,
800				self.head,
801				(self.tail.into_inner() - self.head.into_inner()) as usize,
802			)
803		}
804		.to_bitslice()
805	}
806}
807
808impl<'a, T, O> PartialElement<'a, Mut, T, O>
809where
810	T: BitStore,
811	O: BitOrder,
812	Address<Mut, T>: Referential<'a>,
813{
814	/// Stores a value through `self` after masking away extra bits.
815	///
816	/// ## Parameters
817	///
818	/// - `&mut self`
819	/// - `value`: A bit-map which will be written into the governed bits. This
820	///   is a bit-map store, not an integer store; the value will not be
821	///   shifted into position and will only be masked directly against the
822	///   bits that this partial-element governs.
823	///
824	/// ## Returns
825	///
826	/// The previous value of the governed bits.
827	#[inline]
828	pub fn store_value(&mut self, value: T::Mem) -> T::Mem {
829		let this = self.access();
830		let prev = this.clear_bits(self.mask);
831		this.set_bits(self.mask & value);
832		prev & self.mask.into_inner()
833	}
834
835	/// Inverts the value of each bit governed by the partial-element.
836	///
837	/// ## Returns
838	///
839	/// The previous value of the governed bits.
840	#[inline]
841	#[cfg(not(tarpaulin_include))]
842	pub fn invert(&mut self) -> T::Mem {
843		self.access().invert_bits(self.mask) & self.mask.into_inner()
844	}
845
846	/// Clears all bits governed by the partial-element to `0`.
847	///
848	/// ## Returns
849	///
850	/// The previous value of the governed bits.
851	#[inline]
852	#[cfg(not(tarpaulin_include))]
853	pub fn clear(&mut self) -> T::Mem {
854		self.access().clear_bits(self.mask) & self.mask.into_inner()
855	}
856
857	/// Sets all bits governed by the partial-element to `1`.
858	///
859	/// ## Returns
860	///
861	/// The previous value of the governed bits.
862	#[inline]
863	#[cfg(not(tarpaulin_include))]
864	pub fn set(&mut self) -> T::Mem {
865		self.access().set_bits(self.mask) & self.mask.into_inner()
866	}
867
868	/// Produces a reference capable of tolerating other handles viewing the
869	/// same *memory element*.
870	#[inline]
871	fn access(&self) -> &T::Access {
872		unsafe { &*self.elem.to_const().cast::<T::Access>() }
873	}
874}
875
876impl<'a, M, T, O> PartialElement<'a, M, T, O>
877where
878	M: Mutability,
879	O: BitOrder,
880	T: 'a + BitStore + radium::Radium,
881{
882	/// Performs a store operation on a partial-element whose bits might be
883	/// observed by another handle.
884	#[inline]
885	pub fn store_value_aliased(&self, value: T::Mem) -> T::Mem {
886		let this = unsafe { &*self.elem.to_const().cast::<T::Access>() };
887		let prev = this.clear_bits(self.mask);
888		this.set_bits(self.mask & value);
889		prev & self.mask.into_inner()
890	}
891}
892
893#[cfg(not(tarpaulin_include))]
894impl<'a, T, O> Clone for PartialElement<'a, Const, T, O>
895where
896	T: BitStore,
897	O: BitOrder,
898	Address<Const, T>: Referential<'a>,
899{
900	#[inline]
901	fn clone(&self) -> Self {
902		*self
903	}
904}
905
906impl<'a, M, T, O> Debug for PartialElement<'a, M, T, O>
907where
908	M: Mutability,
909	T: 'a + BitStore,
910	O: BitOrder,
911{
912	#[inline]
913	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
914		write!(
915			fmt,
916			"PartialElement<{} {}, {}>",
917			M::RENDER,
918			any::type_name::<T>(),
919			any::type_name::<O>(),
920		)?;
921		fmt.debug_struct("")
922			.field("elem", &self.load_value())
923			.field("mask", &self.mask.fmt_display())
924			.field("head", &self.head.fmt_display())
925			.field("tail", &self.tail.fmt_display())
926			.finish()
927	}
928}
929
930#[cfg(not(tarpaulin_include))]
931impl<'a, M, T, O> Hash for PartialElement<'a, M, T, O>
932where
933	M: Mutability,
934	T: 'a + BitStore,
935	O: BitOrder,
936{
937	#[inline]
938	fn hash<H>(&self, hasher: &mut H)
939	where H: Hasher {
940		self.load_value().hash(hasher);
941		self.mask.hash(hasher);
942		self.head.hash(hasher);
943		self.tail.hash(hasher);
944	}
945}
946
947impl<T, O> Copy for PartialElement<'_, Const, T, O>
948where
949	T: BitStore,
950	O: BitOrder,
951{
952}
953
954#[cfg(test)]
955mod tests {
956	use rand::random;
957
958	use super::*;
959	use crate::prelude::*;
960
961	#[test]
962	fn bit_domain() {
963		let data = BitArray::<[u32; 3], Msb0>::new(random());
964
965		let bd = data.bit_domain();
966		assert!(bd.enclave().is_none());
967		let (head, body, tail) = bd.region().unwrap();
968		assert_eq!(data, body);
969		assert!(head.is_empty());
970		assert!(tail.is_empty());
971
972		let bd = data[2 ..].bit_domain();
973		let (head, body, tail) = bd.region().unwrap();
974		assert_eq!(head, &data[2 .. 32]);
975		assert_eq!(body, &data[32 ..]);
976		assert!(tail.is_empty());
977
978		let bd = data[.. 94].bit_domain();
979		let (head, body, tail) = bd.region().unwrap();
980		assert!(head.is_empty());
981		assert_eq!(body, &data[.. 64]);
982		assert_eq!(tail, &data[64 .. 94]);
983
984		let bd = data[2 .. 94].bit_domain();
985		let (head, body, tail) = bd.region().unwrap();
986		assert_eq!(head, &data[2 .. 32]);
987		assert_eq!(body, &data[32 .. 64]);
988		assert_eq!(tail, &data[64 .. 94]);
989
990		let bd = data[34 .. 62].bit_domain();
991		assert!(bd.region().is_none());
992		assert_eq!(bd.enclave().unwrap(), data[34 .. 62]);
993
994		let (head, body, tail) =
995			BitDomain::<Const, usize, Lsb0>::default().region().unwrap();
996		assert!(head.is_empty());
997		assert!(body.is_empty());
998		assert!(tail.is_empty());
999	}
1000
1001	#[test]
1002	fn domain() {
1003		let data: [u32; 3] = random();
1004		let bits = data.view_bits::<Msb0>();
1005
1006		let d = bits.domain();
1007		assert!(d.enclave().is_none());
1008		let (head, body, tail) = d.region().unwrap();
1009		assert!(head.is_none());
1010		assert!(tail.is_none());
1011		assert_eq!(body, data);
1012
1013		let d = bits[2 ..].domain();
1014		let (head, body, tail) = d.region().unwrap();
1015		assert_eq!(head.unwrap().load_value(), (data[0] << 2) >> 2);
1016		assert_eq!(body, &data[1 ..]);
1017		assert!(tail.is_none());
1018
1019		let d = bits[.. 94].domain();
1020		let (head, body, tail) = d.region().unwrap();
1021		assert!(head.is_none());
1022		assert_eq!(body, &data[.. 2]);
1023		assert_eq!(tail.unwrap().load_value(), (data[2] >> 2) << 2);
1024
1025		let d = bits[2 .. 94].domain();
1026		let (head, body, tail) = d.region().unwrap();
1027		assert_eq!(head.unwrap().load_value(), (data[0] << 2) >> 2);
1028		assert_eq!(body, &data[1 .. 2]);
1029		assert_eq!(tail.unwrap().load_value(), (data[2] >> 2) << 2);
1030
1031		let d = bits[34 .. 62].domain();
1032		assert!(d.region().is_none());
1033		assert_eq!(
1034			d.enclave().unwrap().load_value(),
1035			((data[1] << 2) >> 4) << 2,
1036		);
1037
1038		assert!(matches!(bits![].domain(), Domain::Region {
1039			head: None,
1040			body: &[],
1041			tail: None,
1042		}));
1043
1044		assert!(matches!(
1045			Domain::<Const, usize, Lsb0>::default(),
1046			Domain::Region {
1047				head: None,
1048				body: &[],
1049				tail: None,
1050			},
1051		));
1052
1053		let data = core::cell::Cell::new(0u8);
1054		let partial =
1055			data.view_bits::<Lsb0>()[2 .. 6].domain().enclave().unwrap();
1056		assert_eq!(partial.store_value_aliased(!0), 0);
1057		assert_eq!(data.get(), 0b00_1111_00);
1058	}
1059
1060	#[test]
1061	fn iter() {
1062		let bits = [0x12u8, 0x34, 0x56].view_bits::<Lsb0>();
1063		let mut domain = bits[4 .. 12].domain();
1064		assert_eq!(domain.len(), 2);
1065		assert_eq!(domain.next().unwrap(), 0x10);
1066		assert_eq!(domain.next_back().unwrap(), 0x04);
1067
1068		assert!(domain.next().is_none());
1069		assert!(domain.next_back().is_none());
1070
1071		assert_eq!(bits[2 .. 6].domain().len(), 1);
1072		assert_eq!(bits[18 .. 22].domain().next_back().unwrap(), 0b00_0101_00);
1073
1074		let mut domain = bits[4 .. 20].domain();
1075		assert_eq!(domain.next_back().unwrap(), 0x06);
1076		assert_eq!(domain.next_back().unwrap(), 0x34);
1077		assert_eq!(domain.next_back().unwrap(), 0x10);
1078	}
1079
1080	#[test]
1081	#[cfg(feature = "alloc")]
1082	fn render() {
1083		#[cfg(not(feature = "std"))]
1084		use alloc::format;
1085
1086		let data = BitArray::<u32, Msb0>::new(random());
1087
1088		let render = format!("{:?}", data.bit_domain());
1089		let expected = format!(
1090			"BitDomain::<*const u32, {}>::Region {{ head: {:?}, body: {:?}, \
1091			 tail: {:?} }}",
1092			any::type_name::<Msb0>(),
1093			BitSlice::<u32, Msb0>::empty(),
1094			data.as_bitslice(),
1095			BitSlice::<u32, Msb0>::empty(),
1096		);
1097		assert_eq!(render, expected);
1098
1099		let render = format!("{:?}", data[2 .. 30].bit_domain());
1100		let expected = format!(
1101			"BitDomain::<*const u32, {}>::Enclave({:?})",
1102			any::type_name::<Msb0>(),
1103			&data[2 .. 30],
1104		);
1105		assert_eq!(render, expected);
1106
1107		let render = format!("{:?}", data.domain());
1108		let expected = format!(
1109			"Domain::<*const u32, {}>::Region {{ head: None, body: {:?}, tail: \
1110			 None }}",
1111			any::type_name::<Msb0>(),
1112			data.as_raw_slice(),
1113		);
1114		assert_eq!(render, expected);
1115
1116		let render = format!("{:?}", data[2 .. 30].domain());
1117		let expected = format!(
1118			"Domain::<*const u32, {}>::Enclave",
1119			any::type_name::<Msb0>(),
1120		);
1121		assert!(render.starts_with(&expected));
1122
1123		let partial = 0x3Cu8.view_bits::<Lsb0>()[2 .. 6]
1124			.domain()
1125			.enclave()
1126			.unwrap();
1127		let render = format!("{:?}", partial);
1128		assert_eq!(
1129			render,
1130			format!(
1131				"PartialElement<*const u8, {}> {{ elem: 60, mask: {}, head: \
1132				 {}, tail: {} }}",
1133				any::type_name::<Lsb0>(),
1134				partial.mask,
1135				partial.head,
1136				partial.tail,
1137			),
1138		);
1139	}
1140}