Skip to content

Commit fd52458

Browse files
committed
Add TryFrom to convert from Varargs to tuples
godot-rust#886
1 parent 0f54128 commit fd52458

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

gdnative-core/src/export/method.rs

+111
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,117 @@ impl<'a> Iterator for Varargs<'a> {
300300
}
301301
}
302302

303+
// Return a second token.
304+
macro_rules! replace_expr {
305+
($_t:tt $sub:expr) => {
306+
$sub
307+
};
308+
}
309+
310+
// Count parameters.
311+
macro_rules! count_tts {
312+
($($tts:tt)*) => {
313+
0usize $(+ replace_expr!($tts 1usize))*
314+
};
315+
}
316+
317+
// Convert from Varargs to tuples, implement traits.
318+
macro_rules! varargs_into_tuple {
319+
($($params:ident),*) => {
320+
impl<'a, $($params: FromVariant),*> std::convert::TryFrom<Varargs<'a>> for ($($params,)*) {
321+
type Error = VarargsError;
322+
323+
#[inline]
324+
fn try_from(value: Varargs<'a>) -> Result<Self, Self::Error> {
325+
const EXPECTED: usize = count_tts!($($params)*);
326+
let args = &value.args;
327+
if args.len() == EXPECTED {
328+
#[allow(unused_variables, unused_mut)]
329+
let mut i: usize = 0;
330+
#[allow(clippy::eval_order_dependence)]
331+
Ok((
332+
$({
333+
i += 1;
334+
$params::from_variant(args[i - 1])?
335+
},)*
336+
))
337+
} else {
338+
Err(ArgumentLengthError{
339+
passed: args.len(),
340+
expected: EXPECTED,
341+
}.into())
342+
}
343+
}
344+
}
345+
};
346+
}
347+
348+
// Define up to the length supported by standard library.
349+
varargs_into_tuple!();
350+
varargs_into_tuple!(A);
351+
varargs_into_tuple!(A, B);
352+
varargs_into_tuple!(A, B, C);
353+
varargs_into_tuple!(A, B, C, D);
354+
varargs_into_tuple!(A, B, C, D, E);
355+
varargs_into_tuple!(A, B, C, D, E, F);
356+
varargs_into_tuple!(A, B, C, D, E, F, G);
357+
varargs_into_tuple!(A, B, C, D, E, F, G, H);
358+
varargs_into_tuple!(A, B, C, D, E, F, G, H, I);
359+
varargs_into_tuple!(A, B, C, D, E, F, G, H, I, J);
360+
varargs_into_tuple!(A, B, C, D, E, F, G, H, I, J, K);
361+
varargs_into_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
362+
363+
/// All possible error types for convert from Varargs.
364+
#[derive(Debug)]
365+
pub enum VarargsError {
366+
ArgumentLengthError(ArgumentLengthError),
367+
FromVariantError(FromVariantError),
368+
}
369+
370+
impl std::error::Error for VarargsError {}
371+
impl std::fmt::Display for VarargsError {
372+
#[inline]
373+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374+
match &self {
375+
VarargsError::ArgumentLengthError(e) => e.fmt(f),
376+
VarargsError::FromVariantError(e) => e.fmt(f),
377+
}
378+
}
379+
}
380+
381+
impl From<ArgumentLengthError> for VarargsError {
382+
#[inline]
383+
fn from(value: ArgumentLengthError) -> Self {
384+
Self::ArgumentLengthError(value)
385+
}
386+
}
387+
388+
impl From<FromVariantError> for VarargsError {
389+
#[inline]
390+
fn from(value: FromVariantError) -> Self {
391+
Self::FromVariantError(value)
392+
}
393+
}
394+
395+
/// Error to argument lengths do not match.
396+
#[derive(Debug)]
397+
pub struct ArgumentLengthError {
398+
passed: usize,
399+
expected: usize,
400+
}
401+
402+
impl std::error::Error for ArgumentLengthError {}
403+
impl std::fmt::Display for ArgumentLengthError {
404+
#[inline]
405+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406+
write!(
407+
f,
408+
"Argument lengths do not match. passed {}, expected {}",
409+
self.passed, self.expected
410+
)
411+
}
412+
}
413+
303414
/// Trait for structures that can be parsed from `Varargs`.
304415
///
305416
/// This trait can be derived for structure types where each type implements `FromVariant`.

0 commit comments

Comments
 (0)