#[macro_export]
macro_rules! enum_wrapper {
    (@add_enum_variant $name: ident, $enum_variant: ident : $enum_value: expr, $($tts:tt)*) => {
        pub const $enum_variant: $name = $name { raw: $enum_value };
        enum_wrapper!(@add_enum_variant $name, $($tts)* ,);
    };
    (@add_enum_variant $name: ident, $enum_variant: ident : $enum_value: path, $($tts:tt)*) => {
        pub const $enum_variant: $name = $name { raw: $enum_value };
        enum_wrapper!(@add_enum_variant $name, $($tts)* ,);
    };
    (@add_enum_variant $name: ident, $(,)*) => {};
    (@add_debug_variant $self:ident, $f:ident, $enum_variant: ident : $enum_value: path, $($tts:tt)*) => {
        if $self.raw == Self::$enum_variant.raw {
            write!($f, stringify!($enum_variant));
            return Ok(())
        };
        enum_wrapper!(@add_debug_variant $self, $f, $($tts)* ,)
    };
    (@add_debug_variant $self:ident, $f:ident, $enum_variant: ident : $enum_value: expr, $($tts:tt)*) => {
        if $self.raw == Self::$enum_variant.raw {
            write!($f, stringify!($enum_variant));
            return Ok(())
        };
        enum_wrapper!(@add_debug_variant $self, $f, $($tts)* ,)
    };
    (@add_debug_variant $self:ident, $f:ident, $(,)*) => {};
    ($name: ident, $repr_type: ty, $($tts:tt)+) => {
        #[derive(pipewire_wrapper_proc_macro::RawWrapper, PartialEq, Eq, Clone, Copy)]
        #[repr(transparent)]
        pub struct $name {
            #[raw]
            pub(crate) raw: $repr_type,
        }
        impl $name {
            enum_wrapper!(@add_enum_variant $name, $($tts)*);
        }
        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                enum_wrapper!(@add_debug_variant self, f, $($tts)*);
                write!(f, "UNKNOWN({:?})", self.raw);
                Ok(())
            }
        }
    };
}
#[macro_export]
macro_rules! spa_interface_call {
    ($self:ident, $method:ident:$version:expr, $($arg:expr),*) => {{
        spa_interface_call!(@implementation $self, $method:$version, $($arg),*)
    }};
    ($self:ident, $method:ident, $($arg:expr),*) => {{
        spa_interface_call!(@implementation $self, $method:0u32, $($arg),*)
    }};
    ($self:ident, $method:ident) => {{
        spa_interface_call!($self, $method,)
    }};
    (@implementation $self:ident, $method:ident:$version:expr, $($arg:expr),*) => {{
        use pipewire_wrapper_proc_macro::spa_interface;
        use $crate::error::Error;
        use $crate::wrapper::SpaInterface;
        let funcs: *const <Self as SpaInterface>::Methods = $self.spa_interface().cb().funcs();
        if $self.spa_interface().version_min($version) {
            if let Some(funcs) = unsafe { funcs.as_ref() } {
                if let Some(func) = funcs.$method {
                    let result = unsafe { func($self.spa_interface().cb().data(), $($arg),*) };
                    Ok(result)
                } else {
                    Err(Error::MethodNotFound(String::from(stringify!($method))))
                }
            } else {
                Err(Error::MethodCallOnNull)
            }
        } else {
            Err(Error::VersionMismatch($version, $self.spa_interface().version()))
        }
    }};
}
#[macro_export]
macro_rules! events_builder_build {
    ($events_struct:ident<$lifetime:lifetime, $generic_type:ident>, $events_raw:ident, $($callback_field:ident => $callback:ident,)*) => {
         pub fn build(self) -> Pin<Box<$events_struct<$lifetime, $generic_type>>> {
            events_builder_build!(@function_body_generic self, $events_struct<$generic_type>, $events_raw, $($callback_field => $callback,)*)
         }
    };
    ($events_struct:ident<$lifetime:lifetime>, $events_raw:ident, $($callback_field:ident => $callback:ident,)*) => {
         pub fn build(self) -> Pin<Box<$events_struct<$lifetime>>> {
            events_builder_build!(@function_body self, $events_struct, $events_raw, $($callback_field => $callback,)*)
         }
    };
    ($events_struct:ident, $events_raw:ident, $($callback_field:ident => $callback:ident,)*) => {
         pub fn build(self) -> Pin<Box<$events_struct>> {
            events_builder_build!(@function_body self, $events_struct, $events_raw, $($callback_field => $callback,)*)
         }
    };
    (@function_body $self:ident, $events_struct:ident, $events_raw:ident, $($callback_field:ident => $callback:ident,)*) => {{
            let hook = $crate::spa::interface::Hook::new();
            let raw = $events_raw {
                version: 0,
                $($callback_field: None,
                )*
            };
            let raw = <$events_struct as $crate::wrapper::Wrapper>::RawWrapperType::from_raw(raw);
            let mut pinned_raw = Box::into_pin(Box::new(raw));
            let mut events = Box::into_pin(Box::new($events_struct {
                ref_: NonNull::new(pinned_raw.as_ptr()).unwrap(),
                raw: pinned_raw,
                hook,
                $($callback_field: $self.$callback_field.flatten(),
                )*
            }));
            $(if events.$callback_field.is_some() {
                events.raw.raw.$callback_field = Some(<$events_struct>::$callback);
            })*
            events
    }};
    (@function_body_generic $self:ident, $events_struct:ident<$generic_type:ident>, $events_raw:ident, $($callback_field:ident => $callback:ident,)*) => {{
            let hook = $crate::spa::interface::Hook::new();
            let raw = $events_raw {
                version: 0,
                $($callback_field: None,
                )*
            };
            let raw = <$events_struct<$generic_type> as $crate::wrapper::Wrapper>::RawWrapperType::from_raw(raw);
            let mut pinned_raw = Box::into_pin(Box::new(raw));
            let mut events = Box::into_pin(Box::new($events_struct {
                ref_: NonNull::new(pinned_raw.as_ptr()).unwrap(),
                raw: pinned_raw,
                hook,
                $($callback_field: $self.$callback_field.flatten(),
                )*
            }));
            $(if events.$callback_field.is_some() {
                events.raw.raw.$callback_field = Some(<$events_struct::<$generic_type>>::$callback);
            })*
            events
    }};
}
#[macro_export]
macro_rules! events_channel_builder {
    ($struct_name:ident, $($callback_field:ident => $callback:ident,)*) => {
        paste::paste! {
            events_channel_builder!(
                [<$struct_name EventsChannelBuilder>],
                [<$struct_name EventsBuilder>],
                [<$struct_name Events>],
                [<$struct_name EventType>],
                $($callback_field => $callback,)*);
        }
    };
    ($channel_builder:ident, $events_builder:ident, $events_struct:ident, $events_type:ident, $($callback_field:ident => $callback:ident,)*) => {
        pub struct $channel_builder<'p> {
            events_builder: $events_builder<'p>,
            sender: Sender<'p, $events_type>,
            receiver: Receiver<'p, $events_type>,
        }
        impl<'p> $channel_builder<'p> {
            $(pub fn $callback_field(mut self) -> Self {
                self.events_builder = self
                    .events_builder
                    .$callback_field(Self::$callback(self.sender.clone()));
                self
            })*
            pub fn build_loop_channel(self) -> (Pin<Box<$events_struct<'p>>>, Receiver<'p, $events_type>) {
                let events = self.events_builder.build();
                (events, self.receiver)
            }
            pub fn build_channel(self) -> (Pin<Box<$events_struct<'p>>>, mpsc::Receiver<$events_type>) {
                let (sender, receiver) = self.build_loop_channel();
                (sender, receiver.into_receiver())
            }
        }
        impl Default for $channel_builder<'_> {
            fn default() -> Self {
                let (sender, receiver) = loop_::channel::LoopChannel::channel();
                Self {
                    events_builder: Default::default(),
                    sender,
                    receiver,
                }
            }
        }
    };
}