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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! A pixel mixer module.
use core::borrow::{Borrow, BorrowMut};
use crate::color::PixelRgb;
use crate::phase_amp::*;

/// Implementations of this trait should compute the vertical and horizontal intermediate data for a
/// [Mixer].
pub trait IntermediateCalculator<T> {
    /// Computes an intermediate data for a given angle.
    ///
    /// The input value is given in radians in the range: `[0, 2PI)`.
    /// The output will be stored in the array of given types as defined by [Mixer::IntermediateH]
    /// or [Mixer::IntermediateV]. The type should be a `f32` or a packed simd `f32x8` if a
    /// "use-simd" crate feature is enabled.
    fn calculate(&self, v: T) -> T;
}

/// Implementations of this trait should compute the color of each pixel based on an intermediate
/// data created by a [IntermediateCalculator].
///
/// The type `T` should be a `f32` or a packed simd `f32x8` if a "use-simd" crate feature is
/// enabled.
pub trait Mixer<T: Sized + Default + Copy> {
    /// This type should be an array of the type T for an intermediate horizontal data.
    type IntermediateH: Sized + Default + Copy + BorrowMut<[T]> + Borrow<[T]>;
    /// This type should be an array of the type T for an intermediate vertical data.
    type IntermediateV: Sized + Default + Copy + BorrowMut<[T]> + Borrow<[T]>;

    /// Returns the number of intermediate horizontal values.
    #[inline]
    fn intermediate_h_len() -> usize { core::mem::size_of::<Self::IntermediateH>() / core::mem::size_of::<T>() }

    /// Returns the number of intermediate vertical values.
    #[inline]
    fn intermediate_v_len() -> usize { core::mem::size_of::<Self::IntermediateV>() / core::mem::size_of::<T>() }

    /// The implementors should compute a pixel and send it as an instance of [PixelRgb] to the
    /// provided `next_pixel` function.
    ///
    /// The computation should be based on the provided combination of intermediate data.
    fn mix_pixels(vxp: &Self::IntermediateH, vyp: &Self::IntermediateV, next_pixel: &mut dyn FnMut(PixelRgb));
}

/// Implementations of this trait should produce an iterator of an [IntermediateCalculator] tool.
///
/// The type `T` should be a `f32` or a packed simd `f32x8` if a "use-simd" crate feature is
/// enabled.
pub trait IntermediateCalculatorProducer<'a, P, T>
    where P: PhaseAmpsSelect<'a> + ?Sized,
          T: Sized + Default + Copy
{
    /// Provide an iterator implementation which produce [IntermediateCalculator] tools.
    /// The iterator must be a [ExactSizeIterator] with exactly the same length as
    /// the associated [Mixer::IntermediateH] array's number of elements.
    type CalcIterH: ExactSizeIterator + Iterator<Item = Self::LineCalcH> + Sized;
    /// Provide an iterator implementation which produce [IntermediateCalculator] tools.
    /// The iterator must be a [ExactSizeIterator] with exactly the same length as
    /// the associated [Mixer::IntermediateV] array's number of elements.
    type CalcIterV: ExactSizeIterator + Iterator<Item = Self::LineCalcV> + Sized;
    /// Provide an implementation of a [IntermediateCalculator] for horizontal intermediate data.
    type LineCalcH: IntermediateCalculator<T> + Sized;
    /// Provide an implementation of a [IntermediateCalculator] for vertical intermediate data.
    type LineCalcV: IntermediateCalculator<T> + Sized;

    /// Should return an instance of a [IntermediateCalculatorProducer::LineCalcH].
    /// The input data references an implementation of [PhaseAmpsSelect] tool.
    fn compose_h_iter(pa: &'a P) -> Self::CalcIterH;
    /// Should return an instance of a [IntermediateCalculatorProducer::LineCalcV].
    /// The input data references an implementation of [PhaseAmpsSelect] tool.
    fn compose_v_iter(pa: &'a P) -> Self::CalcIterV;
}