Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
use crate::{
Array, ArraySize,
typenum::{Prod, Quot, U0, Unsigned},
};
use core::{
mem::ManuallyDrop,
ops::{Div, Mul, Rem},
ptr,
};
/// Defines a sequence of sequences that can be merged into a bigger overall sequence.
pub trait Flatten<T, M: ArraySize> {
/// Size of the output array.
type OutputSize: ArraySize;
/// Flatten array.
fn flatten(self) -> Array<T, Self::OutputSize>;
}
impl<T, N, M> Flatten<T, Prod<M, N>> for Array<Array<T, M>, N>
where
N: ArraySize,
M: ArraySize + Mul<N>,
Prod<M, N>: ArraySize,
{
type OutputSize = Prod<M, N>;
// SAFETY: this is the reverse transmute between [T; K*N] and [[T; K], M], which is guaranteed
// to be safe by the Rust memory layout of these types.
fn flatten(self) -> Array<T, Self::OutputSize> {
let whole = ManuallyDrop::new(self);
unsafe { ptr::read(whole.as_ptr().cast()) }
}
}
/// Defines a sequence that can be split into a sequence of smaller sequences of uniform size.
pub trait Unflatten<M>
where
M: ArraySize,
{
/// Part of the array we're decomposing into.
type Part;
/// Unflatten array into `Self::Part` chunks.
fn unflatten(self) -> Array<Self::Part, M>;
}
impl<T, N, M> Unflatten<M> for Array<T, N>
where
N: ArraySize + Div<M> + Rem<M, Output = U0>,
M: ArraySize,
Quot<N, M>: ArraySize,
{
type Part = Array<T, Quot<N, M>>;
// SAFETY: this is doing the same thing as what is done in `Array::split`.
// Basically, this is doing transmute between [T; K*N] and [[T; K], M], which is guaranteed to
// be safe by the Rust memory layout of these types.
fn unflatten(self) -> Array<Self::Part, M> {
let part_size = Quot::<N, M>::USIZE;
let whole = ManuallyDrop::new(self);
Array::from_fn(|i| unsafe {
let offset = i.checked_mul(part_size).expect("overflow");
ptr::read(whole.as_ptr().add(offset).cast())
})
}
}
impl<'a, T, N, M> Unflatten<M> for &'a Array<T, N>
where
N: ArraySize + Div<M> + Rem<M, Output = U0>,
M: ArraySize,
Quot<N, M>: ArraySize,
{
type Part = &'a Array<T, Quot<N, M>>;
// SAFETY: this is doing the same thing as what is done in `Array::split`.
// Basically, this is doing transmute between [T; K*N] and [[T; K], M], which is guaranteed to
// be safe by the Rust memory layout of these types.
fn unflatten(self) -> Array<Self::Part, M> {
let part_size = Quot::<N, M>::USIZE;
let mut ptr: *const T = self.as_ptr();
Array::from_fn(|_i| unsafe {
let part = &*(ptr.cast());
ptr = ptr.add(part_size);
part
})
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
Array,
sizes::{U2, U5},
};
#[test]
fn flatten() {
let flat: Array<u8, _> = Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let unflat2: Array<Array<u8, _>, _> = Array([
Array([1, 2]),
Array([3, 4]),
Array([5, 6]),
Array([7, 8]),
Array([9, 10]),
]);
let unflat5: Array<Array<u8, _>, _> =
Array([Array([1, 2, 3, 4, 5]), Array([6, 7, 8, 9, 10])]);
// Flatten
let actual = unflat2.flatten();
assert_eq!(flat, actual);
let actual = unflat5.flatten();
assert_eq!(flat, actual);
// Unflatten
let actual: Array<Array<u8, U2>, U5> = flat.unflatten();
assert_eq!(unflat2, actual);
let actual: Array<Array<u8, U5>, U2> = flat.unflatten();
assert_eq!(unflat5, actual);
// Unflatten on references
let actual: Array<&Array<u8, U2>, U5> = (&flat).unflatten();
for (i, part) in actual.iter().enumerate() {
assert_eq!(&unflat2[i], *part);
}
let actual: Array<&Array<u8, U5>, U2> = (&flat).unflatten();
for (i, part) in actual.iter().enumerate() {
assert_eq!(&unflat5[i], *part);
}
}
}
+106
View File
@@ -0,0 +1,106 @@
//! Support for constructing arrays using a provided generator function.
use crate::{Array, ArraySize};
use core::{
convert::Infallible,
mem::{self, MaybeUninit},
ptr,
};
impl<T, U> Array<T, U>
where
U: ArraySize,
{
/// Create array where each array element `T` is returned by the `f` call.
#[inline]
pub fn from_fn(mut f: impl FnMut(usize) -> T) -> Self {
let Ok(ret) = Self::try_from_fn::<Infallible>(|n| Ok(f(n)));
ret
}
/// Create array fallibly where each array element `T` is returned by the `f` call, or return
/// an error if any are encountered.
///
/// # Errors
///
/// Propagates the `E` type returned from the provided `F` in the event of error.
pub fn try_from_fn<E>(f: impl FnMut(usize) -> Result<T, E>) -> Result<Self, E> {
let mut array = Array::<MaybeUninit<T>, U>::uninit();
try_from_fn_erased(array.0.as_mut(), f)?;
// SAFETY: if we got here, every element of the array was initialized
Ok(unsafe { array.assume_init() })
}
}
/// Fills a `MaybeUninit` slice using the given fallible generator function.
///
/// Using a slice avoids monomorphizing for each array size.
#[inline]
fn try_from_fn_erased<T, E, F>(buffer: &mut [MaybeUninit<T>], mut f: F) -> Result<(), E>
where
F: FnMut(usize) -> Result<T, E>,
{
let mut guard = Guard {
array_mut: buffer,
initialized: 0,
};
while guard.initialized < guard.array_mut.len() {
let item = f(guard.initialized)?;
// SAFETY: the loop's condition ensures we won't push too many items
unsafe { guard.push_unchecked(item) };
}
mem::forget(guard);
Ok(())
}
/// Drop guard which tracks the total number of initialized items, and handles dropping them in
/// the event a panic occurs.
///
/// Use `mem::forget` when the array has been fully constructed.
struct Guard<'a, T> {
/// Array being constructed.
array_mut: &'a mut [MaybeUninit<T>],
/// Number of items in the array which have been initialized.
initialized: usize,
}
impl<T> Guard<'_, T> {
/// Push an item onto the guard, writing to its `MaybeUninit` slot and incrementing the
/// counter of the number of initialized items.
///
/// # Safety
///
/// This can only be called n-times for as many elements are in the slice.
#[inline]
pub unsafe fn push_unchecked(&mut self, item: T) {
// SAFETY: the `initialized` counter tracks the number of initialized items, so as long as
// this is called the correct number of times for the array size writes will always be
// in-bounds and to an uninitialized slot in the array.
unsafe {
self.array_mut
.get_unchecked_mut(self.initialized)
.write(item);
self.initialized = self.initialized.saturating_add(1);
}
}
}
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
debug_assert!(self.initialized <= self.array_mut.len());
// SAFETY: the loop only iterates over initialized items
unsafe {
let p: *mut T = self.array_mut.as_mut_ptr().cast();
for i in 0..self.initialized {
ptr::drop_in_place(p.add(i));
}
}
}
}
+132
View File
@@ -0,0 +1,132 @@
//! Support for constructing arrays using a provided iterator function and other iterator-related
//! functionality.
use crate::{Array, ArraySize};
use core::{
fmt,
slice::{Iter, IterMut},
};
/// Couldn't construct an array from an iterator because the number of items in the iterator
/// didn't match the array size.
#[derive(Clone, Copy, Debug)]
pub struct TryFromIteratorError;
impl fmt::Display for TryFromIteratorError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("iterator did not contain the correct number of items for the array size")
}
}
impl core::error::Error for TryFromIteratorError {}
impl<T, U> Array<T, U>
where
U: ArraySize,
{
/// Construct an array from the given iterator, returning [`TryFromIteratorError`] in the event
/// that the number of items in the iterator does not match the array size.
///
/// # Errors
///
/// Returns [`TryFromIteratorError`] in the event the iterator does not return a number of
/// items which is exactly equal to the array size.
pub fn try_from_iter<I: IntoIterator<Item = T>>(iter: I) -> Result<Self, TryFromIteratorError> {
let mut iter = iter.into_iter();
let ret = Self::try_from_fn(|_| iter.next().ok_or(TryFromIteratorError))?;
match iter.next() {
None => Ok(ret),
Some(_) => Err(TryFromIteratorError),
}
}
}
impl<T, U> FromIterator<T> for Array<T, U>
where
U: ArraySize,
{
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut iter = iter.into_iter();
let ret = Self::from_fn(|_| {
iter.next()
.expect("iterator should have enough items to fill array")
});
assert!(
iter.next().is_none(),
"too many items in iterator to fit in array"
);
ret
}
}
impl<T, U> IntoIterator for Array<T, U>
where
U: ArraySize,
{
type Item = T;
type IntoIter = <U::ArrayType<T> as IntoIterator>::IntoIter;
/// Creates a consuming iterator, that is, one that moves each value out of the array (from
/// start to end).
///
/// The array cannot be used after calling this unless `T` implements `Copy`, so the whole
/// array is copied.
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T, U> IntoIterator for &'a Array<T, U>
where
U: ArraySize,
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
#[inline]
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T, U> IntoIterator for &'a mut Array<T, U>
where
U: ArraySize,
{
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
#[inline]
fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
#[cfg(test)]
mod tests {
use crate::{Array, sizes::U3};
#[test]
fn mut_array_ref_into_iterator() {
let array_ref: &mut Array<u8, U3> = &mut Array([1, 2, 3]);
let mut iter = array_ref.into_iter();
for i in 1..=3 {
assert_eq!(iter.next().copied(), Some(i));
}
assert_eq!(iter.next(), None);
}
#[cfg(feature = "alloc")]
#[test]
fn display_try_from_iterator_error() {
use super::TryFromIteratorError;
use alloc::string::ToString;
let _ = TryFromIteratorError.to_string();
}
}
File diff suppressed because it is too large Load Diff
+93
View File
@@ -0,0 +1,93 @@
//! Support for serializing and deserializing `Array` using `serde`.
use crate::{Array, ArraySize};
use core::{fmt, marker::PhantomData};
use serde::{
de::{self, Deserialize, Deserializer, SeqAccess, Visitor},
ser::{Serialize, SerializeTuple, Serializer},
};
impl<'de, T, U> Deserialize<'de> for Array<T, U>
where
T: Deserialize<'de>,
U: ArraySize,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
struct ArrayVisitor<T> {
element: PhantomData<T>,
}
impl<'de, T, U> Visitor<'de> for ArrayVisitor<Array<T, U>>
where
T: Deserialize<'de>,
U: ArraySize,
{
type Value = Array<T, U>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "an array of length {}", U::USIZE)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Array<T, U>, A::Error>
where
A: SeqAccess<'de>,
{
Array::<T, U>::try_from_fn(|i| {
seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(i, &self))
})
}
}
let visitor = ArrayVisitor {
element: PhantomData,
};
deserializer.deserialize_tuple(U::USIZE, visitor)
}
}
impl<T, U> Serialize for Array<T, U>
where
T: Serialize,
U: ArraySize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_tuple(U::USIZE)?;
for elem in self {
seq.serialize_element(elem)?;
}
seq.end()
}
}
#[cfg(test)]
mod tests {
use crate::{Array, sizes::U3};
type A = Array<u8, U3>;
#[test]
#[cfg(feature = "alloc")]
fn expecting() {
use alloc::string::ToString;
let err = serde_json::from_str::<A>("true").unwrap_err();
assert!(err.to_string().contains("expected an array of length 3"));
}
#[test]
fn round_trip() {
let example: A = Array([1, 2, 3]);
let s = serde_json::to_string(&example).unwrap();
let deserialized: A = serde_json::from_str(&s).unwrap();
assert_eq!(example, deserialized);
}
}
File diff suppressed because it is too large Load Diff
+289
View File
@@ -0,0 +1,289 @@
//! Trait definitions.
use crate::Array;
use core::{
borrow::{Borrow, BorrowMut},
fmt::Debug,
ops::{Index, IndexMut, Range},
};
use typenum::Unsigned;
/// Trait which associates a [`usize`] size and `ArrayType` with a
/// `typenum`-provided [`Unsigned`] integer.
///
/// # Safety
///
/// `ArrayType` MUST be an array with a number of elements exactly equal to
/// [`Unsigned::USIZE`]. Breaking this requirement will cause undefined behavior.
///
/// NOTE: This trait is effectively sealed and can not be implemented by third-party crates.
/// It is implemented only for a number of types defined in [`typenum::consts`].
#[diagnostic::on_unimplemented(note = "size may not be supported (see RustCrypto/hybrid-array#66)")]
pub unsafe trait ArraySize: Unsigned + Debug {
/// Array type which corresponds to this size.
///
/// This is always defined to be `[T; N]` where `N` is the same as
/// [`ArraySize::USIZE`][`typenum::Unsigned::USIZE`].
type ArrayType<T>: AssocArraySize<Size = Self>
+ AsRef<[T]>
+ AsMut<[T]>
+ Borrow<[T]>
+ BorrowMut<[T]>
+ From<Array<T, Self>>
+ Index<usize>
+ Index<Range<usize>>
+ IndexMut<usize>
+ IndexMut<Range<usize>>
+ Into<Array<T, Self>>
+ IntoIterator<Item = T>;
}
/// Associates an [`ArraySize`] with a given type. Can be used to accept `[T; N]` const generic
/// arguments and convert to [`Array`] internally.
///
/// This trait is also the magic glue that makes the [`ArrayN`][`crate::ArrayN`] type alias work.
///
/// # Example
///
/// ```
/// use hybrid_array::{ArrayN, AssocArraySize};
///
/// pub fn example<const N: usize>(bytes: &[u8; N])
/// where
/// [u8; N]: AssocArraySize + AsRef<ArrayN<u8, N>>
/// {
/// // _arrayn is ArrayN<u8, N>
/// let _arrayn = bytes.as_ref();
/// }
/// ```
pub trait AssocArraySize: Sized {
/// Size of an array type, expressed as a [`typenum`]-based [`ArraySize`].
type Size: ArraySize;
}
impl<T, U> AssocArraySize for Array<T, U>
where
U: ArraySize,
{
type Size = U;
}
/// Obtain an `&Array` reference for a given type.
///
/// This provides functionality equivalent to `AsRef<Array>` or `Borrow<Array>`, but is deliberately
/// implemented as its own trait both so it can leverage [`AssocArraySize`] to determine the
/// array size, and also to avoid inference problems that occur when third party impls of traits
/// like [`AsRef`] and [`Borrow`] are added to `[T; N]`.
///
/// # Usage with `[T; N]`
///
/// ```
/// use hybrid_array::{Array, ArraySize, AsArrayRef};
///
/// pub fn getn_hybrid<T, U: ArraySize>(arr: &Array<T, U>, n: usize) -> &T {
/// &arr[2]
/// }
///
/// pub fn getn_generic<T, const N: usize>(arr: &[T; N], n: usize) -> &T
/// where
/// [T; N]: AsArrayRef<T>
/// {
/// getn_hybrid(arr.as_array_ref(), n)
/// }
///
/// let array = [0u8, 1, 2, 3];
/// let x = getn_generic(&array, 2);
/// assert_eq!(x, &2);
/// ```
pub trait AsArrayRef<T>: AssocArraySize {
/// Converts this type into an immutable [`Array`] reference.
fn as_array_ref(&self) -> &Array<T, Self::Size>;
}
/// Obtain a `&mut Array` reference for a given type.
///
/// Companion trait to [`AsArrayRef`] for mutable references, equivalent to [`AsMut`] or
/// [`BorrowMut`].
pub trait AsArrayMut<T>: AsArrayRef<T> {
/// Converts this type into a mutable [`Array`] reference.
fn as_array_mut(&mut self) -> &mut Array<T, Self::Size>;
}
impl<T, U> AsArrayRef<T> for Array<T, U>
where
U: ArraySize,
{
fn as_array_ref(&self) -> &Self {
self
}
}
impl<T, U> AsArrayMut<T> for Array<T, U>
where
U: ArraySize,
{
fn as_array_mut(&mut self) -> &mut Self {
self
}
}
impl<T, U, const N: usize> AsArrayRef<T> for [T; N]
where
Self: AssocArraySize<Size = U>,
U: ArraySize<ArrayType<T> = Self>,
{
fn as_array_ref(&self) -> &Array<T, U> {
self.into()
}
}
impl<T, U, const N: usize> AsArrayMut<T> for [T; N]
where
Self: AssocArraySize<Size = U>,
U: ArraySize<ArrayType<T> = Self>,
{
fn as_array_mut(&mut self) -> &mut Array<T, U> {
self.into()
}
}
/// Extension trait for `[T]` providing methods for working with [`Array`].
pub trait SliceExt<T>: sealed::Sealed {
/// Get a reference to an array from a slice, if the slice is exactly the size of the array.
///
/// Returns `None` if the slice's length is not exactly equal to the array size.
fn as_hybrid_array<U: ArraySize>(&self) -> Option<&Array<T, U>>;
/// Get a mutable reference to an array from a slice, if the slice is exactly the size of the
/// array.
///
/// Returns `None` if the slice's length is not exactly equal to the array size.
fn as_mut_hybrid_array<U: ArraySize>(&mut self) -> Option<&mut Array<T, U>>;
/// Splits the shared slice into a slice of `U`-element arrays, starting at the beginning
/// of the slice, and a remainder slice with length strictly less than `U`.
///
/// # Panics
/// If `U` is 0.
fn as_hybrid_chunks<U: ArraySize>(&self) -> (&[Array<T, U>], &[T]);
/// Splits the exclusive slice into a slice of `U`-element arrays, starting at the beginning
/// of the slice, and a remainder slice with length strictly less than `U`.
///
/// # Panics
/// If `U` is 0.
fn as_hybrid_chunks_mut<U: ArraySize>(&mut self) -> (&mut [Array<T, U>], &mut [T]);
}
impl<T> SliceExt<T> for [T] {
fn as_hybrid_array<U: ArraySize>(&self) -> Option<&Array<T, U>> {
Array::slice_as_array(self)
}
fn as_mut_hybrid_array<U: ArraySize>(&mut self) -> Option<&mut Array<T, U>> {
Array::slice_as_mut_array(self)
}
fn as_hybrid_chunks<U: ArraySize>(&self) -> (&[Array<T, U>], &[T]) {
Array::slice_as_chunks(self)
}
fn as_hybrid_chunks_mut<U: ArraySize>(&mut self) -> (&mut [Array<T, U>], &mut [T]) {
Array::slice_as_chunks_mut(self)
}
}
impl<T> sealed::Sealed for [T] {}
mod sealed {
pub trait Sealed {}
}
#[cfg(test)]
mod tests {
use super::{AsArrayMut, AsArrayRef, SliceExt};
use crate::{
Array,
sizes::{U2, U3},
};
type A = Array<u8, U2>;
#[test]
fn core_as_array_ref() {
assert_eq!([1, 2, 3].as_array_ref(), &Array([1, 2, 3]));
}
#[test]
fn core_as_array_mut() {
assert_eq!([1, 2, 3].as_array_mut(), &Array([1, 2, 3]));
}
#[test]
fn hybrid_as_array_ref() {
assert_eq!(A::from([1, 2]).as_array_ref(), &Array([1, 2]));
}
#[test]
fn hybrid_as_array_mut() {
assert_eq!(A::from([1, 2]).as_array_mut(), &Array([1, 2]));
}
#[test]
fn slice_as_hybrid_array() {
assert_eq!([1, 2].as_hybrid_array::<U3>(), None);
assert_eq!([1, 2, 3].as_hybrid_array::<U3>(), Some(&Array([1, 2, 3])));
assert_eq!([1, 2, 3, 4].as_hybrid_array::<U3>(), None);
}
#[test]
fn slice_as_mut_hybrid_array() {
assert_eq!([1, 2].as_mut_hybrid_array::<U3>(), None);
assert_eq!(
[1, 2, 3].as_mut_hybrid_array::<U3>(),
Some(&mut Array([1, 2, 3]))
);
assert_eq!([1, 2, 3, 4].as_mut_hybrid_array::<U3>(), None);
}
#[test]
fn slice_as_hybrid_chunks() {
let (slice_empty, rem_empty): (&[A], &[u8]) = [].as_hybrid_chunks::<U2>();
assert!(slice_empty.is_empty());
assert!(rem_empty.is_empty());
let (slice_one, rem_one) = [1].as_hybrid_chunks::<U2>();
assert!(slice_one.is_empty());
assert_eq!(rem_one, &[1]);
let (slice_aligned, rem_aligned) = [1u8, 2].as_hybrid_chunks::<U2>();
assert_eq!(slice_aligned, &[Array([1u8, 2])]);
assert_eq!(rem_aligned, b"");
let (slice_unaligned, rem_unaligned) = [1u8, 2, 3].as_hybrid_chunks::<U2>();
assert_eq!(slice_unaligned, &[Array([1u8, 2])]);
assert_eq!(rem_unaligned, &[3]);
}
#[test]
fn slice_as_hybrid_chunks_mut() {
let (slice_empty, rem_empty): (&mut [A], &mut [u8]) = [].as_hybrid_chunks_mut::<U2>();
assert!(slice_empty.is_empty());
assert!(rem_empty.is_empty());
let mut arr1 = [1];
let (slice_one, rem_one) = arr1.as_hybrid_chunks_mut::<U2>();
assert!(slice_one.is_empty());
assert_eq!(rem_one, &[1]);
let mut arr2 = [1u8, 2];
let (slice_aligned, rem_aligned) = arr2.as_hybrid_chunks_mut::<U2>();
assert_eq!(slice_aligned, &mut [Array([1u8, 2])]);
assert_eq!(rem_aligned, b"");
let mut arr3 = [1u8, 2, 3];
let (slice_unaligned, rem_unaligned) = arr3.as_hybrid_chunks_mut::<U2>();
assert_eq!(slice_unaligned, &mut [Array([1u8, 2])]);
assert_eq!(rem_unaligned, &mut [3]);
}
}