Skip to main content

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_dot_Method, R_dot_defined, R_dot_packageName, R_dot_target,
10    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: unsafe { Robj::from_sexp(make_symbol(val)) },
41        }
42    }
43
44    // Internal conversion for constant symbols.
45    pub(crate) fn from_sexp(sexp: SEXP) -> Symbol {
46        unsafe {
47            assert!(TYPEOF(sexp) == SEXPTYPE::SYMSXP);
48        }
49        Symbol {
50            robj: unsafe { 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/// Missing argument marker
78pub fn missing_arg() -> Symbol {
79    unsafe { Symbol::from_sexp(R_MissingArg) }
80}
81
82/// "base"
83pub fn base_symbol() -> Symbol {
84    unsafe { Symbol::from_sexp(R_BaseSymbol) }
85}
86
87/// "{"
88pub fn brace_symbol() -> Symbol {
89    unsafe { Symbol::from_sexp(R_BraceSymbol) }
90}
91
92/// "[["
93pub fn bracket_2_symbol() -> Symbol {
94    unsafe { Symbol::from_sexp(R_Bracket2Symbol) }
95}
96
97/// "["
98pub fn bracket_symbol() -> Symbol {
99    unsafe { Symbol::from_sexp(R_BracketSymbol) }
100}
101
102/// "class"
103pub fn class_symbol() -> Symbol {
104    unsafe { Symbol::from_sexp(R_ClassSymbol) }
105}
106
107/// ".Device"
108pub fn device_symbol() -> Symbol {
109    unsafe { Symbol::from_sexp(R_DeviceSymbol) }
110}
111
112/// "dimnames"
113pub fn dimnames_symbol() -> Symbol {
114    unsafe { Symbol::from_sexp(R_DimNamesSymbol) }
115}
116
117/// "dim"
118pub fn dim_symbol() -> Symbol {
119    unsafe { Symbol::from_sexp(R_DimSymbol) }
120}
121
122/// "$"
123pub fn dollar_symbol() -> Symbol {
124    unsafe { Symbol::from_sexp(R_DollarSymbol) }
125}
126
127/// "..."
128pub fn dots_symbol() -> Symbol {
129    unsafe { Symbol::from_sexp(R_DotsSymbol) }
130}
131//     pub fn drop_symbol() -> Symbol { unsafe { Symbol::from_sexp(R_DropSymbol) }}"drop"
132
133/// "::"
134pub fn double_colon_symbol() -> Symbol {
135    unsafe { Symbol::from_sexp(R_DoubleColonSymbol) }
136}
137
138/// ".Last.value"
139pub fn lastvalue_symbol() -> Symbol {
140    unsafe { Symbol::from_sexp(R_LastvalueSymbol) }
141}
142/// "levels"
143pub fn levels_symbol() -> Symbol {
144    unsafe { Symbol::from_sexp(R_LevelsSymbol) }
145}
146/// "mode"
147pub fn mode_symbol() -> Symbol {
148    unsafe { Symbol::from_sexp(R_ModeSymbol) }
149}
150/// "na.rm"
151pub fn na_rm_symbol() -> Symbol {
152    unsafe { Symbol::from_sexp(R_NaRmSymbol) }
153}
154/// "name"
155pub fn name_symbol() -> Symbol {
156    unsafe { Symbol::from_sexp(R_NameSymbol) }
157}
158/// "names"
159pub fn names_symbol() -> Symbol {
160    unsafe { Symbol::from_sexp(R_NamesSymbol) }
161}
162/// _NAMESPACE__."
163pub fn namespace_env_symbol() -> Symbol {
164    unsafe { Symbol::from_sexp(R_NamespaceEnvSymbol) }
165}
166/// "package"
167pub fn package_symbol() -> Symbol {
168    unsafe { Symbol::from_sexp(R_PackageSymbol) }
169}
170/// "previous"
171pub fn previous_symbol() -> Symbol {
172    unsafe { Symbol::from_sexp(R_PreviousSymbol) }
173}
174/// "quote"
175pub fn quote_symbol() -> Symbol {
176    unsafe { Symbol::from_sexp(R_QuoteSymbol) }
177}
178/// "row.names"
179pub fn row_names_symbol() -> Symbol {
180    unsafe { Symbol::from_sexp(R_RowNamesSymbol) }
181}
182/// ".Random.seed"
183pub fn seeds_symbol() -> Symbol {
184    unsafe { Symbol::from_sexp(R_SeedsSymbol) }
185}
186/// "sort.list"
187pub fn sort_list_symbol() -> Symbol {
188    unsafe { Symbol::from_sexp(R_SortListSymbol) }
189}
190/// "source"
191pub fn source_symbol() -> Symbol {
192    unsafe { Symbol::from_sexp(R_SourceSymbol) }
193}
194/// "spec"
195pub fn spec_symbol() -> Symbol {
196    unsafe { Symbol::from_sexp(R_SpecSymbol) }
197}
198/// "tsp"
199pub fn tsp_symbol() -> Symbol {
200    unsafe { Symbol::from_sexp(R_TspSymbol) }
201}
202/// ":::"
203pub fn triple_colon_symbol() -> Symbol {
204    unsafe { Symbol::from_sexp(R_TripleColonSymbol) }
205}
206/// ".defined"
207pub fn dot_defined() -> Symbol {
208    unsafe { Symbol::from_sexp(R_dot_defined) }
209}
210/// ".Method"
211pub fn dot_method() -> Symbol {
212    unsafe { Symbol::from_sexp(R_dot_Method) }
213}
214/// "packageName"
215pub fn dot_package_name() -> Symbol {
216    unsafe { Symbol::from_sexp(R_dot_packageName) }
217}
218
219/// ".target"
220pub fn dot_target() -> Symbol {
221    unsafe { Symbol::from_sexp(R_dot_target) }
222}
223
224#[cfg(test)]
225mod test {
226    use super::*;
227    use crate as extendr_api;
228
229    #[test]
230    fn test_constant_symbols() {
231        test! {
232            assert!(missing_arg().is_symbol());
233            assert!(base_symbol().is_symbol());
234            assert!(brace_symbol().is_symbol());
235            assert!(bracket_2_symbol().is_symbol());
236            assert!(bracket_symbol().is_symbol());
237            assert!(class_symbol().is_symbol());
238            assert!(device_symbol().is_symbol());
239            assert!(dimnames_symbol().is_symbol());
240            assert!(dim_symbol().is_symbol());
241            assert!(dollar_symbol().is_symbol());
242            assert!(dots_symbol().is_symbol());
243            assert!(lastvalue_symbol().is_symbol());
244            assert!(levels_symbol().is_symbol());
245            assert!(mode_symbol().is_symbol());
246            assert!(na_rm_symbol().is_symbol());
247            assert!(name_symbol().is_symbol());
248            assert!(names_symbol().is_symbol());
249            assert!(namespace_env_symbol().is_symbol());
250            assert!(package_symbol().is_symbol());
251            assert!(previous_symbol().is_symbol());
252            assert!(quote_symbol().is_symbol());
253            assert!(row_names_symbol().is_symbol());
254            assert!(seeds_symbol().is_symbol());
255            assert!(sort_list_symbol().is_symbol());
256            assert!(source_symbol().is_symbol());
257            assert!(spec_symbol().is_symbol());
258            assert!(tsp_symbol().is_symbol());
259            assert!(triple_colon_symbol().is_symbol());
260            assert!(dot_defined().is_symbol());
261            assert!(dot_method().is_symbol());
262            assert!(dot_package_name().is_symbol());
263            assert!(dot_target().is_symbol());
264        }
265    }
266}