1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*! A statically-allocated, fixed-size, buffer containing a [`BitSlice`] region.

You can read the language’s [array fundamental documentation][std] here.

This module defines the [`BitArray`] immediate type, and its associated support
code.

[`BitArray`] is equivalent to `[bool; N]`, in its operation and in its
relationship to the [`BitSlice`] type. It has little behavior or properties in
its own right, and serves solely as a type capable of being used in immediate
value position, and delegates to `BitSlice` for all actual work.

[`BitArray`]: crate::array::BitArray
[`BitSlice`]: crate::slice::BitSlice
[std]: https://doc.rust-lang.org/stable/std/primitive.array.html
!*/

use crate::{
	order::{
		BitOrder,
		Lsb0,
	},
	slice::BitSlice,
	view::BitView,
};

use core::{
	marker::PhantomData,
	mem::MaybeUninit,
	slice,
};

/* Note on C++ `std::bitset<N>` compatibility:

The ideal API for `BitArray` is as follows:

```rust
struct BitArray<O, T, const N: usize>
where
  O: BitOrder,
  T: BitStore,
  N < T::MAX_BITS,
{
  _ord: PhantomData<O>,
  data: [T; crate::mem::elts::<T>(N)],
}

impl<O, T, const N: usize> BitArray<O, T, N>
where
  O: BitOrder,
  T: BitStore,
{
  pub fn len(&self) -> usize { N }
}
```

This allows the structure to be parametric over the number of bits, rather than
a scalar or array type that satisfies the number of bits. Unfortunately, it is
inexpressible until the Rust compiler’s const-evaluation engine permits using
numeric type parameters in type-level expressions.
*/

/** An array of individual bits, able to be held by value on the stack.

This type is generic over all [`Sized`] implementors of the [`BitView`] trait.
Due to limitations in the Rust language’s const-generics implementation (it is
both unstable and incomplete), this must take an array type parameter directly,
rather than register type and bit-count integer parameters. This makes it less
convenient to use than C++’s [`std::bitset<N>`] array type. The [`bitarr!`]
macro is capable of constructing both values and specific types of `BitArray`,
and this macro should be preferred for most use.

The advantage of using this wrapper is that it implements [`Deref`]/[`Mut`] to
[`BitSlice`], as well as implementing all of `BitSlice`s traits by forwarding to
the `BitSlice` view of its contained data. This allows it to have `BitSlice`
behavior by itself, without requiring explicit [`.as_bitslice()`] calls in user
code.

# Limitations

This does not track start or end indices of its [`BitSlice`] view, and so that
view will always fully span the buffer. You cannot produce, for example, an
array of twelve bits.

# Type Parameters

- `O`: The ordering of bits within memory registers.
- `V`: Some buffer which can be used as the basis for a [`BitSlice`] view. This
  will usually be an array of `[T: BitRegister; N]`.

# Examples

This type is useful for marking that some value is always to be used as a
[`BitSlice`].
**/
///
/// ```rust
/// use bitvec::prelude::*;
///
/// struct HasBitfields {
///   header: u32,
///   // creates a type declaration.
///   fields: bitarr!(for 20, in Msb0, u8),
/// }
///
/// impl HasBitfields {
///   pub fn new() -> Self {
///     Self {
///       header: 0,
///       // creates a value object.
///       // the type paramaters must be repeated.
///       fields: bitarr![Msb0, u8; 0; 20],
///     }
///   }
///
///   /// Access a bit region directly
///   pub fn get_subfield(&self) -> &BitSlice<Msb0, u8> {
///     &self.fields[.. 4]
///   }
///
///   /// Read a 12-bit value out of a region
///   pub fn read_value(&self) -> u16 {
///     self.fields[4 .. 16].load()
///   }
///
///   /// Write a 12-bit value into a region
///   pub fn set_value(&mut self, value: u16) {
///     self.fields[4 .. 16].store(value);
///   }
/// }
/// ```
/**
# Eventual Obsolescence

When const-generics stabilize, this will be modified to have a signature more
like `BitArray<O, T, const N: usize>([T; elts::<T>(N)]);`, to mirror the
behavior of ordinary arrays `[T; N]` as they stand today.

[`BitSlice`]: crate::slice::BitSlice
[`BitView`]: crate::view::BitView
[`Deref`]: core::ops::Deref
[`Mut`]: core::ops::DerefMut
[`Sized`]: core::marker::Sized
[`bitarr!`]: macro@crate::bitarr
[`std::bitset<N>`]: https://en.cppreference.com/w/cpp/utility/bitset
[`.as_bitslice()`]: Self::as_bitslice
**/
#[repr(transparent)]
pub struct BitArray<O = Lsb0, V = [usize; 1]>
where
	O: BitOrder,
	V: BitView,
{
	/// The ordering of bits within a storage element `V::Store`.
	_ord: PhantomData<O>,
	/// The wrapped data store.
	data: V,
}

