use core::{
convert::Infallible,
mem::{self, MaybeUninit},
};
use crate::{
init::{Init, InitError, InitPin, InitPinResult, InitResult, Initializer, IntoInitPin},
owned::Own,
pin::DropSlot,
uninit::Uninit,
};
#[inline]
fn maybe_uninit_slice<T, const N: usize>(m: &mut MaybeUninit<[T; N]>) -> &mut [MaybeUninit<T>] {
unsafe { &mut *(m.as_mut_ptr() as *mut [MaybeUninit<T>; N]) }
}
#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq)]
#[error("slice initialization error")]
pub struct SliceError;
trait SpecInitSlice<T> {
fn init_slice(self, place: Uninit<'_, [T]>) -> InitResult<'_, [T], SliceError>;
fn init_array<const N: usize>(
self,
place: Uninit<'_, [T; N]>,
) -> InitResult<'_, [T; N], SliceError>;
}
impl<T: Clone> SpecInitSlice<T> for &[T] {
default fn init_slice(self, mut place: Uninit<'_, [T]>) -> InitResult<'_, [T], SliceError> {
if place.len() != self.len() {
return Err(InitError { error: SliceError, place });
}
place.write_clone_of_slice(self);
Ok(unsafe { place.assume_init() })
}
default fn init_array<const N: usize>(
self,
mut place: Uninit<'_, [T; N]>,
) -> InitResult<'_, [T; N], SliceError> {
if N != self.len() {
return Err(InitError { error: SliceError, place });
}
maybe_uninit_slice(&mut place).write_clone_of_slice(self);
Ok(unsafe { place.assume_init() })
}
}
impl<T: Copy> SpecInitSlice<T> for &[T] {
fn init_slice(self, mut place: Uninit<'_, [T]>) -> InitResult<'_, [T], SliceError> {
if place.len() != self.len() {
return Err(InitError { error: SliceError, place });
}
place.write_copy_of_slice(self);
Ok(unsafe { place.assume_init() })
}
fn init_array<const N: usize>(
self,
mut place: Uninit<'_, [T; N]>,
) -> InitResult<'_, [T; N], SliceError> {
if N != self.len() {
return Err(InitError { error: SliceError, place });
}
maybe_uninit_slice(&mut place).write_copy_of_slice(self);
Ok(unsafe { place.assume_init() })
}
}
#[derive(Debug, PartialEq)]
pub struct Slice<'a, T>(&'a [T]);
impl<T> Initializer for Slice<'_, T> {
type Error = SliceError;
}
impl<T: Clone> InitPin<[T]> for Slice<'_, T> {
#[inline]
fn init_pin<'a, 'b>(
self,
place: Uninit<'a, [T]>,
slot: DropSlot<'a, 'b, [T]>,
) -> InitPinResult<'a, 'b, [T], SliceError> {
match self.0.init_slice(place) {
Ok(own) => Ok(Own::into_pin(own, slot)),
Err(err) => Err(err.into_pin(slot)),
}
}
}
impl<T: Clone> Init<[T]> for Slice<'_, T> {
#[inline]
fn init(self, place: Uninit<'_, [T]>) -> InitResult<'_, [T], SliceError> {
self.0.init_slice(place)
}
}
impl<T: Clone, const N: usize> InitPin<[T; N]> for Slice<'_, T> {
#[inline]
fn init_pin<'a, 'b>(
self,
place: Uninit<'a, [T; N]>,
slot: DropSlot<'a, 'b, [T; N]>,
) -> InitPinResult<'a, 'b, [T; N], SliceError> {
match self.0.init_array(place) {
Ok(own) => Ok(Own::into_pin(own, slot)),
Err(err) => Err(err.into_pin(slot)),
}
}
}
impl<T: Clone, const N: usize> Init<[T; N]> for Slice<'_, T> {
#[inline]
fn init(self, place: Uninit<'_, [T; N]>) -> InitResult<'_, [T; N], SliceError> {
self.0.init_array(place)
}
}
#[inline]
pub const fn slice<T: Clone>(s: &[T]) -> Slice<'_, T> {
Slice(s)
}
impl<'a, T: Clone> IntoInitPin<[T], Slice<'a, T>> for &'a [T] {
type Init = Slice<'a, T>;
type Error = SliceError;
#[inline]
fn into_init(self) -> Self::Init {
Slice(self)
}
}
impl<'a, T: Clone, const N: usize> IntoInitPin<[T; N], Slice<'a, T>> for &'a [T] {
type Init = Slice<'a, T>;
type Error = SliceError;
#[inline]
fn into_init(self) -> Self::Init {
Slice(self)
}
}
#[derive(Debug, PartialEq)]
pub struct Str<'a>(&'a str);
impl Initializer for Str<'_> {
type Error = SliceError;
}
impl InitPin<str> for Str<'_> {
fn init_pin<'a, 'b>(
self,
mut place: Uninit<'a, str>,
slot: DropSlot<'a, 'b, str>,
) -> InitPinResult<'a, 'b, str, SliceError> {
if place.len() != self.0.len() {
return Err(InitError { error: SliceError, place }.into_pin(slot));
}
let src = unsafe { mem::transmute::<&[u8], &[MaybeUninit<u8>]>(self.0.as_bytes()) };
place.copy_from_slice(src);
Ok(unsafe { place.assume_init_pin(slot) })
}
}
impl Init<str> for Str<'_> {
fn init(self, mut place: Uninit<'_, str>) -> InitResult<'_, str, SliceError> {
if place.len() != self.0.len() {
return Err(InitError { error: SliceError, place });
}
let src = unsafe { mem::transmute::<&[u8], &[MaybeUninit<u8>]>(self.0.as_bytes()) };
place.copy_from_slice(src);
Ok(unsafe { place.assume_init() })
}
}
#[inline]
pub const fn str(s: &str) -> Str<'_> {
Str(s)
}
impl<'b> IntoInitPin<str, Str<'b>> for &'b str {
type Init = Str<'b>;
type Error = SliceError;
#[inline]
fn into_init(self) -> Self::Init {
Str(self)
}
}
#[derive(Debug, PartialEq)]
pub struct Repeat<T>(T);
impl<T> Initializer for Repeat<T> {
type Error = Infallible;
}
impl<T: Clone> InitPin<[T]> for Repeat<T> {
fn init_pin<'a, 'b>(
self,
mut place: Uninit<'a, [T]>,
slot: DropSlot<'a, 'b, [T]>,
) -> InitPinResult<'a, 'b, [T], Infallible> {
place.write_filled(self.0);
Ok(unsafe { place.assume_init_pin(slot) })
}
}
impl<T: Clone> Init<[T]> for Repeat<T> {
fn init(self, mut place: Uninit<'_, [T]>) -> InitResult<'_, [T], Infallible> {
place.write_filled(self.0);
Ok(unsafe { place.assume_init() })
}
}
impl<T: Clone, const N: usize> InitPin<[T; N]> for Repeat<T> {
fn init_pin<'a, 'b>(
self,
mut place: Uninit<'a, [T; N]>,
slot: DropSlot<'a, 'b, [T; N]>,
) -> InitPinResult<'a, 'b, [T; N], Infallible> {
maybe_uninit_slice(&mut place).write_filled(self.0);
Ok(unsafe { place.assume_init_pin(slot) })
}
}
impl<T: Clone, const N: usize> Init<[T; N]> for Repeat<T> {
fn init(self, mut place: Uninit<'_, [T; N]>) -> InitResult<'_, [T; N], Infallible> {
maybe_uninit_slice(&mut place).write_filled(self.0);
Ok(unsafe { place.assume_init() })
}
}
#[inline]
pub const fn repeat<T: Clone>(value: T) -> Repeat<T> {
Repeat(value)
}
#[derive(Debug, PartialEq)]
pub struct RepeatWith<F>(F);
impl<F> Initializer for RepeatWith<F> {
type Error = Infallible;
}
impl<T, F> InitPin<[T]> for RepeatWith<F>
where
F: Fn(usize) -> T,
{
fn init_pin<'a, 'b>(
self,
mut place: Uninit<'a, [T]>,
slot: DropSlot<'a, 'b, [T]>,
) -> InitPinResult<'a, 'b, [T], Infallible> {
place.write_with(self.0);
Ok(unsafe { place.assume_init_pin(slot) })
}
}
impl<T, F> Init<[T]> for RepeatWith<F>
where
F: Fn(usize) -> T,
{
fn init(self, mut place: Uninit<'_, [T]>) -> InitResult<'_, [T], Infallible> {
place.write_with(self.0);
Ok(unsafe { place.assume_init() })
}
}
impl<T, F, const N: usize> InitPin<[T; N]> for RepeatWith<F>
where
F: Fn(usize) -> T,
{
fn init_pin<'a, 'b>(
self,
mut place: Uninit<'a, [T; N]>,
slot: DropSlot<'a, 'b, [T; N]>,
) -> InitPinResult<'a, 'b, [T; N], Infallible> {
maybe_uninit_slice(&mut place).write_with(self.0);
Ok(unsafe { place.assume_init_pin(slot) })
}
}
impl<T, F, const N: usize> Init<[T; N]> for RepeatWith<F>
where
F: Fn(usize) -> T,
{
fn init(self, mut place: Uninit<'_, [T; N]>) -> InitResult<'_, [T; N], Infallible> {
maybe_uninit_slice(&mut place).write_with(self.0);
Ok(unsafe { place.assume_init() })
}
}
#[inline]
pub const fn repeat_with<T, F>(f: F) -> RepeatWith<F>
where
F: Fn(usize) -> T,
{
RepeatWith(f)
}