Skip to main content

miniextendr_api/
visibility.rs

1//! Return-visibility markers: [`Invisible<T>`] and [`Visible<T>`].
2//!
3//! An R function's result is either printed at the console when the call is
4//! the top-level expression (visible) or not (invisible, as `invisible(x)`
5//! returns it). `#[miniextendr]` wrappers decide this per function or method:
6//!
7//! - A bare function whose R value is `NULL` (no return type, `-> ()`,
8//!   `Option<()>`, `Result<(), E>` on success) returns it invisibly, so a
9//!   side-effect call does not print `NULL`.
10//! - Every other return is visible, including a method that hands back its
11//!   receiver for chaining (`&mut self -> ()`, `&mut self -> &mut Self`,
12//!   `self -> Self`): `counter$increment()` prints the counter, exactly as an
13//!   R function returning `self` would.
14//!
15//! Wrapping the return type changes that decision without touching the
16//! value: `Invisible<T>` makes the wrapper return `invisible(...)`,
17//! `Visible<T>` forces a visible return where the default is invisible (a
18//! visible `NULL`, say). The attribute spelling, `#[miniextendr(invisible)]`
19//! / `#[miniextendr(visible)]` on a function or `r6(invisible)` & co. on a
20//! method, does the identical thing; use whichever reads better. A marker and
21//! an attribute that disagree are a compile error.
22//!
23//! ```ignore
24//! use miniextendr_api::{Invisible, miniextendr};
25//!
26//! #[derive(miniextendr_api::ExternalPtr)]
27//! pub struct Counter { n: i32 }
28//!
29//! #[miniextendr(r6)]
30//! impl Counter {
31//!     pub fn new() -> Self { Counter { n: 0 } }
32//!     /// Chainable and silent: `c$bump()` prints nothing, `c$bump()$bump()` works.
33//!     pub fn bump(&mut self) -> Invisible<()> { self.n += 1; Invisible(()) }
34//!     /// Chainable and visible (the default): `c$tick()` prints the counter.
35//!     pub fn tick(&mut self) { self.n += 1; }
36//!     /// A value returned invisibly, `withVisible(c$peek())$visible` is `FALSE`.
37//!     pub fn peek(&self) -> Invisible<i32> { Invisible(self.n) }
38//! }
39//! ```
40//!
41//! The marker is transparent everywhere else: `Invisible<Option<i32>>` gives
42//! `NA_integer_` for `None`, as `Option<i32>` does, `Invisible<Self>` still wraps the
43//! returned handle in the class, `Invisible<Result<T, E>>` still raises on
44//! `Err`. Both types implement [`IntoR`] by forwarding to `T`, so a value that
45//! reaches a conversion without the macro having peeled the marker (a type
46//! alias, a `use Invisible as Quiet` rename) still converts correctly; only
47//! the visibility falls back to the default. Markers are return-position only:
48//! `Invisible<T>` as a parameter type is a compile error, as is nesting one
49//! marker inside another.
50
51use crate::into_r::IntoR;
52
53/// Return-position marker: the R wrapper returns this value with
54/// `invisible()`. See the [module docs](self).
55#[repr(transparent)]
56#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Invisible<T> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Invisible",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Invisible<T> {
    #[inline]
    fn clone(&self) -> Self {
        Invisible(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for Invisible<T> { }Copy, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::marker::StructuralPartialEq for
    Invisible<T> {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Invisible<T> {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl<T: ::core::cmp::Eq> ::core::cmp::Eq for Invisible<T> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq<T>; }
}Eq, #[automatically_derived]
impl<T: ::core::cmp::PartialOrd> ::core::cmp::PartialOrd for Invisible<T> {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}PartialOrd, #[automatically_derived]
impl<T: ::core::cmp::Ord> ::core::cmp::Ord for Invisible<T> {
    #[inline]
    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, #[automatically_derived]
impl<T: ::core::hash::Hash> ::core::hash::Hash for Invisible<T> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
impl<T: ::core::default::Default> ::core::default::Default for Invisible<T> {
    #[inline]
    fn default() -> Self { Invisible(::core::default::Default::default()) }
}Default)]
57pub struct Invisible<T>(pub T);
58
59/// Return-position marker: the R wrapper returns this value visibly even where
60/// the default is invisible (a `NULL` from a unit-returning function). See the
61/// [module docs](self).
62#[repr(transparent)]
63#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Visible<T> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Visible",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Visible<T> {
    #[inline]
    fn clone(&self) -> Self { Visible(::core::clone::Clone::clone(&self.0)) }
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for Visible<T> { }Copy, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::marker::StructuralPartialEq for
    Visible<T> {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Visible<T> {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl<T: ::core::cmp::Eq> ::core::cmp::Eq for Visible<T> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq<T>; }
}Eq, #[automatically_derived]
impl<T: ::core::cmp::PartialOrd> ::core::cmp::PartialOrd for Visible<T> {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}PartialOrd, #[automatically_derived]
impl<T: ::core::cmp::Ord> ::core::cmp::Ord for Visible<T> {
    #[inline]
    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, #[automatically_derived]
impl<T: ::core::hash::Hash> ::core::hash::Hash for Visible<T> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
impl<T: ::core::default::Default> ::core::default::Default for Visible<T> {
    #[inline]
    fn default() -> Self { Visible(::core::default::Default::default()) }
}Default)]
64pub struct Visible<T>(pub T);
65
66macro_rules! marker_impls {
67    ($name:ident) => {
68        impl<T> $name<T> {
69            /// Wrap a value.
70            #[inline]
71            pub const fn new(value: T) -> Self {
72                $name(value)
73            }
74
75            /// Unwrap the value.
76            #[inline]
77            pub fn into_inner(self) -> T {
78                self.0
79            }
80        }
81
82        impl<T> From<T> for $name<T> {
83            #[inline]
84            fn from(value: T) -> Self {
85                $name(value)
86            }
87        }
88
89        impl<T> ::std::ops::Deref for $name<T> {
90            type Target = T;
91
92            #[inline]
93            fn deref(&self) -> &T {
94                &self.0
95            }
96        }
97
98        impl<T> ::std::ops::DerefMut for $name<T> {
99            #[inline]
100            fn deref_mut(&mut self) -> &mut T {
101                &mut self.0
102            }
103        }
104
105        /// Forwards to `T`: the marker only informs the generated R wrapper.
106        impl<T: IntoR> IntoR for $name<T> {
107            type Error = T::Error;
108
109            #[inline]
110            fn try_into_sexp(self) -> Result<crate::SEXP, Self::Error> {
111                self.0.try_into_sexp()
112            }
113
114            #[inline]
115            unsafe fn try_into_sexp_unchecked(self) -> Result<crate::SEXP, Self::Error> {
116                // SAFETY: same contract as the caller's.
117                unsafe { self.0.try_into_sexp_unchecked() }
118            }
119        }
120    };
121}
122
123impl<T> Invisible<T> {
    /// Wrap a value.
    #[inline]
    pub const fn new(value: T) -> Self { Invisible(value) }
    /// Unwrap the value.
    #[inline]
    pub fn into_inner(self) -> T { self.0 }
}
impl<T> From<T> for Invisible<T> {
    #[inline]
    fn from(value: T) -> Self { Invisible(value) }
}
impl<T> ::std::ops::Deref for Invisible<T> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T { &self.0 }
}
impl<T> ::std::ops::DerefMut for Invisible<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T { &mut self.0 }
}
/// Forwards to `T`: the marker only informs the generated R wrapper.
impl<T: IntoR> IntoR for Invisible<T> {
    type Error = T::Error;
    #[inline]
    fn try_into_sexp(self) -> Result<crate::SEXP, Self::Error> {
        self.0.try_into_sexp()
    }
    #[inline]
    unsafe fn try_into_sexp_unchecked(self)
        -> Result<crate::SEXP, Self::Error> {
        unsafe { self.0.try_into_sexp_unchecked() }
    }
}marker_impls!(Invisible);
124impl<T> Visible<T> {
    /// Wrap a value.
    #[inline]
    pub const fn new(value: T) -> Self { Visible(value) }
    /// Unwrap the value.
    #[inline]
    pub fn into_inner(self) -> T { self.0 }
}
impl<T> From<T> for Visible<T> {
    #[inline]
    fn from(value: T) -> Self { Visible(value) }
}
impl<T> ::std::ops::Deref for Visible<T> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T { &self.0 }
}
impl<T> ::std::ops::DerefMut for Visible<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T { &mut self.0 }
}
/// Forwards to `T`: the marker only informs the generated R wrapper.
impl<T: IntoR> IntoR for Visible<T> {
    type Error = T::Error;
    #[inline]
    fn try_into_sexp(self) -> Result<crate::SEXP, Self::Error> {
        self.0.try_into_sexp()
    }
    #[inline]
    unsafe fn try_into_sexp_unchecked(self)
        -> Result<crate::SEXP, Self::Error> {
        unsafe { self.0.try_into_sexp_unchecked() }
    }
}marker_impls!(Visible);
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn markers_are_transparent_wrappers() {
132        let i = Invisible::new(41).into_inner() + 1;
133        assert_eq!(i, 42);
134        let mut v: Visible<Vec<i32>> = Visible::from(vec![1]);
135        v.push(2);
136        assert_eq!(v.len(), 2);
137        assert_eq!(*v, vec![1, 2]);
138        assert_eq!(Invisible(()), Invisible::default());
139        assert_eq!(
140            std::mem::size_of::<Invisible<u64>>(),
141            std::mem::size_of::<u64>()
142        );
143    }
144}