Skip to main content

binius_field/underlier/
divisible.rs

1// Copyright 2024-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4use std::mem::size_of;
5
6/// Divides an underlier type into smaller underliers in memory and iterates over them.
7///
8/// [`Divisible`] provides iteration over the subdivisions of an underlier type, guaranteeing that
9/// iteration proceeds from the least significant bits to the most significant bits, regardless of
10/// the CPU architecture's endianness.
11///
12/// # Endianness Handling
13///
14/// To ensure consistent LSB-to-MSB iteration order across all platforms:
15/// - On little-endian systems: elements are naturally ordered LSB-to-MSB in memory, so iteration
16///   proceeds forward through the array
17/// - On big-endian systems: elements are ordered MSB-to-LSB in memory, so iteration is reversed to
18///   achieve LSB-to-MSB order
19///
20/// This abstraction allows code to work with subdivided underliers in a platform-independent way
21/// while maintaining the invariant that the first element always represents the least significant
22/// portion of the value.
23pub trait Divisible<T>: Sized {
24	/// The log2 of the number of `T` elements that fit in `Self`.
25	const LOG_N: usize;
26
27	/// The number of `T` elements that fit in `Self`.
28	const N: usize = 1 << Self::LOG_N;
29
30	/// Returns an iterator over subdivisions of this underlier value, ordered from LSB to MSB.
31	fn value_iter(value: Self) -> impl ExactSizeIterator<Item = T> + Send + Clone;
32
33	/// Returns an iterator over subdivisions of this underlier reference, ordered from LSB to MSB.
34	fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = T> + Send + Clone + '_;
35
36	/// Returns an iterator over subdivisions of a slice of underliers, ordered from LSB to MSB.
37	fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = T> + Send + Clone + '_;
38
39	/// Get element at index (LSB-first ordering).
40	///
41	/// # Panics
42	///
43	/// Panics if `index >= Self::N`.
44	#[inline]
45	fn get(&self, index: usize) -> T {
46		assert!(index < Self::N, "index {index} out of bounds (N = {})", Self::N);
47		// Safety: `index < Self::N` checked above.
48		unsafe { self.get_unchecked(index) }
49	}
50
51	/// Set element at index (LSB-first ordering), in place.
52	///
53	/// # Panics
54	///
55	/// Panics if `index >= Self::N`.
56	#[inline]
57	fn set(&mut self, index: usize, val: T) {
58		assert!(index < Self::N, "index {index} out of bounds (N = {})", Self::N);
59		// Safety: `index < Self::N` checked above.
60		unsafe { self.set_unchecked(index, val) };
61	}
62
63	/// Get element at index (LSB-first ordering) without bounds checking.
64	///
65	/// # Safety
66	///
67	/// The caller must ensure that `index < Self::N`.
68	unsafe fn get_unchecked(&self, index: usize) -> T;
69
70	/// Set element at index (LSB-first ordering) in place, without bounds checking.
71	///
72	/// # Safety
73	///
74	/// The caller must ensure that `index < Self::N`.
75	unsafe fn set_unchecked(&mut self, index: usize, val: T);
76
77	/// Create a value with `val` broadcast to all `N` positions.
78	fn broadcast(val: T) -> Self;
79
80	/// Construct a value from an iterator of elements.
81	///
82	/// Consumes at most `N` elements from the iterator. If the iterator
83	/// yields fewer than `N` elements, remaining positions are filled with zeros.
84	fn from_iter(iter: impl Iterator<Item = T>) -> Self;
85}
86
87/// Helper functions for Divisible implementations using bytemuck memory casting.
88///
89/// These functions handle the endianness-aware iteration over subdivisions of an underlier type.
90pub mod memcast {
91	use bytemuck::{Pod, Zeroable};
92
93	/// Returns an iterator over subdivisions of a value, ordered from LSB to MSB.
94	#[cfg(target_endian = "little")]
95	#[inline]
96	pub fn value_iter<Big, Small, const N: usize>(
97		value: Big,
98	) -> impl ExactSizeIterator<Item = Small> + Send + Clone
99	where
100		Big: Pod,
101		Small: Pod + Send,
102	{
103		bytemuck::must_cast::<Big, [Small; N]>(value).into_iter()
104	}
105
106	/// Returns an iterator over subdivisions of a value, ordered from LSB to MSB.
107	#[cfg(target_endian = "big")]
108	#[inline]
109	pub fn value_iter<Big, Small, const N: usize>(
110		value: Big,
111	) -> impl ExactSizeIterator<Item = Small> + Send + Clone
112	where
113		Big: Pod,
114		Small: Pod + Send,
115	{
116		bytemuck::must_cast::<Big, [Small; N]>(value)
117			.into_iter()
118			.rev()
119	}
120
121	/// Returns an iterator over subdivisions of a reference, ordered from LSB to MSB.
122	#[cfg(target_endian = "little")]
123	#[inline]
124	pub fn ref_iter<Big, Small, const N: usize>(
125		value: &Big,
126	) -> impl ExactSizeIterator<Item = Small> + Send + Clone + '_
127	where
128		Big: Pod,
129		Small: Pod + Send + Sync,
130	{
131		bytemuck::must_cast_ref::<Big, [Small; N]>(value)
132			.iter()
133			.copied()
134	}
135
136	/// Returns an iterator over subdivisions of a reference, ordered from LSB to MSB.
137	#[cfg(target_endian = "big")]
138	#[inline]
139	pub fn ref_iter<Big, Small, const N: usize>(
140		value: &Big,
141	) -> impl ExactSizeIterator<Item = Small> + Send + Clone + '_
142	where
143		Big: Pod,
144		Small: Pod + Send + Sync,
145	{
146		bytemuck::must_cast_ref::<Big, [Small; N]>(value)
147			.iter()
148			.rev()
149			.copied()
150	}
151
152	/// Returns an iterator over subdivisions of a slice, ordered from LSB to MSB.
153	#[cfg(target_endian = "little")]
154	#[inline]
155	pub fn slice_iter<Big, Small>(
156		slice: &[Big],
157	) -> impl ExactSizeIterator<Item = Small> + Send + Clone + '_
158	where
159		Big: Pod,
160		Small: Pod + Send + Sync,
161	{
162		bytemuck::must_cast_slice::<Big, Small>(slice)
163			.iter()
164			.copied()
165	}
166
167	/// Returns an iterator over subdivisions of a slice, ordered from LSB to MSB.
168	///
169	/// For big-endian: iterate through the raw slice, but for each element's
170	/// subdivisions, reverse the index to maintain LSB-first ordering.
171	#[cfg(target_endian = "big")]
172	#[inline]
173	pub fn slice_iter<Big, Small, const LOG_N: usize>(
174		slice: &[Big],
175	) -> impl ExactSizeIterator<Item = Small> + Send + Clone + '_
176	where
177		Big: Pod,
178		Small: Pod + Send + Sync,
179	{
180		const N: usize = 1 << LOG_N;
181		let raw_slice = bytemuck::must_cast_slice::<Big, Small>(slice);
182		(0..raw_slice.len()).map(move |i| {
183			let element_idx = i >> LOG_N;
184			let sub_idx = i & (N - 1);
185			let reversed_sub_idx = N - 1 - sub_idx;
186			let raw_idx = element_idx * N + reversed_sub_idx;
187			raw_slice[raw_idx]
188		})
189	}
190
191	/// Get element at index (LSB-first ordering) without bounds checking.
192	///
193	/// # Safety
194	///
195	/// The caller must ensure that `index < N`.
196	#[cfg(target_endian = "little")]
197	#[inline]
198	pub unsafe fn get<Big, Small, const N: usize>(value: &Big, index: usize) -> Small
199	where
200		Big: Pod,
201		Small: Pod,
202	{
203		// Safety: the caller guarantees `index < N`.
204		unsafe { *bytemuck::must_cast_ref::<Big, [Small; N]>(value).get_unchecked(index) }
205	}
206
207	/// Get element at index (LSB-first ordering) without bounds checking.
208	///
209	/// # Safety
210	///
211	/// The caller must ensure that `index < N`.
212	#[cfg(target_endian = "big")]
213	#[inline]
214	pub unsafe fn get<Big, Small, const N: usize>(value: &Big, index: usize) -> Small
215	where
216		Big: Pod,
217		Small: Pod,
218	{
219		// Safety: the caller guarantees `index < N`, so `N - 1 - index < N`.
220		unsafe { *bytemuck::must_cast_ref::<Big, [Small; N]>(value).get_unchecked(N - 1 - index) }
221	}
222
223	/// Set element at index (LSB-first ordering), returning modified value, without bounds
224	/// checking.
225	///
226	/// # Safety
227	///
228	/// The caller must ensure that `index < N`.
229	#[cfg(target_endian = "little")]
230	#[inline]
231	pub unsafe fn set<Big, Small, const N: usize>(value: &Big, index: usize, val: Small) -> Big
232	where
233		Big: Pod,
234		Small: Pod,
235	{
236		let mut arr = *bytemuck::must_cast_ref::<Big, [Small; N]>(value);
237		// Safety: the caller guarantees `index < N`.
238		unsafe {
239			*arr.get_unchecked_mut(index) = val;
240		}
241		bytemuck::must_cast(arr)
242	}
243
244	/// Set element at index (LSB-first ordering), returning modified value, without bounds
245	/// checking.
246	///
247	/// # Safety
248	///
249	/// The caller must ensure that `index < N`.
250	#[cfg(target_endian = "big")]
251	#[inline]
252	pub unsafe fn set<Big, Small, const N: usize>(value: &Big, index: usize, val: Small) -> Big
253	where
254		Big: Pod,
255		Small: Pod,
256	{
257		let mut arr = *bytemuck::must_cast_ref::<Big, [Small; N]>(value);
258		// Safety: the caller guarantees `index < N`, so `N - 1 - index < N`.
259		unsafe {
260			*arr.get_unchecked_mut(N - 1 - index) = val;
261		}
262		bytemuck::must_cast(arr)
263	}
264
265	/// Broadcast a value to all positions.
266	#[inline]
267	pub fn broadcast<Big, Small, const N: usize>(val: Small) -> Big
268	where
269		Big: Pod,
270		Small: Pod + Copy,
271	{
272		bytemuck::must_cast::<[Small; N], Big>([val; N])
273	}
274
275	/// Construct a value from an iterator of elements.
276	#[cfg(target_endian = "little")]
277	#[inline]
278	pub fn from_iter<Big, Small, const N: usize>(iter: impl Iterator<Item = Small>) -> Big
279	where
280		Big: Pod,
281		Small: Pod,
282	{
283		let mut arr: [Small; N] = Zeroable::zeroed();
284		for (i, val) in iter.take(N).enumerate() {
285			arr[i] = val;
286		}
287		bytemuck::must_cast(arr)
288	}
289
290	/// Construct a value from an iterator of elements.
291	#[cfg(target_endian = "big")]
292	#[inline]
293	pub fn from_iter<Big, Small, const N: usize>(iter: impl Iterator<Item = Small>) -> Big
294	where
295		Big: Pod,
296		Small: Pod,
297	{
298		let mut arr: [Small; N] = Zeroable::zeroed();
299		for (i, val) in iter.take(N).enumerate() {
300			arr[N - 1 - i] = val;
301		}
302		bytemuck::must_cast(arr)
303	}
304}
305
306/// Helper functions for Divisible implementations using bitmask operations on sub-byte elements.
307///
308/// These functions work on any type that implements `Divisible<u8>` by extracting
309/// and modifying sub-byte elements through the byte interface.
310pub mod bitmask {
311	use super::{Divisible, SmallU};
312
313	/// Get a sub-byte element at index (LSB-first ordering) without bounds checking.
314	///
315	/// # Safety
316	///
317	/// The caller must ensure that `index < Big::N` (over `SmallU<BITS>` elements).
318	#[inline]
319	pub unsafe fn get<Big, const BITS: usize>(value: Big, index: usize) -> SmallU<BITS>
320	where
321		Big: Divisible<u8>,
322	{
323		let elems_per_byte = 8 / BITS;
324		let byte_index = index / elems_per_byte;
325		let sub_index = index % elems_per_byte;
326		// Safety: `index < Big::N` over `SmallU<BITS>` implies `byte_index < Big::N` over `u8`.
327		let byte = unsafe { Divisible::<u8>::get_unchecked(&value, byte_index) };
328		let shift = sub_index * BITS;
329		SmallU::<BITS>::new(byte >> shift)
330	}
331
332	/// Set a sub-byte element at index (LSB-first ordering), returning modified value, without
333	/// bounds checking.
334	///
335	/// # Safety
336	///
337	/// The caller must ensure that `index < Big::N` (over `SmallU<BITS>` elements).
338	#[inline]
339	pub unsafe fn set<Big, const BITS: usize>(
340		mut value: Big,
341		index: usize,
342		val: SmallU<BITS>,
343	) -> Big
344	where
345		Big: Divisible<u8>,
346	{
347		let elems_per_byte = 8 / BITS;
348		let byte_index = index / elems_per_byte;
349		let sub_index = index % elems_per_byte;
350		// Safety: `index < Big::N` over `SmallU<BITS>` implies `byte_index < Big::N` over `u8`.
351		let byte = unsafe { Divisible::<u8>::get_unchecked(&value, byte_index) };
352		let shift = sub_index * BITS;
353		let mask = (1u8 << BITS) - 1;
354		let new_byte = (byte & !(mask << shift)) | (val.val() << shift);
355		// Safety: `byte_index < Big::N` over `u8`, as above.
356		unsafe { Divisible::<u8>::set_unchecked(&mut value, byte_index, new_byte) };
357		value
358	}
359}
360
361/// Helper functions for Divisible implementations using the get method.
362///
363/// These functions create iterators by mapping indices through `Divisible::get`,
364/// useful for SIMD types where extract intrinsics provide efficient element access.
365pub mod mapget {
366	use binius_utils::iter::IterExtensions;
367
368	use super::Divisible;
369
370	/// Create an iterator over subdivisions by mapping get over indices.
371	#[inline]
372	pub fn value_iter<Big, Small>(value: Big) -> impl ExactSizeIterator<Item = Small> + Send + Clone
373	where
374		Big: Divisible<Small> + Send + Clone,
375		Small: Send,
376	{
377		(0..Big::N).map_skippable(move |i| Divisible::<Small>::get(&value, i))
378	}
379
380	/// Create a slice iterator by computing global index and using get.
381	#[inline]
382	pub fn slice_iter<Big, Small>(
383		slice: &[Big],
384	) -> impl ExactSizeIterator<Item = Small> + Send + Clone + '_
385	where
386		Big: Divisible<Small> + Send + Sync,
387		Small: Send,
388	{
389		let total = slice.len() * Big::N;
390		(0..total).map_skippable(move |global_idx| {
391			let elem_idx = global_idx / Big::N;
392			let sub_idx = global_idx % Big::N;
393			Divisible::<Small>::get(&slice[elem_idx], sub_idx)
394		})
395	}
396}
397
398/// Iterator for dividing an underlier into sub-byte elements (ie. [`SmallU`]).
399///
400/// This iterator wraps a byte iterator and extracts sub-byte elements from each byte.
401/// Generic over the byte iterator type `I`.
402#[derive(Clone)]
403pub struct SmallUDivisIter<I, const N: usize> {
404	byte_iter: I,
405	current_byte: Option<u8>,
406	sub_idx: usize,
407}
408
409impl<I: Iterator<Item = u8>, const N: usize> SmallUDivisIter<I, N> {
410	const ELEMS_PER_BYTE: usize = 8 / N;
411
412	pub fn new(mut byte_iter: I) -> Self {
413		let current_byte = byte_iter.next();
414		Self {
415			byte_iter,
416			current_byte,
417			sub_idx: 0,
418		}
419	}
420}
421
422impl<I: ExactSizeIterator<Item = u8>, const N: usize> Iterator for SmallUDivisIter<I, N> {
423	type Item = SmallU<N>;
424
425	#[inline]
426	fn next(&mut self) -> Option<Self::Item> {
427		let byte = self.current_byte?;
428		let shift = self.sub_idx * N;
429		let result = SmallU::<N>::new(byte >> shift);
430
431		self.sub_idx += 1;
432		if self.sub_idx >= Self::ELEMS_PER_BYTE {
433			self.sub_idx = 0;
434			self.current_byte = self.byte_iter.next();
435		}
436
437		Some(result)
438	}
439
440	#[inline]
441	fn size_hint(&self) -> (usize, Option<usize>) {
442		let remaining_in_current = if self.current_byte.is_some() {
443			Self::ELEMS_PER_BYTE - self.sub_idx
444		} else {
445			0
446		};
447		let remaining_bytes = self.byte_iter.len();
448		let total = remaining_in_current + remaining_bytes * Self::ELEMS_PER_BYTE;
449		(total, Some(total))
450	}
451}
452
453impl<I: ExactSizeIterator<Item = u8>, const N: usize> ExactSizeIterator for SmallUDivisIter<I, N> {}
454
455/// Implements `Divisible` trait using bytemuck memory casting.
456///
457/// This macro generates `Divisible` implementations for a big type over smaller types.
458/// The implementations use the helper functions in the `memcast` module.
459macro_rules! impl_divisible_memcast {
460	($big:ty, $($small:ty),+) => {
461		$(
462			impl $crate::underlier::Divisible<$small> for $big {
463				const LOG_N: usize = (size_of::<$big>() / size_of::<$small>()).ilog2() as usize;
464
465				#[inline]
466				fn value_iter(value: Self) -> impl ExactSizeIterator<Item = $small> + Send + Clone {
467					const N: usize = size_of::<$big>() / size_of::<$small>();
468					$crate::underlier::memcast::value_iter::<$big, $small, N>(value)
469				}
470
471				#[inline]
472				fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = $small> + Send + Clone + '_ {
473					const N: usize = size_of::<$big>() / size_of::<$small>();
474					$crate::underlier::memcast::ref_iter::<$big, $small, N>(value)
475				}
476
477				#[inline]
478				#[cfg(target_endian = "little")]
479				fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $small> + Send + Clone + '_ {
480					$crate::underlier::memcast::slice_iter::<$big, $small>(slice)
481				}
482
483				#[inline]
484				#[cfg(target_endian = "big")]
485				fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $small> + Send + Clone + '_ {
486					const LOG_N: usize = (size_of::<$big>() / size_of::<$small>()).ilog2() as usize;
487					$crate::underlier::memcast::slice_iter::<$big, $small, LOG_N>(slice)
488				}
489
490				#[inline]
491				unsafe fn get_unchecked(&self, index: usize) -> $small {
492					const N: usize = size_of::<$big>() / size_of::<$small>();
493					// Safety: the caller guarantees `index < Self::N == N`.
494					unsafe { $crate::underlier::memcast::get::<$big, $small, N>(self, index) }
495				}
496
497				#[inline]
498				unsafe fn set_unchecked(&mut self, index: usize, val: $small) {
499					const N: usize = size_of::<$big>() / size_of::<$small>();
500					// Safety: the caller guarantees `index < Self::N == N`.
501					*self = unsafe { $crate::underlier::memcast::set::<$big, $small, N>(&*self, index, val) };
502				}
503
504				#[inline]
505				fn broadcast(val: $small) -> Self {
506					const N: usize = size_of::<$big>() / size_of::<$small>();
507					$crate::underlier::memcast::broadcast::<$big, $small, N>(val)
508				}
509
510				#[inline]
511				fn from_iter(iter: impl Iterator<Item = $small>) -> Self {
512					const N: usize = size_of::<$big>() / size_of::<$small>();
513					$crate::underlier::memcast::from_iter::<$big, $small, N>(iter)
514				}
515			}
516		)+
517	};
518}
519
520#[allow(unused)]
521pub(crate) use impl_divisible_memcast;
522
523/// Implements `Divisible` trait for SmallU types using bitmask operations.
524///
525/// This macro generates `Divisible<SmallU<BITS>>` implementations for a big type
526/// by wrapping byte iteration with bitmasking to extract sub-byte elements.
527macro_rules! impl_divisible_bitmask {
528	// Special case for u8: operates directly on the byte without needing Divisible::<u8>
529	(u8, $($bits:expr),+) => {
530		$(
531			impl $crate::underlier::Divisible<$crate::underlier::SmallU<$bits>> for u8 {
532				const LOG_N: usize = (8usize / $bits).ilog2() as usize;
533
534				#[inline]
535				fn value_iter(value: Self) -> impl ExactSizeIterator<Item = $crate::underlier::SmallU<$bits>> + Send + Clone {
536					$crate::underlier::SmallUDivisIter::new(std::iter::once(value))
537				}
538
539				#[inline]
540				fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = $crate::underlier::SmallU<$bits>> + Send + Clone + '_ {
541					$crate::underlier::SmallUDivisIter::new(std::iter::once(*value))
542				}
543
544				#[inline]
545				fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $crate::underlier::SmallU<$bits>> + Send + Clone + '_ {
546					$crate::underlier::SmallUDivisIter::new(slice.iter().copied())
547				}
548
549				#[inline]
550				unsafe fn get_unchecked(&self, index: usize) -> $crate::underlier::SmallU<$bits> {
551					let shift = index * $bits;
552					$crate::underlier::SmallU::<$bits>::new(*self >> shift)
553				}
554
555				#[inline]
556				unsafe fn set_unchecked(&mut self, index: usize, val: $crate::underlier::SmallU<$bits>) {
557					let shift = index * $bits;
558					let mask = (1u8 << $bits) - 1;
559					*self = (*self & !(mask << shift)) | (val.val() << shift);
560				}
561
562				#[inline]
563				fn broadcast(val: $crate::underlier::SmallU<$bits>) -> Self {
564					if $bits == 1 {
565						// For 1-bit values: 0 -> 0x00, 1 -> 0xFF
566						val.val().wrapping_neg()
567					} else {
568						let mut result = val.val();
569						// Self-replicate to fill the byte
570						let mut current_bits = $bits;
571						while current_bits < 8 {
572							result |= result << current_bits;
573							current_bits *= 2;
574						}
575						result
576					}
577				}
578
579				#[inline]
580				fn from_iter(iter: impl Iterator<Item = $crate::underlier::SmallU<$bits>>) -> Self {
581					const N: usize = 8 / $bits;
582					let mut result: Self = 0;
583					for (i, val) in iter.take(N).enumerate() {
584						$crate::underlier::Divisible::<$crate::underlier::SmallU<$bits>>::set(&mut result, i, val);
585					}
586					result
587				}
588			}
589		)+
590	};
591
592	// General case for types larger than u8: wraps byte iteration
593	($big:ty, $($bits:expr),+) => {
594		$(
595			impl $crate::underlier::Divisible<$crate::underlier::SmallU<$bits>> for $big {
596				const LOG_N: usize = (8 * size_of::<$big>() / $bits).ilog2() as usize;
597
598				#[inline]
599				fn value_iter(value: Self) -> impl ExactSizeIterator<Item = $crate::underlier::SmallU<$bits>> + Send + Clone {
600					$crate::underlier::SmallUDivisIter::new(
601						$crate::underlier::Divisible::<u8>::value_iter(value)
602					)
603				}
604
605				#[inline]
606				fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = $crate::underlier::SmallU<$bits>> + Send + Clone + '_ {
607					$crate::underlier::SmallUDivisIter::new(
608						$crate::underlier::Divisible::<u8>::ref_iter(value)
609					)
610				}
611
612				#[inline]
613				fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $crate::underlier::SmallU<$bits>> + Send + Clone + '_ {
614					$crate::underlier::SmallUDivisIter::new(
615						$crate::underlier::Divisible::<u8>::slice_iter(slice)
616					)
617				}
618
619				#[inline]
620				unsafe fn get_unchecked(&self, index: usize) -> $crate::underlier::SmallU<$bits> {
621					// Safety: the caller guarantees `index < Self::N`.
622					unsafe { $crate::underlier::bitmask::get::<Self, $bits>(*self, index) }
623				}
624
625				#[inline]
626				unsafe fn set_unchecked(&mut self, index: usize, val: $crate::underlier::SmallU<$bits>) {
627					// Safety: the caller guarantees `index < Self::N`.
628					*self = unsafe { $crate::underlier::bitmask::set::<Self, $bits>(*self, index, val) };
629				}
630
631				#[inline]
632				fn broadcast(val: $crate::underlier::SmallU<$bits>) -> Self {
633					// First splat to u8, then splat the byte to fill Self
634					let byte = $crate::underlier::Divisible::<$crate::underlier::SmallU<$bits>>::broadcast(val);
635					$crate::underlier::Divisible::<u8>::broadcast(byte)
636				}
637
638				#[inline]
639				fn from_iter(iter: impl Iterator<Item = $crate::underlier::SmallU<$bits>>) -> Self {
640					const N: usize = 8 * size_of::<$big>() / $bits;
641					let mut result: Self = bytemuck::Zeroable::zeroed();
642					for (i, val) in iter.take(N).enumerate() {
643						$crate::underlier::Divisible::<$crate::underlier::SmallU<$bits>>::set(&mut result, i, val);
644					}
645					result
646				}
647			}
648		)+
649	};
650}
651
652#[allow(unused)]
653pub(crate) use impl_divisible_bitmask;
654
655use super::small_uint::SmallU;
656
657// Implement Divisible using memcast for primitive types
658impl_divisible_memcast!(u128, u64, u32, u16, u8);
659impl_divisible_memcast!(u64, u32, u16, u8);
660impl_divisible_memcast!(u32, u16, u8);
661impl_divisible_memcast!(u16, u8);
662
663// Implement Divisible using bitmask for SmallU types
664impl_divisible_bitmask!(u8, 1, 2, 4);
665impl_divisible_bitmask!(u16, 1, 2, 4);
666impl_divisible_bitmask!(u32, 1, 2, 4);
667impl_divisible_bitmask!(u64, 1, 2, 4);
668impl_divisible_bitmask!(u128, 1, 2, 4);
669
670// Divisible for SmallU types that subdivide into smaller SmallU types
671impl Divisible<SmallU<1>> for SmallU<2> {
672	const LOG_N: usize = 1;
673
674	#[inline]
675	fn value_iter(value: Self) -> impl ExactSizeIterator<Item = SmallU<1>> + Send + Clone {
676		mapget::value_iter(value)
677	}
678
679	#[inline]
680	fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = SmallU<1>> + Send + Clone + '_ {
681		mapget::value_iter(*value)
682	}
683
684	#[inline]
685	fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = SmallU<1>> + Send + Clone + '_ {
686		mapget::slice_iter(slice)
687	}
688
689	#[inline]
690	unsafe fn get_unchecked(&self, index: usize) -> SmallU<1> {
691		SmallU::<1>::new(self.val() >> index)
692	}
693
694	#[inline]
695	unsafe fn set_unchecked(&mut self, index: usize, val: SmallU<1>) {
696		let mask = 1u8 << index;
697		*self = SmallU::<2>::new((self.val() & !mask) | (val.val() << index));
698	}
699
700	#[inline]
701	fn broadcast(val: SmallU<1>) -> Self {
702		// 0b0 -> 0b00, 0b1 -> 0b11
703		let v = val.val();
704		SmallU::<2>::new(v | (v << 1))
705	}
706
707	#[inline]
708	fn from_iter(iter: impl Iterator<Item = SmallU<1>>) -> Self {
709		iter.chain(std::iter::repeat(SmallU::<1>::new(0)))
710			.take(2)
711			.enumerate()
712			.fold(SmallU::<2>::new(0), |mut acc, (i, val)| {
713				acc.set(i, val);
714				acc
715			})
716	}
717}
718
719impl Divisible<SmallU<1>> for SmallU<4> {
720	const LOG_N: usize = 2;
721
722	#[inline]
723	fn value_iter(value: Self) -> impl ExactSizeIterator<Item = SmallU<1>> + Send + Clone {
724		mapget::value_iter(value)
725	}
726
727	#[inline]
728	fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = SmallU<1>> + Send + Clone + '_ {
729		mapget::value_iter(*value)
730	}
731
732	#[inline]
733	fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = SmallU<1>> + Send + Clone + '_ {
734		mapget::slice_iter(slice)
735	}
736
737	#[inline]
738	unsafe fn get_unchecked(&self, index: usize) -> SmallU<1> {
739		SmallU::<1>::new(self.val() >> index)
740	}
741
742	#[inline]
743	unsafe fn set_unchecked(&mut self, index: usize, val: SmallU<1>) {
744		let mask = 1u8 << index;
745		*self = SmallU::<4>::new((self.val() & !mask) | (val.val() << index));
746	}
747
748	#[inline]
749	fn broadcast(val: SmallU<1>) -> Self {
750		// 0b0 -> 0b0000, 0b1 -> 0b1111
751		let mut v = val.val();
752		v |= v << 1;
753		v |= v << 2;
754		SmallU::<4>::new(v)
755	}
756
757	#[inline]
758	fn from_iter(iter: impl Iterator<Item = SmallU<1>>) -> Self {
759		iter.chain(std::iter::repeat(SmallU::<1>::new(0)))
760			.take(4)
761			.enumerate()
762			.fold(SmallU::<4>::new(0), |mut acc, (i, val)| {
763				acc.set(i, val);
764				acc
765			})
766	}
767}
768
769impl Divisible<SmallU<2>> for SmallU<4> {
770	const LOG_N: usize = 1;
771
772	#[inline]
773	fn value_iter(value: Self) -> impl ExactSizeIterator<Item = SmallU<2>> + Send + Clone {
774		mapget::value_iter(value)
775	}
776
777	#[inline]
778	fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = SmallU<2>> + Send + Clone + '_ {
779		mapget::value_iter(*value)
780	}
781
782	#[inline]
783	fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = SmallU<2>> + Send + Clone + '_ {
784		mapget::slice_iter(slice)
785	}
786
787	#[inline]
788	unsafe fn get_unchecked(&self, index: usize) -> SmallU<2> {
789		SmallU::<2>::new(self.val() >> (index * 2))
790	}
791
792	#[inline]
793	unsafe fn set_unchecked(&mut self, index: usize, val: SmallU<2>) {
794		let shift = index * 2;
795		let mask = 0b11u8 << shift;
796		*self = SmallU::<4>::new((self.val() & !mask) | (val.val() << shift));
797	}
798
799	#[inline]
800	fn broadcast(val: SmallU<2>) -> Self {
801		// 0bXX -> 0bXXXX
802		let v = val.val();
803		SmallU::<4>::new(v | (v << 2))
804	}
805
806	#[inline]
807	fn from_iter(iter: impl Iterator<Item = SmallU<2>>) -> Self {
808		iter.chain(std::iter::repeat(SmallU::<2>::new(0)))
809			.take(2)
810			.enumerate()
811			.fold(SmallU::<4>::new(0), |mut acc, (i, val)| {
812				acc.set(i, val);
813				acc
814			})
815	}
816}
817
818/// Implements reflexive `Divisible<Self>` for a type (dividing into itself once).
819macro_rules! impl_divisible_self {
820	($($ty:ty),+) => {
821		$(
822			impl Divisible<$ty> for $ty {
823				const LOG_N: usize = 0;
824
825				#[inline]
826				fn value_iter(value: Self) -> impl ExactSizeIterator<Item = $ty> + Send + Clone {
827					std::iter::once(value)
828				}
829
830				#[inline]
831				fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = $ty> + Send + Clone + '_ {
832					std::iter::once(*value)
833				}
834
835				#[inline]
836				fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = $ty> + Send + Clone + '_ {
837					slice.iter().copied()
838				}
839
840				#[inline]
841				unsafe fn get_unchecked(&self, _index: usize) -> $ty {
842					*self
843				}
844
845				#[inline]
846				unsafe fn set_unchecked(&mut self, _index: usize, val: $ty) {
847					*self = val;
848				}
849
850				#[inline]
851				fn broadcast(val: $ty) -> Self {
852					val
853				}
854
855				#[inline]
856				fn from_iter(mut iter: impl Iterator<Item = $ty>) -> Self {
857					iter.next().unwrap_or_else(bytemuck::Zeroable::zeroed)
858				}
859			}
860		)+
861	};
862}
863
864#[allow(unused)]
865pub(crate) use impl_divisible_self;
866
867impl_divisible_self!(u8, u16, u32, u64, u128, SmallU<1>, SmallU<2>, SmallU<4>);
868
869#[cfg(test)]
870mod tests {
871	use super::*;
872	use crate::underlier::small_uint::{U1, U2, U4};
873
874	#[test]
875	fn test_divisible_u8_u4() {
876		let val: u8 = 0x34;
877
878		// Test get - LSB first: nibbles
879		assert_eq!(Divisible::<U4>::get(&val, 0), U4::new(0x4));
880		assert_eq!(Divisible::<U4>::get(&val, 1), U4::new(0x3));
881
882		// Test set
883		let mut modified = val;
884		Divisible::<U4>::set(&mut modified, 0, U4::new(0xF));
885		assert_eq!(modified, 0x3F);
886		let mut modified = val;
887		Divisible::<U4>::set(&mut modified, 1, U4::new(0xA));
888		assert_eq!(modified, 0xA4);
889
890		// Test ref_iter
891		let parts: Vec<U4> = Divisible::<U4>::ref_iter(&val).collect();
892		assert_eq!(parts.len(), 2);
893		assert_eq!(parts[0], U4::new(0x4));
894		assert_eq!(parts[1], U4::new(0x3));
895
896		// Test value_iter
897		let parts: Vec<U4> = Divisible::<U4>::value_iter(val).collect();
898		assert_eq!(parts.len(), 2);
899		assert_eq!(parts[0], U4::new(0x4));
900		assert_eq!(parts[1], U4::new(0x3));
901
902		// Test slice_iter
903		let vals = [0x34u8, 0x56u8];
904		let parts: Vec<U4> = Divisible::<U4>::slice_iter(&vals).collect();
905		assert_eq!(parts.len(), 4);
906		assert_eq!(parts[0], U4::new(0x4));
907		assert_eq!(parts[1], U4::new(0x3));
908		assert_eq!(parts[2], U4::new(0x6));
909		assert_eq!(parts[3], U4::new(0x5));
910	}
911
912	#[test]
913	fn test_divisible_u16_u4() {
914		let val: u16 = 0x1234;
915
916		// Test get - LSB first: nibbles
917		assert_eq!(Divisible::<U4>::get(&val, 0), U4::new(0x4));
918		assert_eq!(Divisible::<U4>::get(&val, 1), U4::new(0x3));
919		assert_eq!(Divisible::<U4>::get(&val, 2), U4::new(0x2));
920		assert_eq!(Divisible::<U4>::get(&val, 3), U4::new(0x1));
921
922		// Test set
923		let mut modified = val;
924		Divisible::<U4>::set(&mut modified, 1, U4::new(0xF));
925		assert_eq!(modified, 0x12F4);
926
927		// Test ref_iter
928		let parts: Vec<U4> = Divisible::<U4>::ref_iter(&val).collect();
929		assert_eq!(parts.len(), 4);
930		assert_eq!(parts[0], U4::new(0x4));
931		assert_eq!(parts[3], U4::new(0x1));
932	}
933
934	#[test]
935	fn test_divisible_u16_u2() {
936		// 0b1011_0010_1101_0011 = 0xB2D3
937		let val: u16 = 0b1011001011010011;
938
939		// Test get - LSB first: 2-bit chunks
940		assert_eq!(Divisible::<U2>::get(&val, 0), U2::new(0b11)); // bits 0-1
941		assert_eq!(Divisible::<U2>::get(&val, 1), U2::new(0b00)); // bits 2-3
942		assert_eq!(Divisible::<U2>::get(&val, 7), U2::new(0b10)); // bits 14-15
943
944		// Test ref_iter
945		let parts: Vec<U2> = Divisible::<U2>::ref_iter(&val).collect();
946		assert_eq!(parts.len(), 8);
947		assert_eq!(parts[0], U2::new(0b11));
948		assert_eq!(parts[7], U2::new(0b10));
949	}
950
951	#[test]
952	fn test_divisible_u16_u1() {
953		// 0b1010_1100_0011_0101 = 0xAC35
954		let val: u16 = 0b1010110000110101;
955
956		// Test get - LSB first: individual bits
957		assert_eq!(Divisible::<U1>::get(&val, 0), U1::new(1)); // bit 0
958		assert_eq!(Divisible::<U1>::get(&val, 1), U1::new(0)); // bit 1
959		assert_eq!(Divisible::<U1>::get(&val, 15), U1::new(1)); // bit 15
960
961		// Test set
962		let mut modified = val;
963		Divisible::<U1>::set(&mut modified, 0, U1::new(0));
964		assert_eq!(modified, 0b1010110000110100);
965
966		// Test ref_iter
967		let parts: Vec<U1> = Divisible::<U1>::ref_iter(&val).collect();
968		assert_eq!(parts.len(), 16);
969		assert_eq!(parts[0], U1::new(1));
970		assert_eq!(parts[15], U1::new(1));
971	}
972
973	#[test]
974	fn test_divisible_u64_u4() {
975		let val: u64 = 0x123456789ABCDEF0;
976
977		// Test get - LSB first: nibbles
978		assert_eq!(Divisible::<U4>::get(&val, 0), U4::new(0x0));
979		assert_eq!(Divisible::<U4>::get(&val, 1), U4::new(0xF));
980		assert_eq!(Divisible::<U4>::get(&val, 15), U4::new(0x1));
981
982		// Test ref_iter
983		let parts: Vec<U4> = Divisible::<U4>::ref_iter(&val).collect();
984		assert_eq!(parts.len(), 16);
985	}
986
987	#[test]
988	fn test_divisible_u32_u8_slice() {
989		let vals: [u32; 2] = [0x04030201, 0x08070605];
990
991		// Test slice_iter
992		let parts: Vec<u8> = Divisible::<u8>::slice_iter(&vals).collect();
993		assert_eq!(parts.len(), 8);
994		// LSB-first ordering within each u32
995		assert_eq!(parts[0], 0x01);
996		assert_eq!(parts[1], 0x02);
997		assert_eq!(parts[2], 0x03);
998		assert_eq!(parts[3], 0x04);
999		assert_eq!(parts[4], 0x05);
1000		assert_eq!(parts[5], 0x06);
1001		assert_eq!(parts[6], 0x07);
1002		assert_eq!(parts[7], 0x08);
1003	}
1004
1005	#[test]
1006	fn test_broadcast_u32_u8() {
1007		let result: u32 = Divisible::<u8>::broadcast(0xAB);
1008		assert_eq!(result, 0xABABABAB);
1009	}
1010
1011	#[test]
1012	fn test_broadcast_u64_u16() {
1013		let result: u64 = Divisible::<u16>::broadcast(0x1234);
1014		assert_eq!(result, 0x1234123412341234);
1015	}
1016
1017	#[test]
1018	fn test_broadcast_u128_u32() {
1019		let result: u128 = Divisible::<u32>::broadcast(0xDEADBEEF);
1020		assert_eq!(result, 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF);
1021	}
1022
1023	#[test]
1024	fn test_broadcast_u8_u4() {
1025		let result: u8 = Divisible::<U4>::broadcast(U4::new(0x5));
1026		assert_eq!(result, 0x55);
1027	}
1028
1029	#[test]
1030	fn test_broadcast_u16_u4() {
1031		let result: u16 = Divisible::<U4>::broadcast(U4::new(0xA));
1032		assert_eq!(result, 0xAAAA);
1033	}
1034
1035	#[test]
1036	fn test_broadcast_u8_u2() {
1037		let result: u8 = Divisible::<U2>::broadcast(U2::new(0b11));
1038		assert_eq!(result, 0xFF);
1039		let result: u8 = Divisible::<U2>::broadcast(U2::new(0b01));
1040		assert_eq!(result, 0x55);
1041	}
1042
1043	#[test]
1044	fn test_broadcast_u8_u1() {
1045		let result: u8 = Divisible::<U1>::broadcast(U1::new(0));
1046		assert_eq!(result, 0x00);
1047		let result: u8 = Divisible::<U1>::broadcast(U1::new(1));
1048		assert_eq!(result, 0xFF);
1049	}
1050
1051	#[test]
1052	fn test_broadcast_smallu2_from_smallu1() {
1053		let result: SmallU<2> = Divisible::<SmallU<1>>::broadcast(SmallU::<1>::new(0));
1054		assert_eq!(result.val(), 0b00);
1055		let result: SmallU<2> = Divisible::<SmallU<1>>::broadcast(SmallU::<1>::new(1));
1056		assert_eq!(result.val(), 0b11);
1057	}
1058
1059	#[test]
1060	fn test_broadcast_smallu4_from_smallu1() {
1061		let result: SmallU<4> = Divisible::<SmallU<1>>::broadcast(SmallU::<1>::new(0));
1062		assert_eq!(result.val(), 0b0000);
1063		let result: SmallU<4> = Divisible::<SmallU<1>>::broadcast(SmallU::<1>::new(1));
1064		assert_eq!(result.val(), 0b1111);
1065	}
1066
1067	#[test]
1068	fn test_broadcast_smallu4_from_smallu2() {
1069		let result: SmallU<4> = Divisible::<SmallU<2>>::broadcast(SmallU::<2>::new(0b10));
1070		assert_eq!(result.val(), 0b1010);
1071	}
1072
1073	#[test]
1074	fn test_broadcast_reflexive() {
1075		let result: u64 = Divisible::<u64>::broadcast(0x123456789ABCDEF0);
1076		assert_eq!(result, 0x123456789ABCDEF0);
1077	}
1078
1079	#[test]
1080	fn test_from_iter_full() {
1081		let result: u32 = Divisible::<u8>::from_iter([0x01, 0x02, 0x03, 0x04].into_iter());
1082		assert_eq!(result, 0x04030201);
1083	}
1084
1085	#[test]
1086	fn test_from_iter_partial() {
1087		// Only 2 elements, remaining should be 0
1088		let result: u32 = Divisible::<u8>::from_iter([0xAB, 0xCD].into_iter());
1089		assert_eq!(result, 0x0000CDAB);
1090	}
1091
1092	#[test]
1093	fn test_from_iter_empty() {
1094		let result: u32 = Divisible::<u8>::from_iter(std::iter::empty());
1095		assert_eq!(result, 0);
1096	}
1097
1098	#[test]
1099	fn test_from_iter_excess() {
1100		// More than N elements, only first 4 should be consumed
1101		let result: u32 =
1102			Divisible::<u8>::from_iter([0x01, 0x02, 0x03, 0x04, 0x05, 0x06].into_iter());
1103		assert_eq!(result, 0x04030201);
1104	}
1105
1106	#[test]
1107	fn test_from_iter_u64_u16() {
1108		let result: u64 = Divisible::<u16>::from_iter([0x1234, 0x5678, 0x9ABC].into_iter());
1109		// Only 3 elements provided, 4th should be 0
1110		assert_eq!(result, 0x0000_9ABC_5678_1234);
1111	}
1112
1113	#[test]
1114	fn test_from_iter_smallu() {
1115		let result: u8 = Divisible::<U4>::from_iter([U4::new(0xA), U4::new(0xB)].into_iter());
1116		assert_eq!(result, 0xBA);
1117	}
1118}