impl<O, V> BitArray<O, V>
where
	O: BitOrder,
	V: BitView,
{
	/// Constructs a new `BitArray` with its memory set to zero.
	#[inline]
	pub fn zeroed() -> Self {
		Self {
			_ord: PhantomData,
			data: unsafe { MaybeUninit::zeroed().assume_init() },
		}
	}

	/// Wraps a buffer in a `BitArray`.
	///
	/// # Examples
	///
	/// ```rust
	/// use bitvec::prelude::*;
	///
	/// let data = [0u8; 2];
	/// let bits: BitArray<Msb0, _> = BitArray::new(data);
	/// assert_eq!(bits.len(), 16);
	/// ```
	#[inline]
	pub fn new(data: V) -> Self {
		Self {
			_ord: PhantomData,
			data,
		}
	}

	/// Removes the `BitArray` wrapper, leaving the contained buffer.
	///
	/// # Examples
	///
	/// ```rust
	/// use bitvec::prelude::*;
	///
	/// let bitarr = bitarr![Lsb0, usize; 0; 30];
	/// let native: [usize; 1] = bitarr.value();
	/// ```
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	pub fn value(self) -> V {
		self.data
	}

	/// Views the array as a [`BitSlice`].
	///
	/// [`BitSlice`]: crate::slice::BitSlice
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	pub fn as_bitslice(&self) -> &BitSlice<O, V::Store> {
		self.data.view_bits::<O>()
	}

	/// Views the array as a mutable [`BitSlice`].
	///
	/// [`BitSlice`]: crate::slice::BitSlice
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	pub fn as_mut_bitslice(&mut self) -> &mut BitSlice<O, V::Store> {
		self.data.view_bits_mut::<O>()
	}

	/// Views the array as a slice of its underlying memory registers.
	#[inline]
	pub fn as_raw_slice(&self) -> &[V::Store] {
		unsafe {
			slice::from_raw_parts(
				&self.data as *const V as *const V::Store,
				V::const_elts(),
			)
		}
	}

	/// Views the array as a mutable slice of its underlying memory registers.
	#[inline]
	pub fn as_mut_raw_slice(&mut self) -> &mut [V::Store] {
		unsafe {
			slice::from_raw_parts_mut(
				&mut self.data as *mut V as *mut V::Store,
				V::const_elts(),
			)
		}
	}

	#[doc(hidden)]
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	#[deprecated = "This is renamed to `as_raw_slice`"]
	pub fn as_slice(&self) -> &[V::Store] {
		self.as_raw_slice()
	}

	#[doc(hidden)]
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	#[deprecated = "This is renamed to `as_mut_raw_slice`"]
	pub fn as_mut_slice(&mut self) -> &mut [V::Store] {
		self.as_mut_raw_slice()
	}

	/// Views the interior buffer.
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	pub fn as_buffer(&self) -> &V {
		&self.data
	}

	/// Mutably views the interior buffer.
	#[inline(always)]
	#[cfg(not(tarpaulin_include))]
	pub fn as_mut_buffer(&mut self) -> &mut V {
		&mut self.data
	}
}

mod iter;
mod ops;
mod traits;

pub use self::iter::IntoIter;

#[cfg(test)]
mod tests;