euphony 0.1.1

music composition environment for programmers
Documentation
use crate::{node::Node, sink::Sink, value::Parameter};

pub trait Processor: Sized
where
    Self: Into<Parameter>,
    for<'a> &'a Self: Into<Parameter>,
{
    fn sink(&self) -> Sink;

    fn node(&self) -> Node;

    #[inline]
    fn fin(self) {
        drop(self)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) struct Definition {
    pub id: u64,
    pub inputs: u64,
    pub buffers: u64,
}

impl Definition {
    #[inline]
    pub fn spawn(&self) -> Node {
        Node::new(self, None)
    }
}

macro_rules! define_processor_binary_op {
    ($name:ident, $op:ident, $lower:ident) => {
        impl core::ops::$op<$name> for f64 {
            type Output = crate::processors::binary::$op;

            #[inline]
            fn $lower(self, rhs: $name) -> Self::Output {
                use crate::processors::input::*;
                crate::processors::binary::$lower()
                    .with_lhs(self)
                    .with_rhs(rhs)
            }
        }

        impl core::ops::$op<&$name> for f64 {
            type Output = crate::processors::binary::$op;

            #[inline]
            fn $lower(self, rhs: &$name) -> Self::Output {
                use crate::processors::input::*;
                crate::processors::binary::$lower()
                    .with_lhs(self)
                    .with_rhs(rhs)
            }
        }

        impl<Rhs: Into<crate::value::Parameter>> core::ops::$op<Rhs> for $name {
            type Output = crate::processors::binary::$op;

            #[inline]
            fn $lower(self, rhs: Rhs) -> Self::Output {
                use crate::processors::input::*;
                crate::processors::binary::$lower()
                    .with_lhs(self)
                    .with_rhs(rhs)
            }
        }

        impl<Rhs: Into<crate::value::Parameter>> core::ops::$op<Rhs> for &$name {
            type Output = crate::processors::binary::$op;

            #[inline]
            fn $lower(self, rhs: Rhs) -> Self::Output {
                use crate::processors::input::*;
                crate::processors::binary::$lower()
                    .with_lhs(self)
                    .with_rhs(rhs)
            }
        }
    };
}

macro_rules! define_processor_ops {
    ($name:ident) => {
        define_processor_binary_op!($name, Add, add);
        define_processor_binary_op!($name, Div, div);
        define_processor_binary_op!($name, Mul, mul);
        define_processor_binary_op!($name, Rem, rem);
        define_processor_binary_op!($name, Sub, sub);

        impl core::ops::Neg for $name {
            type Output = crate::processors::unary::Neg;

            #[inline]
            fn neg(self) -> Self::Output {
                use crate::processors::input::*;
                crate::processors::unary::neg().with_input(self)
            }
        }

        impl core::ops::Neg for &$name {
            type Output = crate::processors::unary::Neg;

            #[inline]
            fn neg(self) -> Self::Output {
                use crate::processors::input::*;
                crate::processors::unary::neg().with_input(self)
            }
        }
    };
}

macro_rules! define_processor {
    (
        $(#[doc = $doc:literal])?
        #[id = $id:literal]
        #[lower = $lower:ident]
        struct $name:ident {
            $(
                #[buffer]
                #[trait = $trait_buffer_name:ident]
                #[with = $with_buffer:ident]
                #[set = $set_buffer:ident]
                $buffer:ident: Buffer<$buffer_id:literal>,
            )*
            $(
                #[trait = $trait_name:ident]
                #[with = $with:ident]
                #[set = $set:ident]
                $input:ident: $input_ty:ident<$input_id:literal>,
            )*
        }
    ) => {
        $(#[doc = $doc])?
        #[derive(Clone, Debug)]
        #[must_use = "nodes do nothing unless routed to a Sink"]
        pub struct $name(crate::node::Node);

        #[inline]
        $(#[doc = $doc])?
        pub fn $lower() -> $name {
            $name::default()
        }

        mod $lower {
            use super::*;

            #[allow(unused_imports)]
            use crate::value::{Parameter, Trigger};

            impl Default for $name {
                #[inline]
                fn default() -> Self {
                    use crate::processor::Definition;
                    static DEF: Definition = Definition {
                        id: $id,
                        inputs: $({
                            let _ = $input_id;
                            1
                        } +)* 0,
                        buffers: $({
                            let _ = $buffer_id;
                            1
                        } +)* 0,
                    };
                    Self(DEF.spawn())
                }
            }

            impl $name {
                $(
                    pub fn $input(&self) -> crate::parameter::$input_ty {
                        crate::parameter::$input_ty {
                            node: self.0.clone(),
                            index: $input_id,
                        }
                    }
                )*

                $(
                    pub fn $buffer(&self) -> crate::parameter::Buffer {
                        crate::parameter::Buffer {
                            node: self.0.clone(),
                            index: $buffer_id,
                        }
                    }
                )*
            }

            impl crate::processor::Processor for $name {
                #[inline]
                fn sink(&self) -> crate::sink::Sink {
                    self.0.sink()
                }

                #[inline]
                fn node(&self) -> crate::node::Node {
                    self.0.node()
                }
            }

            $(
                impl<V: euphony_buffer::AsChannel> crate::processors::input::$trait_buffer_name<V> for $name {
                    #[inline]
                    fn $with_buffer(self, value: V) -> Self {
                        self.0.set_buffer($buffer_id, value);
                        self
                    }

                    #[inline]
                    fn $set_buffer(&self, value: V) -> &Self {
                        self.0.set_buffer($buffer_id, value);
                        self
                    }
                }
            )*

            $(
                impl<V: Into<$input_ty>> crate::processors::input::$trait_name<V> for $name {
                    #[inline]
                    fn $with(self, value: V) -> Self {
                        self.0.set($input_id, value.into());
                        self
                    }

                    #[inline]
                    fn $set(&self, value: V) -> &Self {
                        self.0.set($input_id, value.into());
                        self
                    }
                }
            )*

            impl From<$name> for Parameter {
                #[inline]
                fn from(node: $name) -> Self {
                    node.0.into()
                }
            }

            impl From<&$name> for Parameter {
                #[inline]
                fn from(node: &$name) -> Self {
                    (&node.0).into()
                }
            }

            impl core::ops::Deref for $name {
                type Target = crate::node::Node;

                fn deref(&self) -> &Self::Target {
                    &self.0
                }
            }

            define_processor_ops!($name);
        }
    };
}