Skip to content

Commit 885825f

Browse files
committed
dasp_frame:Generic impl for all [impl Sample;const N: usize]
Replace the hard-coded macro implementing `Frame` for `[impl Sample;0-32]`, with a generic impl based on const-generics. I discovered the need for this, when trying to simplify some macro- -implementations in the `ebur128` crate with const-generics. We cannot remove the need for `NumChannels`, since (see reference 1) "Associated Const Equality" is not yet stable. We can however adapt the `NumChannels` strategy from `N1..N32` to a `NChannels<N>`-generic type. Some opportunities like removing `unsafe` from `zip_map`, remain out of reach due to pending stabilization of the standard library. 1: rust-lang/rust#92827
1 parent 6b15274 commit 885825f

File tree

1 file changed

+127
-171
lines changed

1 file changed

+127
-171
lines changed

dasp_frame/src/lib.rs

+127-171
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
#![cfg_attr(not(feature = "std"), no_std)]
77

8-
use core::iter::DoubleEndedIterator;
8+
use core::{iter::DoubleEndedIterator, mem::MaybeUninit};
99

1010
use dasp_sample::Sample;
1111

@@ -295,198 +295,133 @@ pub struct ChannelsRef<'a, F: Frame>(core::slice::Iter<'a, F::Sample>);
295295
/// Like [`ChannelsRef`], but yields mutable references instead.
296296
pub struct ChannelsMut<'a, F: Frame>(core::slice::IterMut<'a, F::Sample>);
297297

