use {
	glib::{
		types::StaticType,
		value::{FromValue, ValueTypeChecker, ValueTypeMismatchError, ValueTypeMismatchOrNoneError},
		Type, Value,
	},
	std::error::Error,
};
pub trait FromValues<'a> {
	type Error: Error;
	type Types: IntoIterator<Item = Type>;
	fn from_values(args: &'a [Value]) -> Result<Self, Self::Error>
	where
		Self: Sized;
	fn static_types() -> Self::Types;
}
macro_rules! impl_signal_arguments {
	($count:literal; ($($tx:ident),*)) => {
		#[allow(non_snake_case)]
		impl<'a, $($tx,)*> FromValues<'a> for ($($tx, )*) where
			$($tx: FromValue<'a> + StaticType,)*
			$(ValueTypeMismatchOrNoneError<ValueTypeMismatchError>: From<<$tx::Checker as ValueTypeChecker>::Error>,)*
		{
			type Error = ValueTypeMismatchOrNoneError<ValueTypeMismatchError>;
			type Types = [Type; $count];
			fn from_values(args: &'a [Value]) -> Result<Self, Self::Error> {
				match args {
					[$($tx,)*] => Ok(($($tx.get()?,)*)),
					_ => Err(ValueTypeMismatchOrNoneError::UnexpectedNone),
				}
			}
			fn static_types() -> Self::Types {
				[$($tx::static_type(),)*]
			}
		}
	};
}
impl_signal_arguments! { 0; () }
impl_signal_arguments! { 1; (T0) }
impl_signal_arguments! { 2; (T0, T1) }
impl_signal_arguments! { 3; (T0, T1, T2) }
impl_signal_arguments! { 4; (T0, T1, T2, T3) }
impl_signal_arguments! { 5; (T0, T1, T2, T3, T4) }
impl_signal_arguments! { 6; (T0, T1, T2, T3, T4, T5) }
impl_signal_arguments! { 7; (T0, T1, T2, T3, T4, T5, T6) }
impl_signal_arguments! { 8; (T0, T1, T2, T3, T4, T5, T6, T7) }
impl_signal_arguments! { 9; (T0, T1, T2, T3, T4, T5, T6, T7, T8) }
impl_signal_arguments! { 10; (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) }
impl_signal_arguments! { 11; (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) }
impl_signal_arguments! { 12; (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) }