Strict Mode
Strict mode rejects lossy type conversions that would silently widen or truncate values. When enabled, out-of-range values panic instead of being coerced.
Strict mode rejects lossy type conversions that would silently widen or truncate values. When enabled, out-of-range values panic instead of being coerced.
πWhat It Affects
Strict mode applies to lossy integer types only: types where Rβs native
integer range (i32, excluding NA_integer_) cannot represent all values:
| Type | Scalar | Vec | Option | Vec<Option> | Option<Vec> | Vec<Vec> | Vec<Option<Vec>> |
|---|---|---|---|---|---|---|---|
i64 | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
u64 | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
isize | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
usize | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
The last three columns are return types only. Strict returns also support
Box<[T]>, &[T], [T; N], their optional forms, and list rows held in
slices, boxes or arrays (Vec<&[T]>, Vec<Option<&[T]>>, Vec<Box<[T]>>,
Vec<[T; N]>, including optional boxed/array rows). They use the same integer
range checks and batch every failing element across all rows. A missing
container or row is NULL; an empty container or row is an empty integer vector.
Types like i32, f64, String, bool are not affected. They have
lossless R representations.
πBehavior Comparison
πOutput (Rust β R)
Normal mode: Values outside i32 range silently widen to f64 (REALSXP).
// Normal: 2^40 silently becomes double
let big: i64 = 1_099_511_627_776;
big.into_sexp() // β REALSXP (double)
Strict mode: Values outside i32 range panic.
#[miniextendr(strict)]
pub fn strict_big() -> i64 {
1_099_511_627_776 // PANIC: i64 value outside R integer range
}
Valid range: (i32::MIN, i32::MAX] (note i32::MIN (-2147483648) is excluded
because it represents NA_integer_ in R).
πInput (R β Rust)
Normal mode: Accepts INTSXP, REALSXP, RAWSXP, and LGLSXP with coercion.
# Normal: logical TRUE coerced to i64
my_func(TRUE) # OK β 1i64
my_func(1L) # OK β 1i64
my_func(1.0) # OK β 1i64
my_func(as.raw(1)) # OK β 1i64
Strict mode: Only accepts INTSXP and REALSXP. Rejects RAWSXP and LGLSXP. REALSXP values must be whole numbers in range.
# Strict: only numeric types accepted
strict_func(1L) # OK
strict_func(1.0) # OK (whole number)
strict_func(1.5) # PANIC: fractional value
strict_func(TRUE) # PANIC: expected integer or double, got LGLSXP
strict_func(as.raw(1)) # PANIC: expected integer or double, got RAWSXPπHow to Enable
πPer-Function
#[miniextendr(strict)]
pub fn exact_value(x: i64) -> i64 { x }πPer-Impl Block
#[miniextendr(s3, strict)]
impl Calculator {
pub fn compute(&self, n: u64) -> u64 { n * 2 }
}πPer-Function Override
#[miniextendr(strict)] // impl-level: strict
impl Calculator {
pub fn normal_method(&self, x: i64) -> i64 { x } // strict (inherited)
#[miniextendr(no_strict)]
pub fn relaxed_method(&self, x: i64) -> i64 { x } // not strict (overridden)
}πProject-Wide Default
In Cargo.toml:
[dependencies]
miniextendr-api = { version = "0.1", features = ["strict-default"] }
When strict-default is enabled, all #[miniextendr] functions default to strict.
Use #[miniextendr(no_strict)] to opt out.
πError Messages
A rejected input (a logical, raw, fractional, out-of-range or NA value
for a lossy integer parameter) is an argument error, the same condition as
any other failed conversion (kind = "conversion", e$param, e$rust_type;
see ERROR_HANDLING.md). A vector
reports every failing element at once, with Rβs 1-based positions:
'count' must be a single whole number: got logical
'ids' must be integer or whole-number numeric: precision loss (elements 2, 4); NA is not allowed (element 3)
A return value that does not fit an R integer is a panic (kind = "panic"), caught and converted to an R error; a vector names its Rust type
and the positions in the returned vector:
strict conversion failed: i64 value 1099511627776 is outside R integer range
(-2147483647..=2147483647); use a non-strict function to allow lossy f64 wideningstrict conversion failed for Vec<i64>: i64 value 1099511627776 is outside R integer
range (-2147483647..=2147483647) (element 2); use a non-strict function to allow lossy
f64 widening
A list of vectors (Vec<Vec<usize>>) checks every row before it fails, and
names each failing valueβs row (element) and its place in the row:
strict conversion failed for Vec<Vec<usize>>: usize value 3000000000 exceeds R
integer max (2147483647) at inner position 1 (element 2); use a non-strict function
to allow lossy f64 wideningπWhen to Use Strict Mode
Use strict when:
- Building numeric-critical APIs where silent precision loss is a bug
- Working with database IDs, timestamps, or bit flags that must be exact
- You want to catch accidental type coercions during development
Skip strict when:
- Values are known to be small (fit in i32)
- Approximate f64 representation is acceptable
- You want maximum R interoperability (accept any numeric-like input)
πSee Also
- MINIEXTENDR_ATTRIBUTE.md:
strictattribute reference - TYPE_CONVERSIONS.md: normal conversion behavior
- FEATURE_DEFAULTS.md: project-wide feature flags