extendr_api/wrapper/
rstr.rs1use super::*;
2
3#[derive(Clone)]
16pub struct Rstr {
17 pub(crate) robj: Robj,
18}
19
20pub(crate) unsafe fn charsxp_to_str(charsxp: SEXP) -> Option<&'static str> {
24 assert_eq!(TYPEOF(charsxp), SEXPTYPE::CHARSXP);
25 if charsxp == R_NilValue {
26 None
27 } else if charsxp == R_NaString {
28 Some(<&str>::na())
29 } else if charsxp == R_BlankString {
30 Some("")
31 } else {
32 let length = Rf_xlength(charsxp);
33 let all_bytes =
34 std::slice::from_raw_parts(R_CHAR(charsxp).cast(), length.try_into().unwrap());
35 Some(std::str::from_utf8_unchecked(all_bytes))
36 }
37}
38
39impl Rstr {
40 pub fn from_string(val: &str) -> Self {
42 Rstr {
43 robj: Robj::from_sexp(str_to_character(val)),
44 }
45 }
46
47 pub fn as_str(&self) -> &str {
50 self.into()
51 }
52}
53
54impl AsRef<str> for Rstr {
55 fn as_ref(&self) -> &str {
57 self.as_str()
58 }
59}
60
61impl From<String> for Rstr {
62 fn from(s: String) -> Self {
64 Rstr::from_string(&s)
65 }
66}
67
68impl From<&str> for Rstr {
69 fn from(s: &str) -> Self {
71 Rstr::from_string(s)
72 }
73}
74
75impl From<&Rstr> for &str {
76 fn from(value: &Rstr) -> Self {
77 unsafe {
78 let charsxp = value.robj.get();
79 rstr::charsxp_to_str(charsxp).unwrap()
80 }
81 }
82}
83
84impl From<Option<String>> for Rstr {
85 fn from(value: Option<String>) -> Self {
86 if let Some(string) = value {
87 Self::from(string)
88 } else {
89 Self { robj: na_string() }
90 }
91 }
92}
93
94impl Deref for Rstr {
95 type Target = str;
96
97 fn deref(&self) -> &Self::Target {
99 self.as_str()
100 }
101}
102
103impl<T> PartialEq<T> for Rstr
104where
105 T: AsRef<str>,
106{
107 fn eq(&self, other: &T) -> bool {
109 self.as_str() == other.as_ref()
110 }
111}
112
113impl PartialEq<str> for Rstr {
114 fn eq(&self, other: &str) -> bool {
116 self.as_str() == other
117 }
118}
119
120impl std::fmt::Debug for Rstr {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 if self.is_na() {
123 write!(f, "NA_CHARACTER")
124 } else {
125 let s = self.as_str();
126 write!(f, "{:?}", s)
127 }
128 }
129}
130
131impl std::fmt::Display for Rstr {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 let s = self.as_str();
134 write!(f, "{}", s)
135 }
136}
137
138impl CanBeNA for Rstr {
139 fn is_na(&self) -> bool {
140 unsafe { self.robj.get() == R_NaString }
141 }
142
143 fn na() -> Self {
144 unsafe {
145 Self {
146 robj: Robj::from_sexp(R_NaString),
147 }
148 }
149 }
150}