Skip to content

Commit e5f5f56

Browse files
committed
Add get_rest() to Varargs
Added `offset_index` so that actual position of arguments is displayed in error messages.
1 parent c83bf16 commit e5f5f56

File tree

1 file changed

+61
-9
lines changed

1 file changed

+61
-9
lines changed

gdnative-core/src/export/method.rs

+61-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Method registration
22
33
use std::borrow::Cow;
4+
use std::convert::TryInto;
45
use std::fmt;
56
use std::marker::PhantomData;
67
use std::ops::Bound;
@@ -214,6 +215,7 @@ impl<C: NativeClass, F: StaticArgsMethod<C>> Method<C> for StaticArgs<F> {
214215
pub struct Varargs<'a> {
215216
idx: usize,
216217
args: &'a [&'a Variant],
218+
offset_index: usize,
217219
}
218220

219221
impl<'a> Varargs<'a> {
@@ -283,7 +285,11 @@ impl<'a> Varargs<'a> {
283285
pub unsafe fn from_sys(num_args: libc::c_int, args: *mut *mut sys::godot_variant) -> Self {
284286
let args = std::slice::from_raw_parts(args, num_args as usize);
285287
let args = std::mem::transmute::<&[*mut sys::godot_variant], &[&Variant]>(args);
286-
Self { idx: 0, args }
288+
Self {
289+
idx: 0,
290+
args,
291+
offset_index: 0,
292+
}
287293
}
288294

289295
/// Check the length of arguments.
@@ -317,14 +323,17 @@ impl<'a> Varargs<'a> {
317323
/// ```
318324
#[inline]
319325
pub fn get<T: FromVariant>(&self, index: usize) -> Result<T, ArgumentTypeError> {
320-
match self.args.get(index) {
326+
let relative_index = index;
327+
let actual_index = index + self.offset_index;
328+
329+
match self.args.get(relative_index) {
321330
Some(v) => match T::from_variant(v) {
322331
Ok(ok) => Ok(ok),
323-
Err(err) => Err(ArgumentTypeError::new(index, err)),
332+
Err(err) => Err(ArgumentTypeError::new(actual_index, err)),
324333
},
325334
None => {
326335
let err = FromVariantError::Custom("Argument is not set".to_owned());
327-
Err(ArgumentTypeError::new(index, err))
336+
Err(ArgumentTypeError::new(actual_index, err))
328337
}
329338
}
330339
}
@@ -346,14 +355,56 @@ impl<'a> Varargs<'a> {
346355
/// ```
347356
#[inline]
348357
pub fn get_opt<T: FromVariant>(&self, index: usize) -> Result<Option<T>, ArgumentTypeError> {
349-
match self.args.get(index) {
358+
let relative_index = index;
359+
let actual_index = index + self.offset_index;
360+
361+
match self.args.get(relative_index) {
350362
Some(v) => match T::from_variant(v) {
351363
Ok(ok) => Ok(Some(ok)),
352-
Err(err) => Err(ArgumentTypeError::new(index, err)),
364+
Err(err) => Err(ArgumentTypeError::new(actual_index, err)),
353365
},
354366
None => Ok(None),
355367
}
356368
}
369+
370+
/// Returns the type-converted value from the specified argument position.
371+
/// Can be converted to any type that implements TryFrom<Varargs>.
372+
///
373+
/// # Errors
374+
/// Returns an error if the conversion fails.
375+
///
376+
/// # Examples
377+
/// ```ignore
378+
/// # fn foo(args: gdnative::export::Varargs) -> Result<(), Box<dyn std::error::Error>> {
379+
/// args.check_length(1..)?;
380+
/// let a: usize = args.get(0)?;
381+
/// let rest: Vec<i64> = args.get_rest(1)?;
382+
/// # Ok(())
383+
/// # }
384+
/// ```
385+
#[inline]
386+
pub fn get_rest<T>(&self, rest_index: usize) -> Result<T, <Varargs<'a> as TryInto<T>>::Error>
387+
where
388+
Varargs<'a>: TryInto<T>,
389+
{
390+
let relative_rest_index = rest_index;
391+
let actual_rest_index = rest_index + self.offset_index;
392+
393+
let rest = self.args.get(relative_rest_index..).unwrap_or_default();
394+
let varargs = Varargs::<'a> {
395+
idx: 0,
396+
args: rest,
397+
offset_index: actual_rest_index,
398+
};
399+
varargs.try_into()
400+
}
401+
402+
/// Get the varargs's offset index.
403+
#[inline]
404+
#[must_use]
405+
pub fn offset_index(&self) -> usize {
406+
self.offset_index
407+
}
357408
}
358409

359410
impl<'a> Iterator for Varargs<'a> {
@@ -713,10 +764,11 @@ impl<'r, 'a, T: FromVariant> ArgBuilder<'r, 'a, T> {
713764
#[inline]
714765
pub fn get(mut self) -> Result<T, ArgumentError<'a>> {
715766
self.get_optional_internal().and_then(|arg| {
767+
let actual_index = self.args.idx + self.args.offset_index;
716768
arg.ok_or(ArgumentError {
717769
site: self.site,
718770
kind: ArgumentErrorKind::Missing {
719-
idx: self.args.idx,
771+
idx: actual_index,
720772
name: self.name,
721773
},
722774
})
@@ -741,13 +793,13 @@ impl<'r, 'a, T: FromVariant> ArgBuilder<'r, 'a, T> {
741793
ty,
742794
..
743795
} = self;
744-
let idx = args.idx;
796+
let actual_index = args.idx + args.offset_index;
745797

746798
if let Some(arg) = args.next() {
747799
T::from_variant(arg).map(Some).map_err(|err| ArgumentError {
748800
site: *site,
749801
kind: ArgumentErrorKind::CannotConvert {
750-
idx,
802+
idx: actual_index,
751803
name: name.take(),
752804
value: arg,
753805
ty: ty

0 commit comments

Comments
 (0)