use core::cmp;
use core::fmt;
use core::marker;
use core::mem;
use core::ptr;
use audio_core::{Channel, ChannelMut};
#[macro_use]
mod macros;
#[cfg(test)]
mod tests;
#[inline(always)]
fn size_from_ptr<T>(_: *const T) -> usize {
mem::size_of::<T>()
}
interleaved_channel!('a, T, const, InterleavedChannel, align_iterable_ref);
interleaved_channel!('a, T, mut, InterleavedChannelMut, align_iterable_mut);
comparisons!({'a, T}, InterleavedChannel<'a, T>, InterleavedChannelMut<'a, T>);
comparisons!({'a, T}, InterleavedChannelMut<'a, T>, InterleavedChannel<'a, T>);
slice_comparisons!({'a, T, const N: usize}, InterleavedChannel<'a, T>, [T; N]);
slice_comparisons!({'a, T}, InterleavedChannel<'a, T>, [T]);
slice_comparisons!({'a, T}, InterleavedChannel<'a, T>, &[T]);
slice_comparisons!(#[cfg(feature = "std")] {'a, T}, InterleavedChannel<'a, T>, Vec<T>);
slice_comparisons!({'a, T, const N: usize}, InterleavedChannelMut<'a, T>, [T; N]);
slice_comparisons!({'a, T}, InterleavedChannelMut<'a, T>, [T]);
slice_comparisons!({'a, T}, InterleavedChannelMut<'a, T>, &[T]);
slice_comparisons!(#[cfg(feature = "std")] {'a, T}, InterleavedChannelMut<'a, T>, Vec<T>);
pub struct InterleavedChannel<'a, T> {
ptr: ptr::NonNull<T>,
end: *const T,
step: usize,
_marker: marker::PhantomData<&'a [T]>,
}
impl<'a, T> InterleavedChannel<'a, T> {
pub fn from_slice(data: &'a [T], channel: usize, channels: usize) -> Option<Self> {
if data.len().checked_rem(channels)? != 0 || channel >= channels {
return None;
}
Some(unsafe {
Self::new_unchecked(
ptr::NonNull::new_unchecked(data.as_ptr() as *mut _),
data.len(),
channel,
channels,
)
})
}
}
pub struct InterleavedChannelMut<'a, T> {
ptr: ptr::NonNull<T>,
end: *mut T,
step: usize,
_marker: marker::PhantomData<&'a mut [T]>,
}
impl<'a, T> InterleavedChannelMut<'a, T> {
pub fn from_slice(data: &'a mut [T], channel: usize, channels: usize) -> Option<Self> {
if data.len().checked_rem(channels)? != 0 || channel >= channels {
return None;
}
Some(unsafe {
Self::new_unchecked(
ptr::NonNull::new_unchecked(data.as_mut_ptr()),
data.len(),
channel,
channels,
)
})
}
pub fn into_mut(mut self, frame: usize) -> Option<&'a mut T> {
if frame < len!(self) {
if mem::size_of::<T>() == 0 {
Some(unsafe { self.ptr.as_mut() })
} else {
let add = frame.saturating_mul(self.step);
Some(unsafe { &mut *self.ptr.as_ptr().add(add) })
}
} else {
None
}
}
pub fn get_mut(&mut self, n: usize) -> Option<&mut T> {
if n < len!(self) {
if mem::size_of::<T>() == 0 {
Some(unsafe { self.ptr.as_mut() })
} else {
let add = n.saturating_mul(self.step);
Some(unsafe { &mut *self.ptr.as_ptr().add(add) })
}
} else {
None
}
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut {
ptr: self.ptr,
end: self.end,
step: self.step,
_marker: marker::PhantomData,
}
}
}
impl<T> ChannelMut for InterleavedChannelMut<'_, T>
where
T: Copy,
{
type ChannelMut<'this>
= InterleavedChannelMut<'this, Self::Sample>
where
Self: 'this;
type IterMut<'this>
= IterMut<'this, Self::Sample>
where
Self: 'this;
#[inline]
fn as_channel_mut(&mut self) -> Self::ChannelMut<'_> {
InterleavedChannelMut {
ptr: self.ptr,
end: self.end,
step: self.step,
_marker: marker::PhantomData,
}
}
#[inline]
fn get_mut(&mut self, n: usize) -> Option<&mut T> {
(*self).get_mut(n)
}
#[inline]
fn iter_mut(&mut self) -> Self::IterMut<'_> {
(*self).iter_mut()
}
#[inline]
fn try_as_linear_mut(&mut self) -> Option<&mut [T]> {
None
}
}
impl<T> Clone for InterleavedChannel<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for InterleavedChannel<'_, T> {}
pub struct Iter<'a, T> {
ptr: ptr::NonNull<T>,
end: *const T,
step: usize,
_marker: marker::PhantomData<&'a [T]>,
}
impl<T> Iter<'_, T> {
#[inline]
pub(crate) unsafe fn new_aligned(
ptr: ptr::NonNull<T>,
len: usize,
offset: usize,
channels: usize,
step: usize,
) -> Self {
let (ptr, end) = align_iterable_ref(ptr, len, offset, channels);
Self {
ptr,
end,
step,
_marker: marker::PhantomData,
}
}
}
unsafe fn align_iterable_ref<T>(
ptr: ptr::NonNull<T>,
len: usize,
offset: usize,
max: usize,
) -> (ptr::NonNull<T>, *const T) {
debug_assert!(
offset <= max,
"referencing channel out of bounds; offset={}, max={}",
offset,
max,
);
debug_assert!(
len % max == 0,
"number of channels misaligned with length; max={}, len={}",
max,
len,
);
debug_assert!(max <= len, "max out of bounds; max={}, len={}", max, len,);
let ptr = ptr.as_ptr();
let (ptr, end) = if mem::size_of::<T>() == 0 {
let end = (ptr as *const u8).wrapping_add(len / max) as *const T;
(ptr, end)
} else {
let ptr = ptr.add(offset);
let end = ptr.wrapping_add(len) as *const T;
(ptr, end)
};
let ptr = ptr::NonNull::new_unchecked(ptr);
(ptr, end)
}
unsafe fn align_iterable_mut<T>(
ptr: ptr::NonNull<T>,
len: usize,
offset: usize,
max: usize,
) -> (ptr::NonNull<T>, *mut T) {
debug_assert!(
offset <= max,
"referencing channel out of bounds; offset={}, max={}",
offset,
max,
);
debug_assert!(
len % max == 0,
"number of channels misaligned with length; max={}, len={}",
max,
len,
);
debug_assert!(max <= len, "max out of bounds; max={}, len={}", max, len,);
let ptr = ptr.as_ptr();
let (ptr, end) = if mem::size_of::<T>() == 0 {
let end = (ptr as *mut u8).wrapping_add(len / max) as *mut T;
(ptr, end)
} else {
let ptr = ptr.add(offset);
let end = ptr.wrapping_add(len);
(ptr, end)
};
let ptr = ptr::NonNull::new_unchecked(ptr);
(ptr, end)
}
pub struct IterMut<'a, T> {
ptr: ptr::NonNull<T>,
end: *mut T,
step: usize,
_marker: marker::PhantomData<&'a mut [T]>,
}
iterator!(struct Iter -> *const T, T, const, {});
iterator!(struct IterMut -> *mut T, &'a mut T, mut, {&mut});