298-
macro_rules! impl_frame_for_fixed_size_array {
299-
($($NChan:ident $N:expr, [$($idx:expr)*],)*) => {
300-
$(
301-
/// A typified version of a number of channels.
302-
pub struct $NChan;
303-
impl NumChannels for $NChan {}
304-
305-
impl<S> Frame for [S; $N]
306-
where
307-
S: Sample,
308-
{
309-
type Sample = S;
310-
type NumChannels = $NChan;
311-
type Channels = Channels<Self>;
312-
type Float = [S::Float; $N];
313-
type Signed = [S::Signed; $N];
314-
315-
const EQUILIBRIUM: Self = [S::EQUILIBRIUM; $N];
316-
const CHANNELS: usize = $N;
298+
pub struct NChannels<const N: usize> {}
299+
impl<const N: usize> NumChannels for NChannels<N> {}
317300

318-
#[inline]
319-
fn channels(self) -> Self::Channels {
320-
Channels {
321-
next_idx: 0,
322-
frame: self,
323-
}
324-
}
325-
326-
#[inline]
327-
fn channels_ref(&self) -> ChannelsRef<'_, Self> {
328-
ChannelsRef(self.iter())
329-
}
330-
331-
#[inline]
332-
fn channels_mut(&mut self) -> ChannelsMut<'_, Self> {
333-
ChannelsMut(self.iter_mut())
334-
}
301+
impl<S, const N: usize> Frame for [S; N]
302+
where
303+
S: Sample,
304+
{
305+
type Sample = S;
306+
type NumChannels = NChannels<N>;
307+
type Channels = Channels<Self>;
308+
type Float = [S::Float; N];
309+
type Signed = [S::Signed; N];
335310

336-
#[inline]
337-
fn channel(&self, idx: usize) -> Option<&Self::Sample> {
338-
self.get(idx)
339-
}
311+
const EQUILIBRIUM: Self = [S::EQUILIBRIUM; N];
312+
const CHANNELS: usize = N;
340313

341-
#[inline]
342-
fn channel_mut(&mut self, idx: usize) -> Option<&mut Self::Sample> {
343-
self.get_mut(idx)
344-
}
314+
#[inline]
315+
fn channels(self) -> Self::Channels {
316+
Channels {
317+
next_idx: 0,
318+
frame: self,
319+
}
320+
}
345321

346-
#[inline]
347-
fn from_fn<F>(mut from: F) -> Self
348-
where
349-
F: FnMut(usize) -> S,
350-
{
351-
[$(from($idx), )*]
352-
}
322+
#[inline]
323+
fn channels_ref(&self) -> ChannelsRef<'_, Self> {
324+
ChannelsRef(self.iter())
325+
}
353326

354-
#[inline]
355-
fn from_samples<I>(samples: &mut I) -> Option<Self>
356-
where
357-
I: Iterator<Item=Self::Sample>
358-
{
359-
Some([$( {
360-
$idx;
361-
match samples.next() {
362-
Some(sample) => sample,
363-
None => return None,
364-
}
365-
}, )*])
366-
}
327+
#[inline]
328+
fn channels_mut(&mut self) -> ChannelsMut<'_, Self> {
329+
ChannelsMut(self.iter_mut())
330+
}
367331

368-
#[inline(always)]
369-
unsafe fn channel_unchecked(&self, idx: usize) -> &Self::Sample {
370-
self.get_unchecked(idx)
371-
}
332+
#[inline]
333+
fn channel(&self, idx: usize) -> Option<&Self::Sample> {
334+
self.get(idx)
335+
}
372336

373-
#[inline(always)]
374-
unsafe fn channel_unchecked_mut(&mut self, idx: usize) -> &mut Self::Sample {
375-
self.get_unchecked_mut(idx)
376-
}
337+
#[inline]
338+
fn channel_mut(&mut self, idx: usize) -> Option<&mut Self::Sample> {
339+
self.get_mut(idx)
340+
}
377341

378-
#[inline]
379-
fn to_signed_frame(self) -> Self::Signed {
380-
self.map(|s| s.to_sample())
381-
}
342+
#[inline]
343+
fn from_fn<F>(from: F) -> Self
344+
where
345+
F: FnMut(usize) -> S,
346+
{
347+
core::array::from_fn(from)
348+
}
382349

383-
#[inline]
384-
fn to_float_frame(self) -> Self::Float {
385-
self.map(|s| s.to_sample())
386-
}
350+
#[inline]
351+
fn from_samples<I>(samples: &mut I) -> Option<Self>
352+
where
353+
I: Iterator<Item = Self::Sample>,
354+
{
355+
array_from_iter(samples)
356+
}
387357

388-
#[inline]
389-
fn map<F, M>(self, mut map: M) -> F
390-
where
391-
F: Frame<NumChannels=Self::NumChannels>,
392-
M: FnMut(Self::Sample) -> F::Sample,
393-
{
394-
F::from_fn(|channel_idx| {
358+
#[inline(always)]
359+
unsafe fn channel_unchecked(&self, idx: usize) -> &Self::Sample {
360+
self.get_unchecked(idx)
361+
}
395362

396-
// Here we do not require run-time bounds checking as we have asserted that
397-
// the two arrays have the same number of channels at compile time with our
398-
// where clause, i.e.
399-
//
400-
// `F: Frame<NumChannels=Self::NumChannels>`
401-
unsafe { map(*self.channel_unchecked(channel_idx)) }
402-
})
403-
}
363+
#[inline(always)]
364+
unsafe fn channel_unchecked_mut(&mut self, idx: usize) -> &mut Self::Sample {
365+
self.get_unchecked_mut(idx)
366+
}
404367

405-
#[inline]
406-
fn zip_map<O, F, M>(self, other: O, mut zip_map: M) -> F
407-
where
408-
O: Frame<NumChannels=Self::NumChannels>,
409-
F: Frame<NumChannels=Self::NumChannels>,
410-
M: FnMut(Self::Sample, O::Sample) -> F::Sample
411-
{
412-
F::from_fn(|channel_idx| {
368+
#[inline]
369+
fn to_signed_frame(self) -> Self::Signed {
370+
self.map(|s| s.to_sample())
371+
}
413372

414-
// Here we do not require run-time bounds checking as we have asserted that the two
415-
// arrays have the same number of channels at compile time with our where clause, i.e.
416-
//
417-
// ```
418-
// O: Frame<NumChannels=Self::NumChannels>
419-
// F: Frame<NumChannels=Self::NumChannels>
420-
// ```
421-
unsafe {
422-
zip_map(*self.channel_unchecked(channel_idx),
423-
*other.channel_unchecked(channel_idx))
424-
}
425-
})
426-
}
373+
#[inline]
374+
fn to_float_frame(self) -> Self::Float {
375+
self.map(|s| s.to_sample())
376+
}
427377

428-
#[inline]
429-
fn scale_amp(self, amp: S::Float) -> Self {
430-
[$(self[$idx].mul_amp(amp), )*]
431-
}
378+
#[inline]
379+
fn map<F, M>(self, mut map: M) -> F
380+
where
381+
F: Frame<NumChannels = Self::NumChannels>,
382+
M: FnMut(Self::Sample) -> F::Sample,
383+
{
384+
F::from_fn(|channel_idx| {
385+
// Here we do not require run-time bounds checking as we have asserted that
386+
// the two arrays have the same number of channels at compile time with our
387+
// where clause, i.e.
388+
//
389+
// `F: Frame<NumChannels=Self::NumChannels>`
390+
unsafe { map(*self.channel_unchecked(channel_idx)) }
391+
})
392+
}
432393

433-
#[inline]
434-
fn add_amp<F>(self, other: F) -> Self
435-
where
436-
F: Frame<Sample=S::Signed, NumChannels=$NChan>,
437-
{
438-
// Here we do not require run-time bounds checking as we have asserted that the two
439-
// arrays have the same number of channels at compile time with our where clause, i.e.
440-
unsafe {
441-
[$(self[$idx].add_amp(*other.channel_unchecked($idx)), )*]
442-
}
443-
}
394+
#[inline]
395+
fn zip_map<O, F, M>(self, other: O, mut zip_map: M) -> F
396+
where
397+
O: Frame<NumChannels = Self::NumChannels>,
398+
F: Frame<NumChannels = Self::NumChannels>,
399+
M: FnMut(Self::Sample, O::Sample) -> F::Sample,
400+
{
401+
F::from_fn(|channel_idx| {
402+
// Here we do not require run-time bounds checking as we have asserted that the two
403+
// arrays have the same number of channels at compile time with our where clause, i.e.
404+
//
405+
// ```
406+
// O: Frame<NumChannels=Self::NumChannels>
407+
// F: Frame<NumChannels=Self::NumChannels>
408+
// ```
409+
unsafe {
410+
zip_map(
411+
*self.channel_unchecked(channel_idx),
412+
*other.channel_unchecked(channel_idx),
413+
)
444414
}
445-
)*
446-
};
447-
}
448-
449-
impl_frame_for_fixed_size_array! {
450-
N1 1, [0],
451-
N2 2, [0 1],
452-
N3 3, [0 1 2],
453-
N4 4, [0 1 2 3],
454-
N5 5, [0 1 2 3 4],
455-
N6 6, [0 1 2 3 4 5],
456-
N7 7, [0 1 2 3 4 5 6],
457-
N8 8, [0 1 2 3 4 5 6 7],
458-
N9 9, [0 1 2 3 4 5 6 7 8],
459-
N10 10, [0 1 2 3 4 5 6 7 8 9],
460-
N11 11, [0 1 2 3 4 5 6 7 8 9 10],
461-
N12 12, [0 1 2 3 4 5 6 7 8 9 10 11],
462-
N13 13, [0 1 2 3 4 5 6 7 8 9 10 11 12],
463-
N14 14, [0 1 2 3 4 5 6 7 8 9 10 11 12 13],
464-
N15 15, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14],
465-
N16 16, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15],
466-
N17 17, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16],
467-
N18 18, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17],
468-
N19 19, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18],
469-
N20 20, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19],
470-
N21 21, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20],
471-
N22 22, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21],
472-
N23 23, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22],
473-
N24 24, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23],
474-
N25 25, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24],
475-
N26 26, [0 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],
476-
N27 27, [0 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],
477-
N28 28, [0 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],
478-
N29 29, [0 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],
479-
N30 30, [0 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],
480-
N31 31, [0 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],
481-
N32 32, [0 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],
415+
})
416+
}
482417
}
483418

