extendr_api/wrapper/
symbol.rs

1use super::*;
2// NOTE all of these symbol constants should be in their own module
3use extendr_ffi::{
4    R_BaseSymbol, R_BraceSymbol, R_Bracket2Symbol, R_BracketSymbol, R_ClassSymbol, R_DeviceSymbol,
5    R_DimNamesSymbol, R_DimSymbol, R_DollarSymbol, R_DotsSymbol, R_DoubleColonSymbol,
6    R_LastvalueSymbol, R_LevelsSymbol, R_MissingArg, R_ModeSymbol, R_NaRmSymbol, R_NameSymbol,
7    R_NamesSymbol, R_NamespaceEnvSymbol, R_PackageSymbol, R_PreviousSymbol, R_QuoteSymbol,
8    R_RowNamesSymbol, R_SeedsSymbol, R_SortListSymbol, R_SourceSymbol, R_SpecSymbol,
9    R_TripleColonSymbol, R_TspSymbol, R_UnboundValue, R_dot_Method, R_dot_defined,
10    R_dot_packageName, R_dot_target, PRINTNAME, TYPEOF,
11};
12/// Wrapper for creating symbol objects.
13///
14/// ```
15/// use extendr_api::prelude::*;
16/// test! {
17///     let chr = r!(Symbol::from_string("xyz"));
18///     assert_eq!(chr.as_symbol().unwrap().as_str(), "xyz");
19/// }
20/// ```
21///
22#[derive(PartialEq, Clone)]
23pub struct Symbol {
24    pub(crate) robj: Robj,
25}
26
27impl Symbol {
28    /// Make a symbol object from a string.
29    ///
30    /// ```
31    /// use extendr_api::prelude::*;
32    /// test! {
33    ///     let chr = r!(Symbol::from_string("xyz"));
34    ///     assert_eq!(chr, sym!(xyz));
35    /// }
36    /// ```
37    pub fn from_string<S: AsRef<str>>(val: S) -> Self {
38        let val = val.as_ref();
39        Symbol {
40            robj: Robj::from_sexp(make_symbol(val)),
41        }
42    }
43
44    // Internal conversion for constant symbols.
45    fn from_sexp(sexp: SEXP) -> Symbol {
46        unsafe {
47            assert!(TYPEOF(sexp) == SEXPTYPE::SYMSXP);
48        }
49        Symbol {
50            robj: Robj::from_sexp(sexp),
51        }
52    }
53
54    /// Get the string from a symbol object.
55    /// ```
56    /// use extendr_api::prelude::*;
57    /// test! {
58    ///     assert_eq!(sym!(xyz).as_symbol().unwrap().as_str(), "xyz");
59    /// }
60    /// ```
61    pub fn as_str(&self) -> &str {
62        unsafe {
63            let sexp = self.robj.get();
64            let printname = PRINTNAME(sexp);
65            rstr::charsxp_to_str(printname).unwrap()
66        }
67    }
68}
69
70impl From<&str> for Symbol {
71    /// Convert a string to a symbol.
72    fn from(name: &str) -> Self {
73        Symbol::from_string(name)
74    }
75}
76
77/// Unbound marker
78pub fn unbound_value() -> Symbol {
79    unsafe { Symbol::from_sexp(R_UnboundValue) }
80}
81
82/// Missing argument marker
83pub fn missing_arg() -> Symbol {
84    unsafe { Symbol::from_sexp(R_MissingArg) }
85}
86
87/// "base"
88pub fn base_symbol() -> Symbol {
89    unsafe { Symbol::from_sexp(R_BaseSymbol) }
90}
91
92/// "{"
93pub fn brace_symbol() -> Symbol {
94    unsafe { Symbol::from_sexp(R_BraceSymbol) }
95}
96
97/// "[["
98pub fn bracket_2_symbol() -> Symbol {
99    unsafe { Symbol::from_sexp(R_Bracket2Symbol) }
100}
101
102/// "["
103pub fn bracket_symbol() -> Symbol {
104    unsafe { Symbol::from_sexp(R_BracketSymbol) }
105}
106
107/// "class"
108pub fn class_symbol() -> Symbol {
109    unsafe { Symbol::from_sexp(R_ClassSymbol) }
110}
111
112/// ".Device"
113pub fn device_symbol() -> Symbol {
114    unsafe { Symbol::from_sexp(R_DeviceSymbol) }
115}
116
117/// "dimnames"
118pub fn dimnames_symbol() -> Symbol {
119    unsafe { Symbol::from_sexp(R_DimNamesSymbol) }
120}
121
122/// "dim"
123pub fn dim_symbol() -> Symbol {
124    unsafe { Symbol::from_sexp(R_DimSymbol) }
125}
126
127/// "$"
128pub fn dollar_symbol() -> Symbol {
129    unsafe { Symbol::from_sexp(R_DollarSymbol) }
130}
131
132/// "..."
133pub fn dots_symbol() -> Symbol {
134    unsafe { Symbol::from_sexp(R_DotsSymbol) }
135}
136//     pub fn drop_symbol() -> Symbol { unsafe { Symbol::from_sexp(R_DropSymbol) }}"drop"
137
138/// "::"
139pub fn double_colon_symbol() -> Symbol {
140    unsafe { Symbol::from_sexp(R_DoubleColonSymbol) }
141}
142
143/// ".Last.value"
144pub fn lastvalue_symbol() -> Symbol {
145    unsafe { Symbol::from_sexp(R_LastvalueSymbol) }
146}
147/// "levels"
148pub fn levels_symbol() -> Symbol {
149    unsafe { Symbol::from_sexp(R_LevelsSymbol) }
150}
151/// "mode"
152pub fn mode_symbol() -> Symbol {
153    unsafe { Symbol::from_sexp(R_ModeSymbol) }
154}
155/// "na.rm"
156pub fn na_rm_symbol() -> Symbol {
157    unsafe { Symbol::from_sexp(R_NaRmSymbol) }
158}
159/// "name"
160pub fn name_symbol() -> Symbol {
161    unsafe { Symbol::from_sexp(R_NameSymbol) }
162}
163/// "names"
164pub fn names_symbol() -> Symbol {
165    unsafe { Symbol::from_sexp(R_NamesSymbol) }
166}
167/// _NAMESPACE__."
168pub fn namespace_env_symbol() -> Symbol {
169    unsafe { Symbol::from_sexp(R_NamespaceEnvSymbol) }
170}
171/// "package"
172pub fn package_symbol() -> Symbol {
173    unsafe { Symbol::from_sexp(R_PackageSymbol) }
174}
175/// "previous"
176pub fn previous_symbol() -> Symbol {
177    unsafe { Symbol::from_sexp(R_PreviousSymbol) }
178}
179/// "quote"
180pub fn quote_symbol() -> Symbol {
181    unsafe { Symbol::from_sexp(R_QuoteSymbol) }
182}
183/// "row.names"
184pub fn row_names_symbol() -> Symbol {
185    unsafe { Symbol::from_sexp(R_RowNamesSymbol) }
186}
187/// ".Random.seed"
188pub fn seeds_symbol() -> Symbol {
189    unsafe { Symbol::from_sexp(R_SeedsSymbol) }
190}
191/// "sort.list"
192pub fn sort_list_symbol() -> Symbol {
193    unsafe { Symbol::from_sexp(R_SortListSymbol) }
194}
195/// "source"
196pub fn source_symbol() -> Symbol {
197    unsafe { Symbol::from_sexp(R_SourceSymbol) }
198}
199/// "spec"
200pub fn spec_symbol() -> Symbol {
201    unsafe { Symbol::from_sexp(R_SpecSymbol) }
202}
203/// "tsp"
204pub fn tsp_symbol() -> Symbol {
205    unsafe { Symbol::from_sexp(R_TspSymbol) }
206}
207/// ":::"
208pub fn triple_colon_symbol() -> Symbol {
209    unsafe { Symbol::from_sexp(R_TripleColonSymbol) }
210}
211/// ".defined"
212pub fn dot_defined() -> Symbol {
213    unsafe { Symbol::from_sexp(R_dot_defined) }
214}
215/// ".Method"
216pub fn dot_method() -> Symbol {
217    unsafe { Symbol::from_sexp(R_dot_Method) }
218}
219/// "packageName"
220pub fn dot_package_name() -> Symbol {
221    unsafe { Symbol::from_sexp(R_dot_packageName) }
222}
223
224/// ".target"
225pub fn dot_target() -> Symbol {
226    unsafe { Symbol::from_sexp(R_dot_target) }
227}
228
229#[cfg(test)]
230mod test {
231    use super::*;
232    use crate as extendr_api;
233
234    #[test]
235    fn test_constant_symbols() {
236        test! {
237            assert!(unbound_value().is_symbol());
238            assert!(missing_arg().is_symbol());
239            assert!(base_symbol().is_symbol());
240            assert!(brace_symbol().is_symbol());
241            assert!(bracket_2_symbol().is_symbol());
242            assert!(bracket_symbol().is_symbol());
243            assert!(class_symbol().is_symbol());
244            assert!(device_symbol().is_symbol());
245            assert!(dimnames_symbol().is_symbol());
246            assert!(dim_symbol().is_symbol());
247            assert!(dollar_symbol().is_symbol());
248            assert!(dots_symbol().is_symbol());
249            assert!(lastvalue_symbol().is_symbol());
250            assert!(levels_symbol().is_symbol());
251            assert!(mode_symbol().is_symbol());
252            assert!(na_rm_symbol().is_symbol());
253            assert!(name_symbol().is_symbol());
254            assert!(names_symbol().is_symbol());
255            assert!(namespace_env_symbol().is_symbol());
256            assert!(package_symbol().is_symbol());
257            assert!(previous_symbol().is_symbol());
258            assert!(quote_symbol().is_symbol());
259            assert!(row_names_symbol().is_symbol());
260            assert!(seeds_symbol().is_symbol());
261            assert!(sort_list_symbol().is_symbol());
262            assert!(source_symbol().is_symbol());
263            assert!(spec_symbol().is_symbol());
264            assert!(tsp_symbol().is_symbol());
265            assert!(triple_colon_symbol().is_symbol());
266            assert!(dot_defined().is_symbol());
267            assert!(dot_method().is_symbol());
268            assert!(dot_package_name().is_symbol());
269            assert!(dot_target().is_symbol());
270        }
271    }
272}