miniextendr_api/newtype.rs
1//! Container conversions for newtypes and string-parsed types.
2//!
3//! `#[derive(TryFromSexp)]` / `#[derive(IntoR)]` on a single-field newtype
4//! (`struct UserId(Uuid)`) emit the scalar forwarding impls *and* a small marker
5//! impl from this module. The container blankets here then light up
6//! `Vec<UserId>`, `Option<UserId>`, and `Vec<Option<UserId>>` automatically — the
7//! newtype inherits the inner type's exact SEXPTYPE checks, NA policy, error
8//! text and `TryFromSexp::CHARACTER_ONLY` in every shape.
9//!
10//! A type parsed from an R string gets the same three shapes from
11//! [`try_from_sexp_via_str_parse!`](crate::try_from_sexp_via_str_parse), which
12//! implements [`TryFromSexpElement`] with
13//! [`ParsedRStr`](crate::from_r::ParsedRStr) as the inner type (#1766).
14//!
15//! # The containers forward; a check refuses
16//!
17//! The containers never call the element's own `TryFromSexp::try_from_sexp`.
18//! `Option<T>` reads `Option<T::Inner>`, `Vec<T>` reads `Vec<T::Inner>` and
19//! `Vec<Option<T>>` reads `Vec<Option<T::Inner>>`, each wrapping what it
20//! read with [`TryFromSexpElement::from_inner`]. So an element's scalar
21//! `try_from_sexp` must be the inner type's followed by `from_inner`, which
22//! is what the derive emits, and refusing values a type's inner type
23//! accepts belongs in [`TryFromSexpElement::check_sexp`], not in
24//! `try_from_sexp`. The check runs on the R value before it is read, in the
25//! scalar `try_from_sexp`, on a non-`NULL` input for `Option<T>` (`NULL` is
26//! "not given"), and for `Vec<T>` / `Vec<Option<T>>` where R keeps the
27//! element's class. `#[derive(TryFromSexp)]` takes it as
28//! `#[try_from_sexp(validate = path)]` (#1815).
29//!
30//! # Where a `Vec`'s check runs: the inner container decides
31//!
32//! An atomic vector keeps one class for all its elements, on the vector; a
33//! list of R objects keeps a class on each element. So the `Vec` blankets
34//! don't run the check themselves: they pass `T::check_sexp` to the inner
35//! container's hidden
36//! [`TryFromSexp::__mx_try_from_sexp_with_check`]
37//! (#1837). Its default runs the check once on the whole input, which every
38//! atomic inner container keeps. `Vec<List>` and `Vec<Option<List>>` override
39//! it to run the check on each element (but `NULL`) and to report every
40//! failing element in one error, with its position. The blankets override it
41//! too, adding their own check after the one they are given, so a newtype of a
42//! newtype over `List` checks each element, outer check first, as its scalar
43//! does.
44//!
45//! This keeps one blanket per container slot and one element trait: the
46//! choice follows the inner type, through an impl that only `miniextendr-api`
47//! can write (`Vec<List>`), not a second marker trait a downstream type could
48//! implement next to `TryFromSexpElement`. The `Option<T>` blanket runs the
49//! check itself: a scalar keeps its class on itself whatever its inner type.
50//!
51//! # Why the markers live here and not in the derive
52//!
53//! A downstream crate cannot write `impl TryFromSexp for Vec<MyNewtype>`: `Vec` /
54//! `Option` are not `#[fundamental]`, so the local newtype is "covered" and the
55//! orphan rule (E0117) forbids it. The container impls must live in
56//! `miniextendr-api`, keyed on a marker trait the derive *can* legally implement
57//! downstream (foreign trait + local `Self`). The blankets below are those
58//! container impls (#844).
59//!
60//! [`TryFromSexpElement`] / [`IntoRNewtype`] / [`IntoRVecElement`] are
61//! **plumbing**: they are emitted by the derives and by
62//! `try_from_sexp_via_str_parse!`, not implemented by hand. Implementing them
63//! manually is supported but unusual. A hand-written [`TryFromSexpElement`]
64//! also needs a `TryFromSexp` impl on the type for `Option<T>` to convert (the
65//! derive and the macro emit both), and that impl must keep the forwarding
66//! rule above: call [`TryFromSexpElement::check_sexp`], then convert the inner
67//! type and wrap it, and nothing else, since no container ever runs it.
68//!
69//! # One element trait per direction
70//!
71//! Each `TryFromSexp` container slot (`Vec<T>`, `Option<T>`, `Vec<Option<T>>`)
72//! holds exactly one blanket, keyed on [`TryFromSexpElement`]. A second blanket
73//! on another public trait (say, a parse trait) would collide with it (E0119):
74//! a downstream type could implement both, so coherence cannot prove them
75//! disjoint. So every non-built-in element goes through this one trait, and
76//! what differs is the inner type the containers read first: the newtype's
77//! field type, or `ParsedRStr<T>` for a string-parsed type, whose container
78//! impls in `from_r` hold the NA policy and the batched element errors.
79//!
80//! Every container's error is [`SexpError`]: the inner container's error
81//! converts into it, and so does a check's refusal
82//! ([`SexpError::Condition`], carrying
83//! its own classes). The inner containers that exist are all `miniextendr-api`
84//! impls (the orphan rule keeps the rest out), and each one's error is a
85//! `SexpError` or converts into one.
86//!
87//! The blankets bound the inner type through the hidden `VecInner` /
88//! `OptionInner` / `VecOptionInner` helpers rather than
89//! `Vec<T::Inner>: TryFromSexp`. For a type that is not an element,
90//! `T::Inner` cannot be normalized; with the projection as the bound's self
91//! type, the solver gives up on it at once and reports
92//! `T: TryFromSexpElement` as unsatisfied (E0277). Spelled
93//! `Vec<T::Inner>: TryFromSexp`, the same bound sent the solver through
94//! every `Vec<_>` impl (`Vec<Vec<_>>` nests one level per step) until it
95//! overflowed (E0275, #1682).
96//!
97//! # The asymmetries
98//!
99//! Five of the six container shapes are granted. Two are not, for two different
100//! coherence reasons:
101//!
102//! - **`IntoR for Vec<T>` (granted, but shared).** This slot has exactly one
103//! blanket and `MatchArg` already needs it (`Vec<MyEnum>` → STRSXP). Rather
104//! than a second, conflicting `Vec<T>` blanket (E0119), both paths funnel
105//! through [`IntoRVecElement`]: `MatchArg` types reach it via a bridge blanket
106//! in `match_arg.rs`, newtypes via a concrete impl emitted by
107//! `#[derive(IntoR)]`. A type that is *both* a `MatchArg` enum and an `IntoR`
108//! newtype is a coherence error — don't derive both on one type.
109//! - **`IntoR for Option<T>` (not granted).** A bare `Option<T>` blanket
110//! collides with the pre-existing `impl<T: Copy + IntoR> IntoR for Option<&T>`:
111//! `&T` is `#[fundamental]`, so a downstream crate could impl `IntoRNewtype`
112//! for `&LocalType` and coherence cannot prove the two disjoint. Return
113//! `Option<Inner>` (`opt.map(|x| x.0)`) instead. See the note on the missing
114//! blanket below.
115//!
116//! `TryFromSexp for Vec<T>` / `Option<T>` / `Vec<Option<T>>` and `IntoR for
117//! Vec<Option<T>>` are coherence-free: no other blanket occupies those slots.
118//! The concrete `TryFromSexp for Vec<List>` / `Vec<Option<List>>` impls sit
119//! beside them because `List` is not a `TryFromSexpElement`, and no other
120//! crate can make it one (both are `miniextendr-api`'s).
121
122use crate::from_r::{ElementCheck, NativeBorrow, SexpError, TryFromSexp, no_element_check};
123use crate::into_r::IntoR;
124use crate::{SEXP, SEXPTYPE, SexpExt};
125
126// region: marker traits (emitted by the derives, not hand-written)
127
128/// The element side of the `TryFromSexp` impls for `Vec<T>`, `Option<T>` and
129/// `Vec<Option<T>>` (R → Rust).
130///
131/// Each container of `Self` is read as the same container of
132/// [`Inner`](Self::Inner), then every element is wrapped with
133/// [`from_inner`](Self::from_inner): `Vec<Self>` reads `Vec<Self::Inner>`,
134/// `Option<Self>` reads `Option<Self::Inner>`, and `Vec<Option<Self>>` reads
135/// `Vec<Option<Self::Inner>>`. Each shape exists when the inner container
136/// converts, independently of the other two, and keeps its NA policy and
137/// metadata (`NATIVE_BORROW`, `CHARACTER_ONLY`); its error converts into
138/// [`SexpError`].
139///
140/// # Forwarding
141///
142/// No container calls `<Self as TryFromSexp>::try_from_sexp`. They read the
143/// inner type and wrap it, so the element's own `try_from_sexp`, when it has
144/// one, must do the same: [`check_sexp`](Self::check_sexp), then the inner
145/// type's conversion, then [`from_inner`](Self::from_inner). Anything else
146/// it did would hold for a scalar argument and silently not for
147/// `Option<Self>`, `Vec<Self>` or `Vec<Option<Self>>`. A value the inner type
148/// accepts but `Self` refuses is refused in `check_sexp`, which every shape
149/// runs.
150///
151/// Emitted by `#[derive(TryFromSexp)]` (the inner type is the newtype's field;
152/// `#[try_from_sexp(validate = path)]` gives the check) and by
153/// [`try_from_sexp_via_str_parse!`](crate::try_from_sexp_via_str_parse)
154/// (the inner type is [`ParsedRStr<Self>`](crate::from_r::ParsedRStr)). See
155/// the module docs for why both share this one trait.
156#[diagnostic::on_unimplemented(
157 message = "this `Vec` or `Option` of `{Self}` has no conversion from R",
158 label = "`{Self}` does not implement `TryFromSexpElement`",
159 note = "`Vec<T>`, `Option<T>` and `Vec<Option<T>>` convert from R for the built-in types, `#[derive(TryFromSexp)]` newtypes over a type whose container converts, and types given `try_from_sexp_via_str_parse!`"
160)]
161pub trait TryFromSexpElement: Sized {
162 /// The type whose containers are read first.
163 type Inner;
164
165 /// Wrap an inner value into `Self`.
166 fn from_inner(inner: Self::Inner) -> Self;
167
168 /// Refuse an R value before it is read: `Err` for a value the inner type
169 /// would accept but `Self` must not, such as a number that carries a unit
170 /// class (`difftime`, `Date`, `POSIXct`).
171 ///
172 /// Called with the input of every shape, before its inner conversion: by
173 /// the scalar `TryFromSexp` (the derive's calls it), for `Option<Self>`
174 /// on any input but `NULL`, which stays "not given", and for `Vec<Self>`
175 /// and `Vec<Option<Self>>` where R keeps the element's class: once on the
176 /// whole vector for an atomic inner type, on each element (but `NULL`)
177 /// for a list of R objects (`Self::Inner` is `List`, or a newtype over
178 /// it). It sees the value as R holds it, attributes and all, before
179 /// anything is read from it.
180 ///
181 /// Return an [`RError`](crate::condition::RError), or any
182 /// [`RConditionData`](crate::condition::RConditionData) type, with `?`
183 /// or `.into()` to give the refusal its own classes and fields
184 /// ([`SexpError::Condition`]). As an
185 /// argument error it keeps the wrapper's context: `'<p>' must be
186 /// <expected>: <message>`, the classes before the crate's
187 /// `conversion_error_class`, `e$param` and `e$rust_type`. A plain
188 /// `SexpError` (`SexpError::InvalidValue`) works too, with no classes.
189 ///
190 /// The default accepts every value; it is what the derive emits without
191 /// `validate` and what a string-parsed type has.
192 #[inline]
193 fn check_sexp(_sexp: SEXP) -> Result<(), SexpError> {
194 Ok(())
195 }
196}
197
198/// Unwrap a forwarding newtype into its inner value (Rust → R side).
199///
200/// Emitted by `#[derive(IntoR)]`. Powers the `IntoR` container blankets for
201/// `Option<T>` / `Vec<Option<T>>` in this module.
202pub trait IntoRNewtype {
203 /// The wrapped inner type, whose conversions are forwarded to.
204 type Inner;
205
206 /// Unwrap the newtype into its inner value.
207 fn into_inner(self) -> Self::Inner;
208}
209
210/// How a `Vec<Self>` becomes a single R vector SEXP.
211///
212/// This is the shared element-marker behind the **one** `impl<T: …> IntoR for
213/// Vec<T>` blanket slot. Implemented concretely per type — by `#[derive(IntoR)]`
214/// for newtypes (forwarding to `Vec<Inner>`), and by the `MatchArg` bridge in
215/// `match_arg.rs` for `match.arg` enums (STRSXP by variant name). See the module
216/// docs for why this cannot be two competing blankets.
217pub trait IntoRVecElement: Sized {
218 /// Convert all elements into one R vector SEXP.
219 fn elements_into_sexp(values: Vec<Self>) -> SEXP;
220}
221
222// endregion
223
224// region: container helpers (bound on the inner type itself, #1682)
225
226/// `Vec<Self>: TryFromSexp` with an error that converts into [`SexpError`],
227/// with `Self` as the bound's self type.
228///
229/// Plumbing for the `Vec<T>` blanket below: see the module docs (#1682).
230#[doc(hidden)]
231pub trait VecInner: Sized {
232 /// `<Vec<Self> as TryFromSexp>::NATIVE_BORROW`.
233 const VEC_NATIVE_BORROW: Option<NativeBorrow>;
234 /// `<Vec<Self> as TryFromSexp>::CHARACTER_ONLY`.
235 const VEC_CHARACTER_ONLY: bool;
236 /// `<Vec<Self> as TryFromSexp>::__mx_try_from_sexp_with_check`: the
237 /// vector, with `check` run where `Vec<Self>` keeps an element's class.
238 fn vec_try_from_sexp(sexp: SEXP, check: &ElementCheck<'_>) -> Result<Vec<Self>, SexpError>;
239 /// `<Vec<Self> as TryFromSexp>::__mx_try_from_sexp_unchecked_with_check`.
240 ///
241 /// # Safety
242 ///
243 /// As [`TryFromSexp::try_from_sexp_unchecked`].
244 unsafe fn vec_try_from_sexp_unchecked(
245 sexp: SEXP,
246 check: &ElementCheck<'_>,
247 ) -> Result<Vec<Self>, SexpError>;
248}
249
250impl<I> VecInner for I
251where
252 Vec<I>: TryFromSexp,
253 <Vec<I> as TryFromSexp>::Error: Into<SexpError>,
254{
255 const VEC_NATIVE_BORROW: Option<NativeBorrow> = <Vec<I> as TryFromSexp>::NATIVE_BORROW;
256 const VEC_CHARACTER_ONLY: bool = <Vec<I> as TryFromSexp>::CHARACTER_ONLY;
257
258 #[inline]
259 fn vec_try_from_sexp(sexp: SEXP, check: &ElementCheck<'_>) -> Result<Vec<Self>, SexpError> {
260 <Vec<I> as TryFromSexp>::__mx_try_from_sexp_with_check(sexp, check)
261 }
262
263 #[inline]
264 unsafe fn vec_try_from_sexp_unchecked(
265 sexp: SEXP,
266 check: &ElementCheck<'_>,
267 ) -> Result<Vec<Self>, SexpError> {
268 unsafe { <Vec<I> as TryFromSexp>::__mx_try_from_sexp_unchecked_with_check(sexp, check) }
269 }
270}
271
272/// `Option<Self>: TryFromSexp` with an error that converts into
273/// [`SexpError`], with `Self` as the bound's self type.
274///
275/// Plumbing for the `Option<T>` blanket below: see the module docs (#1682).
276#[doc(hidden)]
277pub trait OptionInner: Sized {
278 /// `<Option<Self> as TryFromSexp>::NATIVE_BORROW`.
279 const OPTION_NATIVE_BORROW: Option<NativeBorrow>;
280 /// `<Option<Self> as TryFromSexp>::CHARACTER_ONLY`.
281 const OPTION_CHARACTER_ONLY: bool;
282 /// `<Option<Self> as TryFromSexp>::try_from_sexp`, its error as a
283 /// [`SexpError`].
284 fn option_try_from_sexp(sexp: SEXP) -> Result<Option<Self>, SexpError>;
285 /// `<Option<Self> as TryFromSexp>::try_from_sexp_unchecked`, its error as
286 /// a [`SexpError`].
287 ///
288 /// # Safety
289 ///
290 /// As [`TryFromSexp::try_from_sexp_unchecked`].
291 unsafe fn option_try_from_sexp_unchecked(sexp: SEXP) -> Result<Option<Self>, SexpError>;
292}
293
294impl<I> OptionInner for I
295where
296 Option<I>: TryFromSexp,
297 <Option<I> as TryFromSexp>::Error: Into<SexpError>,
298{
299 const OPTION_NATIVE_BORROW: Option<NativeBorrow> = <Option<I> as TryFromSexp>::NATIVE_BORROW;
300 const OPTION_CHARACTER_ONLY: bool = <Option<I> as TryFromSexp>::CHARACTER_ONLY;
301
302 #[inline]
303 fn option_try_from_sexp(sexp: SEXP) -> Result<Option<Self>, SexpError> {
304 <Option<I> as TryFromSexp>::try_from_sexp(sexp).map_err(Into::into)
305 }
306
307 #[inline]
308 unsafe fn option_try_from_sexp_unchecked(sexp: SEXP) -> Result<Option<Self>, SexpError> {
309 unsafe { <Option<I> as TryFromSexp>::try_from_sexp_unchecked(sexp) }.map_err(Into::into)
310 }
311}
312
313/// `Vec<Option<Self>>: TryFromSexp` with an error that converts into
314/// [`SexpError`], with `Self` as the bound's self type.
315///
316/// Plumbing for the `Vec<Option<T>>` blanket below: see the module docs
317/// (#1682).
318#[doc(hidden)]
319pub trait VecOptionInner: Sized {
320 /// `<Vec<Option<Self>> as TryFromSexp>::NATIVE_BORROW`.
321 const VEC_OPTION_NATIVE_BORROW: Option<NativeBorrow>;
322 /// `<Vec<Option<Self>> as TryFromSexp>::CHARACTER_ONLY`.
323 const VEC_OPTION_CHARACTER_ONLY: bool;
324 /// `<Vec<Option<Self>> as TryFromSexp>::__mx_try_from_sexp_with_check`:
325 /// the vector, with `check` run where `Vec<Option<Self>>` keeps an
326 /// element's class.
327 fn vec_option_try_from_sexp(
328 sexp: SEXP,
329 check: &ElementCheck<'_>,
330 ) -> Result<Vec<Option<Self>>, SexpError>;
331 /// `<Vec<Option<Self>> as TryFromSexp>::__mx_try_from_sexp_unchecked_with_check`.
332 ///
333 /// # Safety
334 ///
335 /// As [`TryFromSexp::try_from_sexp_unchecked`].
336 unsafe fn vec_option_try_from_sexp_unchecked(
337 sexp: SEXP,
338 check: &ElementCheck<'_>,
339 ) -> Result<Vec<Option<Self>>, SexpError>;
340}
341
342impl<I> VecOptionInner for I
343where
344 Vec<Option<I>>: TryFromSexp,
345 <Vec<Option<I>> as TryFromSexp>::Error: Into<SexpError>,
346{
347 const VEC_OPTION_NATIVE_BORROW: Option<NativeBorrow> =
348 <Vec<Option<I>> as TryFromSexp>::NATIVE_BORROW;
349 const VEC_OPTION_CHARACTER_ONLY: bool = <Vec<Option<I>> as TryFromSexp>::CHARACTER_ONLY;
350
351 #[inline]
352 fn vec_option_try_from_sexp(
353 sexp: SEXP,
354 check: &ElementCheck<'_>,
355 ) -> Result<Vec<Option<Self>>, SexpError> {
356 <Vec<Option<I>> as TryFromSexp>::__mx_try_from_sexp_with_check(sexp, check)
357 }
358
359 #[inline]
360 unsafe fn vec_option_try_from_sexp_unchecked(
361 sexp: SEXP,
362 check: &ElementCheck<'_>,
363 ) -> Result<Vec<Option<Self>>, SexpError> {
364 unsafe {
365 <Vec<Option<I>> as TryFromSexp>::__mx_try_from_sexp_unchecked_with_check(sexp, check)
366 }
367 }
368}
369
370// endregion
371
372// region: IntoR for Vec<T> — the unified element-marker blanket
373
374/// The single `IntoR for Vec<T>` blanket, shared by `MatchArg` enums and
375/// `#[derive(IntoR)]` newtypes via [`IntoRVecElement`]. Coexists with the
376/// concrete `impl IntoR for Vec<i32>` (etc.) impls: `IntoRVecElement` is
377/// crate-local, so coherence proves the foreign R-native types do not implement
378/// it.
379impl<T: IntoRVecElement> IntoR for Vec<T> {
380 type Error = std::convert::Infallible;
381
382 #[inline]
383 fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
384 Ok(self.into_sexp())
385 }
386
387 #[inline]
388 unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
389 self.try_into_sexp()
390 }
391
392 #[inline]
393 fn into_sexp(self) -> SEXP {
394 T::elements_into_sexp(self)
395 }
396}
397
398// endregion
399
400// region: TryFromSexp container blankets (R → Rust)
401
402// The `Vec` blankets hand `T::check_sexp`, after the check of any enclosing
403// newtype, to the inner container's `__mx_try_from_sexp_with_check`, which
404// runs it where that container keeps an element's class: once on the whole
405// input for an atomic vector, on each element for a list of R objects
406// (#1837). They then wrap what was read with `T::from_inner`. `Option<T>`
407// runs the check itself, on a non-`NULL` input. None calls
408// `T::try_from_sexp`: see "Forwarding" on `TryFromSexpElement`.
409
410impl<T: TryFromSexpElement> TryFromSexp for Vec<T>
411where
412 T::Inner: VecInner,
413{
414 type Error = SexpError;
415 const NATIVE_BORROW: Option<NativeBorrow> = <T::Inner as VecInner>::VEC_NATIVE_BORROW;
416 const CHARACTER_ONLY: bool = <T::Inner as VecInner>::VEC_CHARACTER_ONLY;
417
418 #[inline]
419 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
420 Self::__mx_try_from_sexp_with_check(sexp, &no_element_check)
421 }
422
423 #[inline]
424 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
425 unsafe { Self::__mx_try_from_sexp_unchecked_with_check(sexp, &no_element_check) }
426 }
427
428 #[inline]
429 fn __mx_try_from_sexp_with_check(
430 sexp: SEXP,
431 check: &ElementCheck<'_>,
432 ) -> Result<Self, SexpError> {
433 let check = |x: SEXP| {
434 check(x)?;
435 T::check_sexp(x)
436 };
437 Ok(<T::Inner as VecInner>::vec_try_from_sexp(sexp, &check)?
438 .into_iter()
439 .map(T::from_inner)
440 .collect())
441 }
442
443 #[inline]
444 unsafe fn __mx_try_from_sexp_unchecked_with_check(
445 sexp: SEXP,
446 check: &ElementCheck<'_>,
447 ) -> Result<Self, SexpError> {
448 let check = |x: SEXP| {
449 check(x)?;
450 T::check_sexp(x)
451 };
452 Ok(
453 unsafe { <T::Inner as VecInner>::vec_try_from_sexp_unchecked(sexp, &check) }?
454 .into_iter()
455 .map(T::from_inner)
456 .collect(),
457 )
458 }
459}
460
461// `T: TryFromSexp` lets `__mx_has_na` ask the element itself
462// (`TryFromSexpElement` has no inner accessor, and an override cannot add a
463// bound, E0276). The derive and the str-parse macro always emit both impls.
464impl<T: TryFromSexpElement + TryFromSexp> TryFromSexp for Option<T>
465where
466 T::Inner: OptionInner,
467{
468 type Error = SexpError;
469 const NATIVE_BORROW: Option<NativeBorrow> = <T::Inner as OptionInner>::OPTION_NATIVE_BORROW;
470 const CHARACTER_ONLY: bool = <T::Inner as OptionInner>::OPTION_CHARACTER_ONLY;
471 // `NULL` (`None`) is "not given" and passes `no_na`.
472 #[inline]
473 fn __mx_has_na(&self) -> bool {
474 self.as_ref().is_some_and(T::__mx_has_na)
475 }
476
477 // `NULL` is "not given" too, so the check sees only a value.
478 #[inline]
479 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
480 if sexp.type_of() != SEXPTYPE::NILSXP {
481 T::check_sexp(sexp)?;
482 }
483 Ok(<T::Inner as OptionInner>::option_try_from_sexp(sexp)?.map(T::from_inner))
484 }
485
486 #[inline]
487 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
488 if sexp.type_of() != SEXPTYPE::NILSXP {
489 T::check_sexp(sexp)?;
490 }
491 Ok(
492 unsafe { <T::Inner as OptionInner>::option_try_from_sexp_unchecked(sexp) }?
493 .map(T::from_inner),
494 )
495 }
496}
497
498impl<T: TryFromSexpElement> TryFromSexp for Vec<Option<T>>
499where
500 T::Inner: VecOptionInner,
501{
502 type Error = SexpError;
503 const NATIVE_BORROW: Option<NativeBorrow> =
504 <T::Inner as VecOptionInner>::VEC_OPTION_NATIVE_BORROW;
505 const CHARACTER_ONLY: bool = <T::Inner as VecOptionInner>::VEC_OPTION_CHARACTER_ONLY;
506
507 #[inline]
508 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
509 Self::__mx_try_from_sexp_with_check(sexp, &no_element_check)
510 }
511
512 #[inline]
513 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
514 unsafe { Self::__mx_try_from_sexp_unchecked_with_check(sexp, &no_element_check) }
515 }
516
517 #[inline]
518 fn __mx_try_from_sexp_with_check(
519 sexp: SEXP,
520 check: &ElementCheck<'_>,
521 ) -> Result<Self, SexpError> {
522 let check = |x: SEXP| {
523 check(x)?;
524 T::check_sexp(x)
525 };
526 Ok(
527 <T::Inner as VecOptionInner>::vec_option_try_from_sexp(sexp, &check)?
528 .into_iter()
529 .map(|opt| opt.map(T::from_inner))
530 .collect(),
531 )
532 }
533
534 #[inline]
535 unsafe fn __mx_try_from_sexp_unchecked_with_check(
536 sexp: SEXP,
537 check: &ElementCheck<'_>,
538 ) -> Result<Self, SexpError> {
539 let check = |x: SEXP| {
540 check(x)?;
541 T::check_sexp(x)
542 };
543 Ok(unsafe {
544 <T::Inner as VecOptionInner>::vec_option_try_from_sexp_unchecked(sexp, &check)
545 }?
546 .into_iter()
547 .map(|opt| opt.map(T::from_inner))
548 .collect())
549 }
550}
551
552// endregion
553
554// region: IntoR container blankets (Rust → R) for Vec<Option>
555
556// NOTE: there is deliberately no `impl<T: IntoRNewtype> IntoR for Option<T>`.
557// That bare `Option<T>` blanket collides (E0119) with the pre-existing
558// `impl<T: Copy + IntoR> IntoR for Option<&T>` (into_r/large_integers.rs): `&T`
559// is `#[fundamental]`, so a downstream crate *could* implement `IntoRNewtype`
560// for `&LocalType`, and coherence cannot prove the two disjoint. Returning a
561// `Option<MyNewtype>` to R is the one shape the derive does not grant — map to
562// the inner first (`opt.map(|x| x.0)` → `Option<Inner>`), which mirrors the
563// NULL-vs-NA guidance already on the `Option<&T>` impl. See issue #844.
564
565impl<T: IntoRNewtype> IntoR for Vec<Option<T>>
566where
567 Vec<Option<T::Inner>>: IntoR,
568{
569 type Error = <Vec<Option<T::Inner>> as IntoR>::Error;
570
571 #[inline]
572 fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
573 self.into_iter()
574 .map(|opt| opt.map(T::into_inner))
575 .collect::<Vec<Option<T::Inner>>>()
576 .try_into_sexp()
577 }
578
579 #[inline]
580 unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
581 unsafe {
582 self.into_iter()
583 .map(|opt| opt.map(T::into_inner))
584 .collect::<Vec<Option<T::Inner>>>()
585 .try_into_sexp_unchecked()
586 }
587 }
588
589 #[inline]
590 fn into_sexp(self) -> SEXP {
591 self.into_iter()
592 .map(|opt| opt.map(T::into_inner))
593 .collect::<Vec<Option<T::Inner>>>()
594 .into_sexp()
595 }
596
597 #[inline]
598 unsafe fn into_sexp_unchecked(self) -> SEXP {
599 unsafe {
600 self.into_iter()
601 .map(|opt| opt.map(T::into_inner))
602 .collect::<Vec<Option<T::Inner>>>()
603 .into_sexp_unchecked()
604 }
605 }
606}
607
608// endregion