Skip to content

Commit 7efa566

Browse files
committed
Add arguments check errors
The `ArgumentBounds` trait was redefined only because `usize` does not implement the `RangeBounds<usize>` trait.
1 parent 2be48e3 commit 7efa566

File tree

1 file changed

+280
-0
lines changed

1 file changed

+280
-0
lines changed

gdnative-core/src/export/method.rs

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::borrow::Cow;
44
use std::fmt;
55
use std::marker::PhantomData;
6+
use std::ops::Bound;
67

78
use crate::core_types::{FromVariant, FromVariantError, Variant};
89
use crate::export::class::NativeClass;
@@ -298,6 +299,285 @@ impl<'a> Iterator for Varargs<'a> {
298299
}
299300
}
300301

302+
/// All possible error types for convert from Varargs.
303+
#[derive(Debug)]
304+
pub enum VarargsError {
305+
ArgumentTypeError(ArgumentTypeError),
306+
ArgumentLengthError(ArgumentLengthError),
307+
}
308+
309+
impl std::error::Error for VarargsError {}
310+
impl std::fmt::Display for VarargsError {
311+
#[inline]
312+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313+
match &self {
314+
VarargsError::ArgumentTypeError(e) => e.fmt(f),
315+
VarargsError::ArgumentLengthError(e) => e.fmt(f),
316+
}
317+
}
318+
}
319+
320+
impl From<ArgumentTypeError> for VarargsError {
321+
#[inline]
322+
fn from(value: ArgumentTypeError) -> Self {
323+
Self::ArgumentTypeError(value)
324+
}
325+
}
326+
327+
impl From<ArgumentLengthError> for VarargsError {
328+
#[inline]
329+
fn from(value: ArgumentLengthError) -> Self {
330+
Self::ArgumentLengthError(value)
331+
}
332+
}
333+
334+
/// Error to argument type do not match.
335+
#[derive(Debug)]
336+
pub struct ArgumentTypeError {
337+
index: usize,
338+
nested_error: FromVariantError,
339+
}
340+
341+
impl ArgumentTypeError {
342+
/// Create a new error with the argument position and `FromVariantError`.
343+
#[inline]
344+
#[must_use]
345+
pub fn new(index: usize, nested_error: FromVariantError) -> Self {
346+
Self {
347+
index,
348+
nested_error,
349+
}
350+
}
351+
352+
/// Returns an ordinal number representation.
353+
#[inline]
354+
#[must_use]
355+
fn ordinal(&self) -> String {
356+
match self.index + 1 {
357+
1 => "1st".to_owned(),
358+
2 => "2nd".to_owned(),
359+
3 => "3rd".to_owned(),
360+
i @ 4.. => format!("{i}th"),
361+
_ => "unknown".to_owned(),
362+
}
363+
}
364+
365+
/// Get the argument type error's index.
366+
#[inline]
367+
#[must_use]
368+
pub fn index(&self) -> usize {
369+
self.index
370+
}
371+
372+
/// Get a reference to the argument type error's nested error.
373+
#[inline]
374+
#[must_use]
375+
pub fn nested_error(&self) -> &FromVariantError {
376+
&self.nested_error
377+
}
378+
}
379+
380+
impl std::error::Error for ArgumentTypeError {}
381+
impl std::fmt::Display for ArgumentTypeError {
382+
#[inline]
383+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384+
write!(
385+
f,
386+
"Incorrect type of {} argument, Cause: {}",
387+
self.ordinal(),
388+
self.nested_error,
389+
)
390+
}
391+
}
392+
393+
/// Error to argument lengths do not match.
394+
#[derive(Debug)]
395+
pub struct ArgumentLengthError {
396+
passed: usize,
397+
expected_min: usize,
398+
expected_max: usize,
399+
}
400+
401+
impl ArgumentLengthError {
402+
/// Creates a new error with the length of the arguments passed and the expected arguments range.
403+
#[inline]
404+
#[must_use]
405+
pub fn new(passed: usize, expected: impl ArgumentBounds) -> Self {
406+
Self {
407+
passed,
408+
expected_min: expected.start_bound(),
409+
expected_max: expected.end_bound(),
410+
}
411+
}
412+
413+
/// Get the argument length error's passed.
414+
#[inline]
415+
#[must_use]
416+
pub fn passed(&self) -> usize {
417+
self.passed
418+
}
419+
420+
/// Get the argument length error's expected min.
421+
#[inline]
422+
#[must_use]
423+
pub fn expected_min(&self) -> usize {
424+
self.expected_min
425+
}
426+
427+
/// Get the argument length error's expected max.
428+
#[inline]
429+
#[must_use]
430+
pub fn expected_max(&self) -> usize {
431+
self.expected_max
432+
}
433+
}
434+
435+
impl std::error::Error for ArgumentLengthError {}
436+
impl std::fmt::Display for ArgumentLengthError {
437+
#[inline]
438+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439+
let expected_msg = match (self.expected_min, self.expected_max) {
440+
(usize::MIN, usize::MAX) => "any".to_owned(),
441+
(usize::MIN, e) => format!("max {e}"),
442+
(s, usize::MAX) => format!("min {s}"),
443+
(s, e) => {
444+
if s == e {
445+
s.to_string()
446+
} else {
447+
format!("min {s} and max {e}")
448+
}
449+
}
450+
};
451+
write!(
452+
f,
453+
"Argument lengths do not match, passed {}, expected {}",
454+
self.passed, expected_msg
455+
)
456+
}
457+
}
458+
459+
/// Produced by range syntax like `a`, `(a, b)`, ..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`.
460+
pub trait ArgumentBounds {
461+
/// Start index bound.
462+
fn start_bound(&self) -> usize;
463+
/// End index bound.
464+
fn end_bound(&self) -> usize;
465+
466+
/// Returns true if item is contained in the range.
467+
#[inline]
468+
fn contains<U>(&self, item: &U) -> bool
469+
where
470+
usize: PartialOrd<U>,
471+
U: ?Sized + PartialOrd<usize>,
472+
{
473+
(self.start_bound() <= *item) && (*item <= self.end_bound())
474+
}
475+
}
476+
477+
impl ArgumentBounds for usize {
478+
#[inline]
479+
fn start_bound(&self) -> usize {
480+
*self
481+
}
482+
483+
#[inline]
484+
fn end_bound(&self) -> usize {
485+
*self
486+
}
487+
}
488+
489+
impl ArgumentBounds for (Bound<usize>, Bound<usize>) {
490+
#[inline]
491+
fn start_bound(&self) -> usize {
492+
match self.0 {
493+
Bound::Included(s) => s,
494+
Bound::Excluded(s) => s + 1,
495+
Bound::Unbounded => usize::MIN,
496+
}
497+
}
498+
499+
#[inline]
500+
fn end_bound(&self) -> usize {
501+
match self.1 {
502+
Bound::Included(e) => e,
503+
Bound::Excluded(e) => e - 1,
504+
Bound::Unbounded => usize::MAX,
505+
}
506+
}
507+
}
508+
509+
impl ArgumentBounds for std::ops::Range<usize> {
510+
#[inline]
511+
fn start_bound(&self) -> usize {
512+
self.start
513+
}
514+
515+
#[inline]
516+
fn end_bound(&self) -> usize {
517+
self.end - 1
518+
}
519+
}
520+
521+
impl ArgumentBounds for std::ops::RangeFrom<usize> {
522+
#[inline]
523+
fn start_bound(&self) -> usize {
524+
self.start
525+
}
526+
527+
#[inline]
528+
fn end_bound(&self) -> usize {
529+
usize::MAX
530+
}
531+
}
532+
533+
impl ArgumentBounds for std::ops::RangeInclusive<usize> {
534+
#[inline]
535+
fn start_bound(&self) -> usize {
536+
*self.start()
537+
}
538+
539+
#[inline]
540+
fn end_bound(&self) -> usize {
541+
*self.end()
542+
}
543+
}
544+
545+
impl ArgumentBounds for std::ops::RangeTo<usize> {
546+
#[inline]
547+
fn start_bound(&self) -> usize {
548+
usize::MIN
549+
}
550+
551+
#[inline]
552+
fn end_bound(&self) -> usize {
553+
self.end - 1
554+
}
555+
}
556+
557+
impl ArgumentBounds for std::ops::RangeToInclusive<usize> {
558+
#[inline]
559+
fn start_bound(&self) -> usize {
560+
usize::MIN
561+
}
562+
563+
#[inline]
564+
fn end_bound(&self) -> usize {
565+
self.end
566+
}
567+
}
568+
569+
impl ArgumentBounds for std::ops::RangeFull {
570+
#[inline]
571+
fn start_bound(&self) -> usize {
572+
usize::MIN
573+
}
574+
575+
#[inline]
576+
fn end_bound(&self) -> usize {
577+
usize::MAX
578+
}
579+
}
580+
301581
/// Trait for structures that can be parsed from `Varargs`.
302582
///
303583
/// This trait can be derived for structure types where each type implements `FromVariant`.

0 commit comments

Comments
 (0)