Skip to main content

arg_error

Macro arg_error 

Source
macro_rules! arg_error {
    (@param $call:expr; call $($rest:tt)*) => { ... };
    (@param $call:expr; param = $param:expr, call $($rest:tt)*) => { ... };
    (@param $call:expr; param = $param:expr, class $($rest:tt)*) => { ... };
    (@param $call:expr; param = $param:expr, data $($rest:tt)*) => { ... };
    (@param $call:expr; param = $param:expr, $($arg:tt)+) => { ... };
    (@param $call:expr; $($rest:tt)*) => { ... };
    (@no_class_or_data) => { ... };
    (call = none, $($rest:tt)*) => { ... };
    (call $($rest:tt)*) => { ... };
    ($($rest:tt)*) => { ... };
}
Expand description

Raise the argument error the generated R wrapper raises for a bad argument, from a #[miniextendr] function body.

arg_error!(param = "mode", "'mode' should be one of {}", choices) raises the condition of the wrapper’s own argument checks (match_arg, inherits, no_na, type preconditions) and of a failed argument conversion: kind = "conversion", e$param set to param (the argument’s R name), the message as formatted, and the crate’s conversion_error_class ([package.metadata.miniextendr]) before the rust_error layering:

class(e)
# [1] "pkg_error_argument" "pkg_error" "rust_error" "simpleError" "error" "condition"

Use it for a check that applies on some paths only, where a #[miniextendr] attribute on the parameter would check every call: an argument passed on to another function’s body, say, which skips that function’s R wrapper and its checks. crate::match_arg_param matches a raw choice argument with the wrapper’s semantics and message and raises through this macro.

It diverges like crate::error! (the same panic_any transport), and conditions queued with crate::defer_warning! & co. are signalled first. The call is the one the wrapper’s checks report: the wrapper’s call as written, or under #[miniextendr(call = caller)] its caller’s. A leading call = none raises it without a call, as for the other condition macros. There is no class = or data =: the classes are the crate’s and the only field is param, so the condition is the wrapper’s.

ⓘ
use miniextendr_api::{arg_error, miniextendr};

#[miniextendr]
pub fn in_metres(x: f64, unit: &str) -> f64 {
    match unit {
        "m" => x,
        "cm" => x / 100.0,
        _ => arg_error!(param = "unit", "'unit' should be one of \"m\", \"cm\""),
    }
}

§How the crate’s classes get there

A macro_rules! macro cannot read [package.metadata.miniextendr], so the tagged condition value carries the marker class CONVERSION_ERROR_CLASS_MARKER and the generated wrapper’s .miniextendr_raise_condition replaces it with .miniextendr_conversion_error_class, the binding its own checks use. Across a trait-ABI call the consumer package’s wrapper raises the condition, so its crate’s classes apply. A raising guard (an ALTREP RUnwind callback, with_r_unwind_protect_or_raise) has no generated R: it resolves the marker in Rust against the classes miniextendr_init! registered (on wasm32, the copy in the wasm_registry.rs snapshot), then raises the same condition, kind = "conversion" included (#1768). A connection callback returns its fallback, as for any panic.

The generated no_na check after a conversion builds the same condition with crate::error_value::arg_check_condition_value, which takes the classes the macro read at expansion time.

§Grammar

arg_error!([call = none,] param = <expr>, <format string>, <args>...). param is anything Into<String>. A call anywhere but first, a repeated one, a missing param, and class = / data = are compile errors:

ⓘ
mx::arg_error!(param = "mode", call = none, "bad");
ⓘ
mx::arg_error!("'mode' is bad");
ⓘ
mx::arg_error!(param = "mode", class = "pkg_error", "bad");
mx::arg_error!(call = none, param = "mode", "'mode' is {mode:?}")