484419
macro_rules! impl_frame_for_sample {
485420
($($T:ty)*) => {
486421
$(
487422
impl Frame for $T {
488423
type Sample = $T;
489-
type NumChannels = N1;
424+
type NumChannels = NChannels<1>;
490425
type Channels = Channels<Self>;
491426
type Float = <$T as Sample>::Float;
492427
type Signed = <$T as Sample>::Signed;
@@ -612,7 +547,7 @@ macro_rules! impl_frame_for_sample {
612547
#[inline]
613548
fn add_amp<F>(self, other: F) -> Self
614549
where
615-
F: Frame<Sample=<$T as Sample>::Signed, NumChannels=N1>,
550+
F: Frame<Sample=<$T as Sample>::Signed, NumChannels=NChannels<1>>,
616551
{
617552
// Here we do not require run-time bounds checking as we have asserted that the two
618553
// arrays have the same number of channels at compile time with our where clause, i.e.
@@ -714,3 +649,24 @@ impl<'a, F: Frame> DoubleEndedIterator for ChannelsMut<'a, F> {
714649
self.0.next_back()
715650
}
716651
}
652+
653+
fn array_from_iter<T, const N: usize>(mut iter: impl Iterator<Item = T>) -> Option<[T; N]> {
654+
// Hopefully something equivalent will be in stdlib some day
655+
656+
unsafe {
657+
let mut result: [MaybeUninit<T>; N] = MaybeUninit::uninit().assume_init();
658+
659+
for i in 0..N {
660+
if let Some(sample) = iter.next() {
661+
result[i].write(sample);
662+
} else {
663+
for i in 0..i {
664+
result[i].assume_init_drop()
665+
}
666+
return None;
667+
}
668+
}
669+
670+
Some(result.map(|v| v.assume_init()))
671+
}
672+
}

0 commit comments

Comments
 (0)